feat(auth): optional WEBTERM_TOKEN access-token gate (W5)
An OPTIONAL shared token so the app can be used off-LAN (via the relay/tunnel) more safely than "anyone who reaches the port gets a shell". Sits IN FRONT OF the existing Origin/CSRF model — never replacing it — and is fully inert when unset. - src/http/auth.ts (new, pure): constantTimeEqual hashes both inputs to sha256 (32 bytes) then crypto.timingSafeEqual — no `===`, no length side-channel, never throws. parseCookieHeader / cookieIsAuthed / buildSetCookie / isAuthEnabled. - WEBTERM_TOKEN in config: 16–512 URL/cookie-safe chars or the server refuses to start. - GET /?token=<t> or POST /auth (rate-limited 10/min) validates → sets HttpOnly; SameSite=Strict; Secure-when-https cookie; public/login.html (no <script>). - When enabled: the WS handshake (AFTER the Origin check, before handleUpgrade) + a central authGate over all remote HTTP require the cookie. Open: /login, /auth. Loopback bypass scoped to /hook* ONLY (tighter than the plan — gates the local browser too). - Unset ⇒ isAuthEnabled false ⇒ pure passthrough (LAN zero-config unchanged). Honest tradeoff (in code + CLAUDE.md + login page): a bar-raiser, NOT a TLS/Tailscale substitute — on bare ws:// the token is cleartext + replayable; only hardens the TLS-terminated relay path. Verified: typecheck + build:web clean, 2118 pass at --test-timeout=30000 (disabled-mode regression proven; only the known tmux flake red); auth.ts 100% line coverage.
This commit is contained in:
@@ -34,6 +34,11 @@ export interface Config {
|
||||
readonly previewBytes: number; // manage-page preview: bytes of scrollback tail rendered
|
||||
readonly useTmux: boolean; // H1: spawn the shell inside tmux so it survives a server restart
|
||||
readonly allowedOrigins: readonly string[]; // derived from NIC IPs, NOT bindHost (M1)
|
||||
// w5-access-token — optional shared access token gate (ADDITIVE, in front of the
|
||||
// Origin/CSRF model; never replaces it). undefined/empty ⇒ auth DISABLED, so LAN
|
||||
// zero-config is preserved. When set: validated at load (16–512 URL/cookie-safe
|
||||
// chars). SECRET — never log; never return over /config/ui. See src/http/auth.ts.
|
||||
readonly webtermToken: string | undefined; // WEBTERM_TOKEN
|
||||
// v0.6 Project Manager — project discovery (impl: src/config.ts T-PM3)
|
||||
readonly projectRoots: readonly string[]; // PROJECT_ROOTS, default [homeDir]
|
||||
readonly projectScanDepth: number; // PROJECT_SCAN_DEPTH, default 4
|
||||
|
||||
Reference in New Issue
Block a user