Commit Graph

7 Commits

Author SHA1 Message Date
null 2a07e762a2 fix: four review-confirmed regressions in auth + OIDC flows
All found by the multi-angle /code-review over the branch and verified
against the installed libraries:

- 401 discriminator: the session-expiry redirect keyed off a path prefix
  (!/auth/*) and falsely logged users out on /profile/change-password
  with a wrong current password. requireAuth's no-session 401 now carries
  the distinct AUTH_REQUIRED code — the only signal api.ts dispatches
  auth:expired on; wrong-credential 401s keep AUTH_ERROR on any path.
  Test updated to pin the code-based contract on both directions.
- OIDC RFC 9207: exchangeAndVerifyTokens rebuilt the callback URL with
  only code+state, dropping the iss parameter openid-client v6 validates
  when the provider advertises support (authentik does) — every OIDC
  login would fail post-upgrade. The full callback query is now forwarded.
- OIDC http issuers: v6 enforces HTTPS on discovery/endpoints (v5
  didn't) — breaking internal http:// providers on Docker networks.
  OIDC_ALLOW_INSECURE_HTTP=true opts back in (documented in .env.example).
- 2FA downgrade: authService's webauthn fallback caught ANY challenge
  error and silently downgraded to password-only login; now only the
  stale-flag 'No registered WebAuthn credentials' case falls through,
  everything else rethrows.
- Burned-challenge retry: the server consumes the single-use 2FA
  challenge before verifying (anti-replay), so after a server rejection
  a retry can only ever return 'Challenge expired'. LoginPage now resets
  to sign-in on server failure (WebAuthn AND the pre-existing TOTP trap);
  a browser-prompt cancel keeps retry (token still live). Also lazy-loads
  @simplewebauthn/browser out of the entry bundle, matching ProfilePage.

Server 252/252, client 52/52, OIDC smoke 44/44, probe 33/33, e2e 27.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 22:57:07 -05:00
null 10eaf73e90 chore(deps): pin typescript at 6.x (4k deferred) + oidc header comment v5 -> v6
TypeScript 7 typechecks this codebase clean, but typescript-eslint (peer:
'>=4.8.4 <6.1.0') cannot parse under it — eslint hard-fails. Pinned back
to the TS 6 line per the plan's incompatibility contingency; revisit when
typescript-eslint ships TS 7 support (tracked in the QA plan backlog).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:08:06 -05:00
null 1627e75b29 chore(deps)!: openid-client 5 -> 6 (4j)
v6 replaced the Issuer/Client classes with a functional API. The four
touchpoints rewritten: discovery() + ClientSecretBasic/Post for the cached
configuration, serverMetadata() for the admin config test,
buildAuthorizationUrl() (returns URL -> .href), and authorizationCodeGrant()
with pkceCodeVerifier/expectedNonce/expectedState for the callback exchange —
same validation surface (JWKS signature, iss/aud/exp/nbf, PKCE, state, nonce),
now enforced by the library's single grant call.

scripts/test-oidc-smoke.js: 44/44. Server suite 252/252.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:05:57 -05:00
null b4634a8080 feat(logging): redacted, level-gated logger; migrate all server console.* (Pillar D)
utils/logger.cts — console-compatible log.{debug,info,warn,error} with:
- level gating (LOG_LEVEL; debug in dev / info in prod), and
- REDACTION of secrets/PII (sensitive keys + bearer/JWT) so tokens,
  passwords, and encrypted values never reach the logs (financial app).
Backend is abstracted (console now, swappable to pino later).

Swept all 317 server-runtime console.* across 35 files → log.* + inserted
the import at correct scope. tests/logger.test.js pins the redaction
contract (4 tests). CODE_STANDARDS updated; raw console.* is now banned in
server code.

Verified: check:server + typecheck:server + lint clean; 240/240 server
tests; client 50/50; build; e2e probe 17/17; boot smoke logs flow through
the logger and graceful shutdown intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 16:05:18 -05:00
null f587d09d4a style: apply Prettier across client + server (no behavior change)
One-time repo-wide `prettier --write` (isolated commit so future diffs
stay reviewable). Mechanical formatting only.

Verified unchanged: typecheck + typecheck:server + check:server clean;
server tests 232/232; client tests 50/50; Vite build succeeds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 14:23:53 -05:00
null 135bd98c6a refactor(server): migrate middleware, workers, and db layer to TypeScript (.cts)
- middleware/ (5): requireAuth, securityHeaders, errorFormatter, csrf,
  rateLimiter — fully typed against the shared http Req/Res/Next types.
- workers/dailyWorker — fully typed.
- db/ (4): database, subscriptionCatalogSeed, migrations/versionedMigrations,
  migrations/legacyReconcileMigrations — large dynamic schema/migration infra,
  converted with @ts-nocheck (typing deferred). All requires updated to .cts.

Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:34:08 -05:00
null 409b8a5618 refactor(server): finish services layer — subscription/spreadsheet/oidc/userDbImport → .cts
Completes the services/ TypeScript migration (0 .js remain). These four are the
largest, most dynamic modules (subscription-catalog matcher, xlsx/spreadsheet
parser, OIDC protocol client, SQLite user-DB importer); converted to .cts with a
top-of-file @ts-nocheck so they run via Node type-stripping now, with rich typing
deferred as an incremental follow-up. The other ~46 services are fully typed.

Behavior-preserving. Verified: typecheck:server 0, check:server 0, suite 226/226.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:22:44 -05:00
Renamed from services/oidcService.js (Browse further)