3 Commits
Author SHA1 Message Date
Paul NothaftandPaul Nothaft 33d6904e66 fix(backend): reject a replayed TOTP code within its validity window (stable) (#1398)
* fix(backend): reject a replayed TOTP code within its validity window

verifyTotp() was stateless — otplib's window:1 tolerance meant the
same 6-digit code could complete two independent logins inside its
~90s validity window. Track each admin's last-consumed step and
reject a code that doesn't advance past it.

* fix(backend): make the TOTP replay-tracking persist atomic

Backport of the same fix on main: the persist for
two_factor_last_used_step is now a conditional UPDATE (only advances
the step, checked via affected-row count) instead of a plain
unconditional write, closing a TOCTOU race where two concurrent
requests carrying the same captured code could both pass before
either UPDATE landed.

---------

Co-authored-by: Paul Nothaft <[email protected]>
2026-09-11 11:21:46 +02:00
Paul NothaftandPaul Nothaft 962f1d9586 fix(tests): raise jest timeouts to the 120s convention (stable) (#902)
Stable backport combining #860 (never reached stable) and #900:

- jest.config.js gains testTimeout: 120000 — stable still ran on Jest's
  5s default for anything unpinned, while its migration chain (134 core
  migrations via backports) is nearly as long as beta's.
- All 19 suite-level jest.setTimeout(30000/60000) pins raised to 120s;
  local pins override the config default (#860's rationale).
- All 15 hook-ARGUMENT timeout pins on migration-booting beforeAll
  hooks raised to 120s (#900's rationale — the 3.97.0-beta.0 release PR
  failed on exactly this class on the beta side).

Untouched: the three suites whose pinned hooks don't run migrations
(webhookDelivery, imageProcessor.storage, storageBackend) and
publicQuotes' 30s pin on the rate-limit lockout test.

No test logic changed.

Co-authored-by: Paul Nothaft <[email protected]>
2026-07-29 12:48:50 +02:00
Paul Nothaft cdbfb514bd test(auth): MFA unit + route + CLI coverage (39 tests)
mfaService unit (encrypt/decrypt, TOTP, single-use recovery, isEnrolled),
adminMfa HTTP (enroll/challenge/verify/recovery/disable; super_admin
enrollment guards #735), and reset-admin-mfa.js CLI.
2026-07-03 11:37:51 +02:00