Commit Graph

10 Commits

Author SHA1 Message Date
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
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
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
aa457b54d4 fix: infinite remount loop — use stable key for session components
When replaceSession changed the session ID from pending-XXX to a
real UUID, Vue's :key="session.id" treated it as a new element,
destroyed and recreated TerminalInstance, which called connectToHost
again, got another UUID, replaced again — infinite loop.

Added a stable `key` field to sessions that never changes after
creation, used as the Vue :key instead of the mutable `id`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 01:51:31 -04:00
Vantz Stockwell
2216ee79aa fix: close WebSocket and auto-remove session on SSH connect failure
When SSH connection fails, close the WebSocket immediately and
auto-remove the pending session after 3 seconds so the user sees
the error message before the panel clears. Prevents stuck sessions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 01:32:48 -04:00
Vantz Stockwell
10f3537b01 fix: move WebSocket paths under /api/ prefix to work through NPM proxy
NPM forwards /api/* correctly but silently drops WebSocket upgrades on
/ws/* despite toggle being enabled and custom nginx config. Moving
gateways to /api/ws/terminal and /api/ws/sftp so they ride the same
proxy rules that already work for REST endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 15:13:45 -04:00
Vantz Stockwell
d74bb28960 fix: terminal never appears — pending session removed before WS connects
Root cause: TerminalInstance.onMounted() called sessions.removeSession()
on the pending session, dropping sessions.length to 0. SessionContainer's
v-if="hasSessions" went false, unmounting the entire terminal UI before
the WebSocket could establish and add the real session.

Fix: Added replaceSession() to session store. TerminalInstance no longer
removes the pending session — instead passes its ID to connectToHost(),
which swaps it in-place when the backend responds with the real session ID.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 11:08:34 -04:00
Vantz Stockwell
1f32ce4620 fix: credential picker in host modal, fix xterm dimensions crash
- Added credential dropdown to New Host modal (loads from vault API)
- Fixed xterm.js "Cannot read dimensions" crash by guarding fitAddon.fit()
  with requestAnimationFrame and container dimension checks
- Added WebGL context loss handler
- credentialId now passed when creating hosts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:31:39 -04:00
Vantz Stockwell
3b14a7c1d1 feat: Termius-inspired UI — right sidebar, host counts, terminal themes
Left sidebar:
- Groups now show recursive host count badges
- Hosts in tree show up to 3 tags inline

Right sidebar (Host Details panel):
- Click any host card to open details panel on the right
- Shows address, port, protocol, group, credential, tags, color, notes
- Connect, Edit, Delete action buttons at bottom
- Selected card gets ring highlight

Terminal themes (10 prebuilt):
- Wraith (default), Dracula, Nord, Solarized Dark, Monokai, One Dark,
  Gruvbox Dark, Tokyo Night, Catppuccin Mocha, Cyberpunk
- Visual theme picker in Settings with color preview + sample text
- Persisted to /api/settings and localStorage for immediate use
- useTerminal reads theme on terminal creation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:19:57 -04:00
Vantz Stockwell
c8868258d5 feat: Phase 2 — SSH terminal + SFTP sidebar in browser
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 17:21:11 -04:00