feat(12-02): implement setup router — all 7 pre-auth routes + guard-first pattern
- Fill setupRouter: GET /status, POST /config, POST /validate/{db,oidc,vapid},
POST /credential, POST /complete (SETUP-01/02)
- isSetupLocked() is FIRST statement in every handler; returns 423 if locked (SETUP-04/D-10)
- /status uses isSetupLocked() directly: covers both explicit + effective-config branches
- /config: zod-validates {oidcIssuer:https, oidcClientId, vapidPublicKey, appExternalUrl};
upserts oidc_issuer|oidc_client_id|vapid_public_key|app_external_url into app_config
- /validate/db: db.execute(sql`SELECT 1`); 200 ok, 503 on failure
- /validate/oidc: fetches discovery doc with AbortSignal.timeout(5000); reads oidc_issuer
from app_config; 200 ok, 400 on unreachable/non-2xx
- /validate/vapid: webpush.setVapidDetails() structural check; reads ONLY from process.env
(VAPID_PRIVATE_KEY never from app_config, never returned; T-12-06/SC-3)
- /credential: inserts local user (oidcIss=null, claimed=false, isAdmin=true) FIRST
(Pitfall 5 FK), then calls validateEncryptAndStoreCredential(); noEchoHook + error map
- /complete: upserts setup_complete='true'; 200 first call, 423 second (Pitfall 8/D-10)
- Mount setupRouter pre-auth in index.ts BEFORE devAuthBypass() (T-12-09/Pitfall 1)
- All 394 tests pass (5 todo = D-08 RED scaffolds); typecheck clean
This commit is contained in:
@@ -10,6 +10,7 @@ import { sseRouter } from './routes/sse.js';
|
||||
import { listsRouter, listItemsRouter } from './routes/lists.js';
|
||||
import { pushRouter } from './routes/push.js';
|
||||
import { adminRouter } from './routes/admin.js';
|
||||
import { setupRouter } from './routes/setup.js';
|
||||
import { oidcAuthMiddleware, processOAuthCallback } from './auth/middleware.js';
|
||||
import { devAuthBypass } from './auth/devBypass.js';
|
||||
import { persistSessionCookie } from './auth/persistSessionCookie.js';
|
||||
@@ -37,6 +38,12 @@ app.get('/callback', (c) => processOAuthCallback(c));
|
||||
// GET /health — unauthenticated, mounted BEFORE the OIDC guard (T-01-03, T-02-05)
|
||||
app.route('/health', healthRouter);
|
||||
|
||||
// /api/setup/* — pre-auth wizard surface; mounted BEFORE the /api/* middleware chain
|
||||
// so the wizard is never caught by devAuthBypass or oidcAuthMiddleware (Pitfall 1 / T-12-09).
|
||||
// Mirrors the /health pre-auth pattern. isSetupLocked() in each handler provides the
|
||||
// 423 lock after setup is complete (SETUP-04 / D-10).
|
||||
app.route('/api/setup', setupRouter);
|
||||
|
||||
// Dev-auth bypass — no-op passthrough unless DEV_AUTH_BYPASS=true AND NODE_ENV!='production'.
|
||||
// When active, injects DEV_USER into the Hono context and the OIDC guard is NOT mounted.
|
||||
// Must be mounted BEFORE oidcAuthMiddleware (T-02-01 mitigation; see auth/devBypass.ts).
|
||||
|
||||
Reference in New Issue
Block a user