Commit Graph

24 Commits

Author SHA1 Message Date
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
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
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
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
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
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
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
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
74d3c0bd9a feat: add delete button for groups in sidebar
Shows × on hover next to the + button. Confirms before deleting.
Hosts in deleted groups become ungrouped.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:23:02 -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
f778213c32 fix: inline modals in index.vue, proper DTO for profile update
Dialogs: bypassed component-based dialogs entirely — inlined modals
directly in index.vue with inline style fallbacks for z-index/colors.
If button clicks work, we see the modal. Period.

Profile 500: created UpdateProfileDto with class-validator decorators
so ValidationPipe processes it correctly. Added error logging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:09:05 -04:00
Vantz Stockwell
19e765058d fix: remove extra </div> from Teleport removal in HostEditDialog
Mismatched div count was silently breaking the component in
production builds. 18 opens, 19 closes → now 18/18.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 08:52:18 -04:00
Vantz Stockwell
04d619eb2d fix: replace PrimeVue dialogs with plain Tailwind modals
PrimeVue Dialog wasn't rendering regardless of theme config.
Rewrote both Host and Group edit dialogs using Teleport + Tailwind,
matching the rest of the app's styling pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 08:45:12 -04:00
Vantz Stockwell
8546824b97 feat: quick connect, search, recent connections
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 17:32:18 -04:00
Vantz Stockwell
19183ee546 feat: vault management UI — SSH key import + credential CRUD
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 17:30:59 -04:00
Vantz Stockwell
e2e03be2dd feat: RDP frontend — Guacamole client with custom JSON WebSocket tunnel
- useRdp.ts: JsonWsTunnel class extends Guacamole.Tunnel to bridge
  guacamole-common-js (expects raw protocol) with our JSON gateway
  (consistent with SSH/SFTP message envelope pattern). Parses
  length-prefixed Guacamole instructions, dispatches to Guacamole.Client.
  Handles mouse/keyboard input, clipboard send, and session lifecycle.
- RdpCanvas.vue: full-size container that mounts the Guacamole display
  canvas. Calls useRdp().connectRdp() on mount, cleans up on unmount.
  Exposes sendClipboard() and disconnect() for toolbar integration.
- RdpToolbar.vue: auto-hiding floating toolbar (3s idle timeout) with
  clipboard paste dialog, fullscreen toggle (HTML5 Fullscreen API),
  settings panel stub, and disconnect button.
- SessionContainer.vue: renders RdpCanvas + RdpToolbar when
  session.protocol === 'rdp', replacing the Phase 3 placeholder.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 17:27:19 -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
Vantz Stockwell
b93fe016ed feat: frontend — auth flow, connection manager UI, host tree
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 17:11:02 -04:00