trails/apps
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
..
journal fix(journal/auth): atomic magic-token consume to close TOCTOU 2026-05-24 12:17:42 +02:00
mobile Bump the production group with 14 updates 2026-05-24 08:31:11 +00:00
planner Bump the production group with 14 updates 2026-05-24 08:31:11 +00:00