diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..bd8175d --- /dev/null +++ b/PLAN.md @@ -0,0 +1,135 @@ +# NexusOps — Make-It-Perfect Plan +Target: `/root/agent-dashboard` on c2-builder-slay (10.30.20.44) +Rule: remove no features. Only add and fix. + +--- + +## PHASE 1 — FIX (make everything that exists actually work) + +### 1.1 Screenshot pipeline (currently dead) +- **server.js**: add `POST /api/agent/screenshot-result` — receives base64 PNG, stores in `exfiltratedFiles` map with `mime: image/png`, marks command completed, broadcasts. +- Add `GET /api/screenshots` + `GET /api/screenshots/:id` (thumbnail/full). +- **Frontend**: new "Screenshots" section — grid of thumbnails, click to expand, per-node filter, download button. +- Verify agent's `screenshot` action posts to the new endpoint; fix the URL in agent.py if it points at the wrong path. + +### 1.2 Files & Credentials UI (backend exists, zero UI) +- New **Files** section: table of exfiltrated files (node, filename, size, time, download). Per-node filter. +- New **Credentials** section: grouped by node + type, redact-by-default with click-to-reveal, CSV export (endpoint already exists). +- Wire both into the existing WebSocket `NODES_UPDATE` payload so they live-refresh. + +### 1.3 Dashboard auth (currently wide open) +- Add session-token middleware to server.js: `NEXUS_AUTH_TOKEN` env var; on first load the UI asks for the token once, stores in localStorage, sends as `Authorization: Bearer`. +- Whitelist: agent endpoints (`/api/agent/*`, `/install*`, `/agent.py`) use a separate agent token embedded at install time. Dashboard/API/export endpoints require the operator token. +- WebSocket: token passed as query param on upgrade. + +### 1.4 Server as a real service +- systemd unit `nexusops-dashboard.service`: node server.js, Restart=always, env file `/root/agent-dashboard/.env` (PORT, PUBLIC_URL, NEXUS_AUTH_TOKEN). +- systemd unit `nexusops-tunnel.service`: cloudflared tunnel for `agent.thetempleofdoom.com` (tunnel creds already on the box — find via `cloudflared tunnel list`). +- `systemctl enable --now` both. Verify reboot survival. + +### 1.5 Persistence hardening +- Replace JSON-file saves with atomic writes (`write tmp → rename`) + a single-writer lock. +- Move to SQLite (`better-sqlite3`) for nodes/metrics/commands/files/creds — keeps all current data shapes, migration script imports existing `data/*.json` on first boot. +- Keeps JSON export endpoints untouched. + +### 1.6 WebSocket resilience +- Frontend: reconnect with exponential backoff (1s→2s→5s→30s cap), visible "reconnecting" pill in nav, full state resync on reconnect. +- Server: heartbeat ping every 25s so proxies/CF don't kill idle sockets. + +### 1.7 Agent robustness +- Verify `--silent` flag actually suppresses output (install scripts rely on it). +- Input capture: if `pynput` missing, agent logs one clear line to server (`input capture unavailable`) instead of silent degradation; dashboard shows the capability as "unavailable" on the node card instead of nothing. +- Agent auto-reconnect on server restart (already partially there — verify backoff doesn't spin at 100% CPU). +- Add agent version string; server tracks it per node; "update agent" skips already-current nodes. + +### 1.8 Empty state + first-run UX +- Dashboard with zero nodes → hero panel with the universal one-liner + QR code (qrcode.js, local) pointing at the public install URL. +- First node connects → confetti-free but noticeable highlight animation. + +--- + +## PHASE 2 — POLISH (the feel) + +### 2.1 Design system pass +- Consolidate to CSS custom properties (colors, spacing, radius, glow) — file already has some; finish the job. +- Typography: JetBrains Mono for terminal/data, Inter for UI chrome. +- Online nodes: subtle emerald pulse ring. Offline: desaturated, grayscale icon. +- Consistent 8px spacing grid; kill stray one-off margins. + +### 2.2 Node cards upgrade +- Inline SVG sparklines (last 30 heartbeats) for CPU + MEM on each card. +- Relative timestamps ("last seen 12s ago") ticking live. +- Click card → slide-in **detail drawer**: full metrics chart, files/creds/screenshots scoped to that node, command console pinned to it, tag editor, ping button with latency readout. +- Right-click (or ⋮ menu): ping, screenshot, update agent, reboot, kill agent, unregister — with confirm modals for destructive ones. + +### 2.3 Command builder +- Structured action picker: dropdown of every agent action (raw_command, manage_service, screenshot, download_file, harvest_credentials, update_agent, …) with a per-action form (service name, file path, etc.) instead of making the operator type raw JSON. +- Terminal output viewer: ANSI color support, mono font, copy button, per-command expandable rows in audit log. +- Bulk commands: tag-based targeting ("all linux nodes", "tag=prod") with live preview of affected nodes before send. + +### 2.4 Global polish +- Keyboard shortcuts: `/` focus search, `i` installer modal, `k` kill switch (with confirm), `Esc` close modals. `?` shows shortcut overlay. +- Toasts (top-right) for: node came online, node went offline, command completed/failed, file received, creds received. +- Loading skeletons for every section on first paint. +- Mobile responsive: cards stack, drawer becomes full-screen modal, terminal scrolls horizontally. +- Nav shows live clock + server latency (WS round-trip). + +--- + +## PHASE 3 — ADD (new, no removals) + +### 3.1 Scheduled commands +- `node-cron` in server: schedule raw/structured commands per node/tag on cron expressions. UI: simple scheduler panel (time picker + action + target). Persisted in SQLite. + +### 3.2 Screenshot gallery + live view +- Gallery view (all nodes, timestamped thumbnails). +- "Watch" mode: request screenshot every N seconds from one node, stream into the drawer (pseudo-live). + +### 3.3 Webhook alerts +- Config panel: webhook URL (n8n on .236 / Discord / generic). +- Events: node online/offline, new node registered, creds harvested, command failed. +- Server POSTs JSON event; n8n routes to Telegram/iMessage. + +### 3.4 Cross-platform binaries +- GitHub Actions (or local runners): build NexusAgent.exe (Windows) + NexusAgent-mac (macOS arm64/x64 universal2) on release. +- Binary tab becomes real: per-OS download buttons with version + build date. +- Fallback: keep "binary only exists for Linux x64" honest until then (grey out, tooltip). + +### 3.5 Node grouping & tags +- Tag management UI: create/rename/delete tags, drag nodes between groups, group-level bulk actions. +- Saved filters ("show me prod-linux only"). + +### 3.6 Audit & export upgrades +- Audit log: filter by node/status/action, date range, export filtered CSV. +- Full-data export (one zip: nodes, commands, files, creds, inputs, logs). + +### 3.7 Health watchdog for the stack itself +- Cron on the MacBook: every 5 min hit `https://agent.thetempleofdoom.com/api/status`; if down → restart services via SSH, alert via existing n8n/Telegram path. + +--- + +## EXECUTION ORDER (suggested) + +| # | Item | Phase | Effort | +|---|------|-------|--------| +| 1 | Server + tunnel systemd units | 1.4 | 15 min | +| 2 | Dashboard auth token | 1.3 | 45 min | +| 3 | Screenshot endpoint + UI | 1.1 | 1.5 h | +| 4 | Files & Credentials UI | 1.2 | 1.5 h | +| 5 | WebSocket reconnect | 1.6 | 30 min | +| 6 | Empty state + QR install | 1.8 | 45 min | +| 7 | Atomic saves → SQLite | 1.5 | 2 h | +| 8 | Agent version + capability reporting | 1.7 | 1 h | +| 9 | Design system + node cards + drawer | 2.1–2.2 | 3 h | +| 10 | Command builder + bulk targeting | 2.3 | 2 h | +| 11 | Shortcuts, toasts, skeletons, mobile | 2.4 | 2 h | +| 12 | Scheduled commands | 3.1 | 1.5 h | +| 13 | Webhook alerts | 3.3 | 1 h | +| 14 | Screenshot gallery/watch | 3.2 | 1 h | +| 15 | Tags/groups UI | 3.5 | 1.5 h | +| 16 | Cross-platform binaries | 3.4 | 3 h | +| 17 | Audit/export upgrades | 3.6 | 1 h | +| 18 | Self-watchdog | 3.7 | 30 min | + +**Ship gate after Phase 1:** every existing feature demonstrably works end-to-end (screenshot round-trip, file exfil → download, creds → UI, auth on, services survive reboot). +**Ship gate after Phase 2:** a stranger could run the dashboard without asking how anything works.