trails/apps/journal/app
Ullrich Schäfer f22bec5a13
fix(journal/auth): atomic magic-token consume to close TOCTOU
verifyLoginCode, verifyMagicToken, and verifyEmailChange previously did
SELECT WHERE used_at IS NULL → UPDATE … SET used_at = now. Two concurrent
verifications could both pass the SELECT and both succeed, accepting the
same single-use token twice.

Collapsed each to a single UPDATE … WHERE … RETURNING * statement.
Postgres serializes row-level locks within an UPDATE, so exactly one
concurrent caller observes a returned row; the rest see an empty array
and get \"Invalid or expired\". The token is also marked used as part of
the same statement — no second write needed.

verifyEmailChange's tertiary email-availability check now runs *after*
the consume; we keep the original semantics where the token is burned
on a clash (the previous code explicitly did the same with a separate
UPDATE).

No behavior change on the happy path. Closes a credential-reuse
window that mattered most for the 6-digit login codes (small search
space, more likely to race).

Full repo: pnpm typecheck, pnpm lint, pnpm test all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 12:17:42 +02:00
..
components Redesign navbar with avatar dropdown and mobile drawer 2026-04-26 09:56:20 +02:00
hooks Implement notifications + supporting fixes 2026-04-26 01:28:55 +02:00
jobs fix(journal): architectural audit omnibus 2026-05-24 10:28:33 +02:00
lib fix(journal/auth): atomic magic-token consume to close TOCTOU 2026-05-24 12:17:42 +02:00
routes fix(journal): remove ineffective dynamic imports 2026-05-24 12:05:08 +02:00
entry.client.tsx Add legal pages, ToS acceptance, and alpha banner 2026-04-18 00:08:48 +02:00
entry.server.tsx Consolidate Sentry config into shared package; fix inconsistencies 2026-04-18 00:30:09 +02:00
root.tsx fix(journal): remove ineffective dynamic imports 2026-05-24 12:05:08 +02:00
routes.ts Add background bulk import for Komoot 2026-05-23 18:19:10 +02:00