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>
- 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>
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>
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>
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>
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>
SFTP: Added console logging to diagnose, plus a watcher that sends
the pending list when sessionId becomes available (covers the race
where WS opens before sessionId is set).
RDP: connectHost() was returning early for non-SSH protocols.
Removed the guard and use host.protocol instead of hardcoded 'ssh'.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The list('/') call fired immediately after connect(), but the
WebSocket was still in CONNECTING state so send() silently dropped
the message. Now buffers the initial list request and sends it
in the onopen callback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
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>
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>
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>
- 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>
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>