Skip to content

feat: host key verification UI components#92

Merged
billchurch merged 17 commits intomainfrom
feature/host-key-verification
Feb 26, 2026
Merged

feat: host key verification UI components#92
billchurch merged 17 commits intomainfrom
feature/host-key-verification

Conversation

@billchurch
Copy link
Owner

@billchurch billchurch commented Feb 25, 2026

Summary

Implements the client-side UI for SSH host key verification, complementing the server-side feature in webssh2. Provides browser-based host key prompting, status display, and localStorage-based key persistence.

Key changes:

  • Client key store: host-key-store.ts — localStorage-backed store with lookup (returning discriminated union for trusted/mismatch/unknown), save, delete, and clear operations
  • Socket event handlers: Async handlers for hostkey:verify, hostkey:verified, hostkey:mismatch, hostkey:alert, hostkey:rejected events with SHA-256 fingerprint computation via SubtleCrypto
  • HostKeyPromptModal: Unknown host key prompt with accept/reject buttons and "remember this key" checkbox (TOFU default: checked)
  • HostKeyMismatchModal: Warning modal for key mismatch with stored fingerprint display
  • HostKeyRejectedModal: Information modal when server policy rejects unknown keys
  • HostKeyStatusIndicator: Status bar shield icon (green=verified, amber=alert) with click-to-expand popover showing host, algorithm, fingerprint, and source
  • Settings UI: "Trusted Host Keys" section in TerminalSettingsModal showing stored keys with per-key and bulk delete
  • Terminal store signals: Reactive signals for host key status, source, info, prompt data, and verification config
  • App wiring: All modals and indicator integrated into main App component

Testing

  • TypeScript typecheck passes with 0 errors
  • Lint passes clean
  • Client builds successfully

Test plan

  • Verify npm run check:all passes
  • Verify npm run build produces clean output
  • Manual test: connect to unknown host — HostKeyPromptModal appears with fingerprint
  • Manual test: accept key with "remember" checked — key saved to localStorage
  • Manual test: reconnect — no prompt, green shield icon in status bar
  • Manual test: click shield icon — popover shows host key details
  • Manual test: key mismatch — HostKeyMismatchModal shows stored vs presented fingerprints
  • Manual test: open Settings → Trusted Host Keys — saved keys displayed with delete buttons
  • Manual test: delete a key from settings — key removed, next connect prompts again

Implement localStorage-backed SSH host key store that supports
TOFU (Trust On First Use) verification in the browser. Provides
lookup, store, remove, import/export, and manual key addition
with validation of SSH algorithms and base64 key data.
Add SolidJS signals for tracking host key verification state
including status, source, fingerprint info, config, and modal
open/close state for prompt and mismatch dialogs.
Modal for unknown host key verification with TOFU flow. Displays
host, algorithm, SHA-256 fingerprint, and optional checkbox to
save the key to the browser client-side store.
Hard block modal for host key mismatches. Shows expected vs received
fingerprints, refuses the connection, and provides guidance based on
whether the mismatch was detected by the server or client store.
Simple rejection notice modal for when a connection is refused by
host key policy. Displays the reason and directs the user to contact
their administrator.
Status bar icon with popover showing host key verification details.
Displays a green shield for verified hosts or amber shield for alerts,
with click-to-expand details showing host, algorithm, fingerprint,
and verification source.
Use bracket notation for index signature properties to comply with
noPropertyAccessFromIndexSignature, and add explicit type assertions
for array element access under noUncheckedIndexedAccess.
Add expandable section for managing client-side SSH host keys with:
- List of stored keys showing host, algorithm, and SHA-256 fingerprint
- Delete button per key entry
- Add Key form for manually entering OpenSSH public keys
- Export keys to JSON file download
- Import keys from JSON file upload
Section only appears when client store is enabled in host key config.
Wire up client-side handling for server host key verification events:
- Add hostkey:verify/verified/mismatch/alert/rejected to ServerToClientEvents
- Add hostkey:verify-response to ClientToServerEvents
- Add hostKeyVerification to PermissionsPayload
- Implement all event handlers in socket service with client store lookup
- Add rejected state signals to terminal store
- Reset host key state on disconnect
Integrate host key verification UI into the main application:
- Add HostKeyPromptModal with accept/reject handlers and client store save
- Add HostKeyMismatchModal with dismiss-to-login flow
- Add HostKeyRejectedModal for server policy rejections
- Add HostKeyStatusIndicator to bottom status bar
- Import socket signal and host key store for emit/save operations
- Fix mismatch modal showing placeholder instead of actual stored
  fingerprint by returning storedKey from lookup and computing
  SHA-256 via SubtleCrypto
- Change closeOnBackdropClick to false on prompt modal to prevent
  accidental rejection
- Default rememberKey checkbox to true (TOFU model)
- Add click-outside-to-close and Escape key handling to status
  indicator popover
The <For> list was driven by hostKeyStore.getAll(), a plain localStorage
read that is not reactive in SolidJS. After deletion the list never
re-rendered, and refreshFingerprints() replaced the fingerprints map
without the deleted key, causing the fallback 'Computing...' text.

Add a reactive storedKeys signal, update it synchronously on delete,
and prune the fingerprints map in place so remaining entries keep their
already-computed fingerprints without an async recompute.
- Consume hostKeyVerification from the /ssh/config HTTP response in
  loadServerAuthMethods and set the hostKeyVerifyConfig signal immediately.
  This makes the Trusted Host Keys settings section visible before any
  socket connection, enabling key import on fresh browsers.
- Make session-related PermissionsPayload fields optional to support
  partial pre-auth permissions events from the server.
Add 31-test suite for client-side TOFU host key store (lookup, store,
remove, import/export, resilience). Add config-hostkey tests for server
config consumption. Fix extensionless import in config.ts, remove 13
unnecessary TransferId type assertions (S4325), flip 2 negated ternary
conditions (S7735) in sftp-service.ts.
…atch)

Apply npm audit fix to address 4 vulnerabilities in dev dependencies:
- rollup 4.57.1 → 4.59.0 (HIGH: arbitrary file write GHSA-mw96-cpmx-2vgc)
- basic-ftp 5.1.0 → 5.2.0 (CRITICAL: path traversal GHSA-5rq4-664w-9x2c)
- ajv/minimatch transitive deps updated (MODERATE/HIGH: ReDoS)

Update SECURITY.md review dates.
@socket-security
Copy link

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​rollup/​rollup-linux-x64-gnu@​4.57.1 ⏵ 4.59.01001004199100

View full report

@billchurch billchurch merged commit 1632eb7 into main Feb 26, 2026
6 checks passed
@billchurch billchurch deleted the feature/host-key-verification branch February 26, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant