Commit Graph

111 Commits

Author SHA1 Message Date
Vantz Stockwell
41613586c5 feat: theme service with 7 built-in terminal color schemes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 06:20:57 -04:00
Vantz Stockwell
995e81de3b Merge branch 'worktree-agent-a36e902e' into feat/phase1-foundation 2026-03-17 06:17:52 -04:00
Vantz Stockwell
7fa4e62cbc Merge branch 'worktree-agent-a9763668' into feat/phase1-foundation 2026-03-17 06:17:52 -04:00
Vantz Stockwell
e8ed0139b3 feat: connection + group CRUD with JSON tags and options
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 06:17:31 -04:00
Vantz Stockwell
4c32694a52 feat: vault service — Argon2id key derivation + AES-256-GCM encrypt/decrypt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 06:16:23 -04:00
Vantz Stockwell
4de47352cd feat: settings service — key-value store with upsert
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 06:15:55 -04:00
Vantz Stockwell
62133d8966 feat: SQLite database layer with WAL mode and schema migrations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 06:13:51 -04:00
Vantz Stockwell
381d142a73 feat: Wails v3 + Vue 3 project scaffold with Tailwind dark theme
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 06:11:19 -04:00
Vantz Stockwell
c64ddac18b docs: Phase 1 implementation plan — 15 tasks with TDD
Foundation plan covering: Wails v3 scaffold, SQLite+WAL, vault encryption,
connection/group CRUD, search, themes, settings, plugin interfaces,
session manager, master password UI, main layout shell, multi-window
spike, RDP frame transport spike, README, and license audit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 06:01:34 -04:00
Vantz Stockwell
98e3556cc7 docs: post-MVP Claude Code plugin spec — AI-assisted terminal operations
Claude Code integration as the first Wraith plugin: terminal I/O, SFTP
file access, CodeMirror handoff, and session context awareness. Proves
the plugin architecture and serves as the reference implementation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 05:41:54 -04:00
Vantz Stockwell
850e8e492e docs: spec hardening — Wails fallback plans, crash recovery, resource mgmt
- Wails v3: defined Plan A/B/C for multi-window with Phase 1 spike
- Crash recovery: workspace snapshot persistence + restore-on-restart
- Resource management: session limits, memory budgets, idle handling
- DPAPI: designed-for upgrade path in vault (post-MVP)
- RDP frame transport spike moved to Phase 1 (don't discover late)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 05:39:35 -04:00
Vantz Stockwell
587b5396fd docs: spec refinements — RDP key pass-through, SQLite WAL, tab transitions
- RDP input: Windows key + Alt+Tab pass-through toggle per connection
- SQLite: WAL mode + busy_timeout for concurrent read/write safety
- UI: 0.5s CSS transitions on tab active/background state changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 05:36:33 -04:00
Vantz Stockwell
0641ce34c8 docs: Wraith Desktop design spec — Go + Wails v3 native app
Complete design specification for rebuilding Wraith as a native Windows
desktop application replacing MobaXTerm. Covers architecture, data model,
SSH/SFTP/RDP flows, vault encryption, UI layout, MobaXTerm config
importer, plugin interface, and phased build plan.

Stack: Go + Wails v3 + Vue 3 + SQLite + FreeRDP3 (purego)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 05:27:32 -04:00
Vantz Stockwell
a75e21138e fix: RDP keyboard capture yields to form elements in modals and toolbars
Keyboard events now check if focus is on an input, textarea, select, or
contenteditable element and let the browser handle them normally. Also
fixes connectRdp type (Awaited<>) and async onMounted in RdpCanvas.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:49:30 -04:00
Vantz Stockwell
8d4ee04285 fix: SSH host key verification — send verifyId, track pending clients, guard stale callbacks
Frontend sends verifyId with host-key-accept so backend can correlate the
verification response. Backend tracks pre-ready connections in pendingClients
map, destroys on error/disconnect, and guards against calling verify() after
the connection has already timed out or errored (_destruct crash fix).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 12:49:22 -04:00
Vantz Stockwell
63315f94c4 test: backend test suite — 8 spec files covering vault encryption, credentials, SSH keys, auth service, controller, guards
63 tests across 8 spec files, all passing. Removes 2 stale stub files from
backend/test/ that were incompatible with the current async EncryptionService
and 3-argument AuthService constructor. New suite lives in src/ co-located
with source files per NestJS convention.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 19:10:12 -04:00
Vantz Stockwell
f01e357647 test: frontend test suite — Vitest infrastructure, auth/connection stores, vault composable, admin middleware
28 tests across 4 spec files. Vitest + happy-dom configured with Nuxt auto-import
shims ($$fetch, navigateTo, defineNuxtRouteMiddleware) so stores and composables
resolve cleanly outside the Nuxt runtime.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 19:06:14 -04:00
Vantz Stockwell
5abbffca9b feat(ui): add color accents across the connection manager
- Default protocol color strips on all host cards (wraith-blue for SSH, purple for RDP)
- Deterministic tag colors from 8-color palette (teal, amber, violet, rose, emerald, sky, orange, indigo)
- Last-connected recency coloring (green=today, amber=this week, gray=older)
- Section header dots (wraith-400 for Recent, gray for All Hosts)
- Active nav link highlighting (wraith-400)
- Group headers get subtle wraith-500 left border accent
- Tree host dots default to protocol color instead of gray
- Fixed rogue modal using hardcoded #1a1a2e/#e94560 — now uses design system
- Fixed sky-600 save buttons → wraith-600 for brand consistency
- Credential type badges: SSH Key=wraith, Password=amber (was purple/blue)
- Colored tags in right sidebar detail panel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 16:01:58 -04:00
Vantz Stockwell
adbfd854a6 fix: skip default admin seed if any admin account exists 2026-03-14 15:52:35 -04:00
Vantz Stockwell
48755ecacd fix: move cookie-parser to main.ts for guaranteed execution before JWT strategy 2026-03-14 15:36:35 -04:00
Vantz Stockwell
ce0c04e7fa fix: relax helmet CSP for Nuxt inline scripts and WebSocket connections 2026-03-14 15:27:53 -04:00
Vantz Stockwell
795e8646df fix: remove keyType reference from decryptForConnection return type 2026-03-14 14:35:36 -04:00
Vantz Stockwell
93811b59cb fix(security): auth hardening — httpOnly cookies, Argon2id passwords, TOTP encryption, rate limiting
C-2: JWT moved from localStorage to httpOnly cookie (eliminates XSS token theft)
C-3: WebSocket auth via short-lived single-use tickets (JWT no longer in URLs)
H-1: JWT expiry reduced from 7 days to 4 hours
H-3: TOTP secrets encrypted at rest with vault EncryptionService (auto-migrates plaintext)
H-6: Rate limiting via @nestjs/throttler (60 req/min global, tighten on auth)
H-8: Constant-time login — Argon2id verify runs against dummy hash for non-existent users
H-9: Password hashing upgraded from bcrypt(10) to Argon2id (auto-upgrades on login)
H-10: Credential list API no longer returns encrypted blobs
H-16: Admin pages use Nuxt route middleware instead of client-side guard
Plus: auth bootstrap plugin, cookie-parser middleware, all frontend Authorization headers removed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 14:24:35 -04:00
Vantz Stockwell
39825f5295 fix(security): terminal logging cleanup, session ownership, host key verification, shell injection opt-in
- H-5: Redact keystroke data from WS message logs — log type/sessionId/bytes only
- H-4: Remove private key content/length/passphrase logging, replace with safe single line
- H-14: Remove username@hostname from password auth log, use hostId only
- M-1: Enforce session ownership in data/resize/disconnect handlers via clientSessions map
- C-5: Real host key verification flow — MITM protection blocks changed keys immediately,
  new hosts ask user via host-key-verify WS message with 30s timeout, pending map resolves on
  host-key-accept/host-key-reject response
- H-13: Shell PROMPT_COMMAND/precmd injection is now opt-in via options.enableCwdTracking

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 14:15:23 -04:00
Vantz Stockwell
74cba6339c fix(security): SFTP session ownership + Guacamole instruction validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 14:14:31 -04:00
Vantz Stockwell
a88c164ac4 fix(security): infrastructure hardening — guacd network isolation, drop DB port, helmet, non-root container
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-14 14:13:28 -04:00
Vantz Stockwell
b11efce6ed feat(security): Argon2id key derivation for vault encryption
BREAKING CHANGE (forward-only): New credentials/keys encrypted with v2
(Argon2id-derived AES-256-GCM). Existing v1 records decrypt transparently.

- Argon2id params: 64 MiB memory, 3 iterations, 4 parallelism (OWASP)
- Per-record 16-byte salt stored in ciphertext format
- v2 format: v2:<salt>:<iv>:<authTag>:<ciphertext>
- Backwards compatible: v1 records still decrypt with raw key
- Admin endpoint POST /api/credentials/migrate-v2 upgrades all v1→v2
- Added docs/FUTURE-FEATURES.md with remaining spec gaps

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 13:40:41 -04:00
Vantz Stockwell
37781a4791 fix: replace popup Monaco editor with fullscreen overlay
Monaco can't mount in a popup window — it references document.activeElement
from the main window context, causing cross-window DOM errors.

Replaced with a fullscreen overlay teleported to <body>:
- Same dark theme toolbar with save/close/dirty indicator
- Ctrl+S to save, Esc to close
- Status bar shows language and keyboard shortcuts
- File tree stays visible underneath (overlay dismisses to it)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 13:28:56 -04:00
Vantz Stockwell
e1be07f34c feat: session tabs with home nav, popup Monaco editor, drag-and-drop upload
Multi-session tabs + home navigation:
- Tab bar with Home button persists above sessions
- Clicking Home shows the underlying page (hosts, vault, etc.)
- Clicking a session tab switches back to that session
- Header nav links also trigger home view
- Sessions stay alive in background when viewing home

Monaco editor in popup window:
- Opening a file in SFTP launches a detached popup with Monaco
- Full syntax highlighting, minimap, Ctrl+S save
- File tree stays visible while editing
- Toolbar with save/close buttons and dirty indicator

Drag-and-drop upload:
- Drop files anywhere on the SFTP sidebar to upload
- Visual overlay with dashed border on drag-over
- Supports multiple files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 13:20:40 -04:00
Vantz Stockwell
733fe6aca1 feat: admin user management UI
- Add admin-only "Users" nav link in header
- Create /admin/users page with full CRUD:
  create user, edit, delete, reset password, reset TOTP
- Matches existing wraith dark theme
- Client-side admin guard redirects non-admins

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 13:07:20 -04:00
Vantz Stockwell
6d76558bc3 feat: multi-user isolation with admin/user roles
Full per-user data isolation across all tables:
- Migration adds userId FK to hosts, host_groups, credentials, ssh_keys,
  connection_logs. Backfills existing data to admin@wraith.local.
- All services scope queries by userId from JWT (req.user.sub).
  Users can only see/modify their own data. Cross-user access returns 403.
- Two roles: admin (full access + user management) and user (own data only).
- Admin endpoints: list/create/edit/delete users, reset password, reset TOTP.
  Protected by AdminGuard. Admins cannot delete themselves or remove own role.
- JWT payload now includes role. Frontend auth store exposes isAdmin getter.
- Seed script fixed: checks for admin@wraith.local specifically (not any user).
  Uses upsert, seeds with role=admin. Migration cleans up duplicate users.
- Connection logs now attributed to the connecting user via WS auth.
- Deleting a user CASCADEs to all their hosts, credentials, keys, and logs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:57:38 -04:00
Vantz Stockwell
b749242583 feat(sftp): SFTP sidebar follows terminal CWD
- Inject shell integration (PROMPT_COMMAND/precmd) on SSH connect that
  emits OSC 7 escape sequences reporting the working directory on every
  prompt. Supports bash and zsh.
- Frontend captures OSC 7 via xterm.js parser, updates session store CWD.
- SFTP sidebar watches session CWD and navigates when it changes.
- SFTP starts at ~/ (user home) instead of / on initial connect, resolved
  via SFTP realpath('.') on the backend.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:44:42 -04:00
Vantz Stockwell
95271f065a fix(rdp): proper display scaling via Guacamole display.scale()
Remove CSS width/height !important override that broke Guacamole's
internal rendering pipeline. Replace with display.scale() auto-fitting
using ResizeObserver for responsive container sizing. Scale mouse
coordinates back to remote display space to keep input accurate.
Clean up diagnostic instruction logging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:20:21 -04:00
Vantz Stockwell
f9070c81f3 diag(rdp): expand instruction logging to find desktop frames
Log first 50 instructions, then every 200th, plus any draw operation
targeting layer 0 (main display). Need to determine if RDPGFX desktop
frames are arriving or if only cursor operations are being received.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:11:12 -04:00
Vantz Stockwell
6ddd343234 diag(rdp): add instruction + display dimension logging
Temporary diagnostics to debug blank screen after successful RDP connection.
Logs first 30 instruction opcodes and display dimensions on ready.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:04:25 -04:00
Vantz Stockwell
1bf225ae27 fix(rdp): send client capability instructions before CONNECT handshake
ROOT CAUSE: guacd showed "User resolution is 0x0 at 0 DPI" and
immediately killed every RDP connection.

The Guacamole protocol requires five client capability instructions
(size, audio, video, image, timezone) BETWEEN receiving 'args' and
sending 'connect'. Our handshake skipped all five and jumped straight
to CONNECT. guacd never received the display dimensions, defaulted to
0x0, and terminated the connection.

Now sends the complete handshake:
  select → (receive args) → size → audio → video → image → timezone → connect

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 06:32:36 -04:00
Vantz Stockwell
34bea52e0b fix(rdp): TCP stream buffering + error surfacing for guacd pipeline
Three bugs fixed:

1. TCP stream fragmentation — guacd→browser data pipe treated each TCP
   chunk as a complete instruction. TCP is a stream protocol; instructions
   WILL be split across chunks (especially display/image data). Added
   instruction buffer that accumulates data and only forwards complete
   instructions (terminated by ';').

2. Missing client.onerror — when guacd fails the RDP connection (NLA,
   auth, TLS), it sends a Guacamole error instruction. No handler was
   registered, so errors were silently swallowed. User saw blank canvas
   with no feedback. Now surfaces errors via console and gateway callback.

3. Missing client.onstatechange — no connection state tracking. Added
   state transition logging for diagnostics.

Also improved CONNECT handshake logging to surface connection parameters
(host, port, user, domain, security mode) without exposing passwords.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 06:17:32 -04:00
Vantz Stockwell
36251c3caa fix(rdp): correct guacd debug entrypoint override
ENTRYPOINT not CMD — guacamole/guacd image sets its own entrypoint,
so command override was being appended as args to guacd binary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 05:58:13 -04:00
Vantz Stockwell
c062cd502d debug(rdp): enable guacd debug logging + log all guacd responses
guacd was dying silently with no error instruction sent back.
Enable -L debug -f for verbose FreeRDP diagnostics and log
first 5 guacd→browser instructions plus connection parameters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 05:53:13 -04:00
Vantz Stockwell
80463235b0 fix(rdp): VERSION echo + guacd host networking for overlay reach
- Echo VERSION_X_Y_Z args back to guacd in CONNECT handshake
- Set guacd to network_mode: host so it can reach RDP targets on
  NetBird/Tailscale overlay networks (100.64.x.x)
- App container uses host.docker.internal to reach guacd on host
- Add diagnostic logging for guacd→browser instruction relay

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 05:23:02 -04:00
Vantz Stockwell
9d3a93bea9 fix(rdp): parse guacd args response and send matching positional connect values 2026-03-14 05:05:00 -04:00
Vantz Stockwell
72526487c3 fix(rdp): replace class extends with direct instance method override on Guacamole.Tunnel 2026-03-14 04:51:03 -04:00
Vantz Stockwell
76db0a6936 fix(rdp): override Guacamole.Tunnel instance methods, fix sendMessage encoding 2026-03-14 04:39:44 -04:00
Vantz Stockwell
e3a978b639 fix(sftp): cache SFTP channel per session to prevent channel exhaustion 2026-03-14 04:18:29 -04:00
Vantz Stockwell
3b1c1aeda1 feat(sftp): add download save-to-disk + upload support, remove debug banner 2026-03-14 04:11:45 -04:00
Vantz Stockwell
a9702795a4 fix(sftp): use Nuxt auto-import names SftpFileTree/SftpFileEditor 2026-03-14 03:45:04 -04:00
Vantz Stockwell
aa1bbb28c4 fix(sftp): fix FileTree not visible — flex overflow layout issue 2026-03-14 03:21:25 -04:00
Vantz Stockwell
fd9e30b3bf debug: add visible SFTP diagnostic banner + WS error/close handlers 2026-03-14 03:02:49 -04:00
Vantz Stockwell
f124d4b7d2 fix(rdp): convert to manual ws.Server, fix URL path, fix double session 2026-03-14 02:40:37 -04:00
Vantz Stockwell
3b5e5e0d36 debug: add onmessage logging to useSftp composable 2026-03-14 02:34:58 -04:00