Commit Graph

147 Commits

Author SHA1 Message Date
sencho-quartermaster[bot] 81abd73fc7 chore(main): release 0.63.0 (#700)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-21 08:52:41 -04:00
sencho-quartermaster[bot] 75d93d20db chore(main): release 0.62.0 (#686)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-19 15:04:43 -04:00
sencho-quartermaster[bot] 47eaffdf93 chore(main): release 0.61.0 (#675)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-18 18:54:42 -04:00
sencho-quartermaster[bot] 4c79093abd chore(main): release 0.60.0 (#672)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 22:58:20 -04:00
sencho-quartermaster[bot] bc91c754c8 chore(main): release 0.59.0 (#668)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 22:06:16 -04:00
sencho-quartermaster[bot] 7d390bd54d chore(main): release 0.58.1 (#660)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 14:43:14 -04:00
sencho-quartermaster[bot] d2c6c26fe8 chore(main): release 0.58.0 (#655)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 13:40:17 -04:00
sencho-quartermaster[bot] 5ec9d50b41 chore(main): release 0.57.0 (#647)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 08:18:25 -04:00
sencho-quartermaster[bot] 3d112969cf chore(main): release 0.56.0 (#644)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-16 21:33:51 -04:00
sencho-quartermaster[bot] baf3123efa chore(main): release 0.55.1 (#641)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-16 20:34:43 -04:00
sencho-token-app[bot] 8190274247 chore(main): release 0.55.0 (#636)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-16 15:04:37 -04:00
sencho-token-app[bot] 8c767e3925 chore(main): release 0.54.1 (#631)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-16 08:17:04 -04:00
sencho-token-app[bot] da5471d7ac chore(main): release 0.54.0 (#627)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 23:16:29 -04:00
sencho-token-app[bot] 6d084540bd chore(main): release 0.53.0 (#624)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 20:53:17 -04:00
sencho-token-app[bot] 7bda33d780 chore(main): release 0.52.0 (#621)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 19:52:51 -04:00
sencho-token-app[bot] ecdfd77453 chore(main): release 0.51.0 (#616)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 18:46:53 -04:00
Anso 7d78c9fe22 feat(auth): add TOTP two-factor authentication with backup codes (#615)
* feat(auth): add TOTP two-factor authentication with backup codes

Adds RFC 6238 time-based one-time password support to every tier,
integrated with the existing password and SSO login paths.

Backend:
- New MfaService wrapping otplib with a plus or minus 1 step tolerance,
  base32 secret generation, and hashed single-use backup codes (bcrypt).
- user_mfa and mfa_used_tokens tables in DatabaseService. The second
  table is a DB-backed replay blacklist, purged on a 60s interval.
- authMiddleware now recognizes an mfa_pending scope. A token carrying
  that scope is rejected on every route except the MFA challenge and
  logout, so no API surface is reachable before the second factor
  clears.
- /api/auth/login issues only a short-lived mfa_pending cookie when the
  user has MFA enrolled. /api/auth/login/mfa consumes that cookie,
  verifies the code (or backup code), and swaps in a real session.
- /api/auth/mfa/* routes for status, enrol/start, enrol/confirm,
  disable, backup-code regenerate, and SSO-bypass opt-in.
- Admin recovery path: POST /api/users/:id/mfa/reset clears the target's
  MFA state, bumps token_version, and writes an audit log entry.
- CLI emergency fallback: backend/src/cli/resetMfa.ts is wired via
  `npm run reset-mfa <username>` and also exported for tests.
- SSO flows (LDAP and OIDC) gate on user_mfa.sso_enforce_mfa before
  issuing a session; default behaviour keeps the SSO path frictionless.
- Per-user lockout after 5 consecutive failed codes (15 min).

Frontend:
- AppStatus gains an mfa-challenge branch driven by /api/auth/status.
- New MfaChallenge screen, MfaEnrollDialog (QR plus manual secret plus
  backup codes), MfaDisableDialog, MfaBackupCodesDialog.
- Account section shows a Two-factor authentication card with enrol,
  regenerate, disable, and the SSO-enforce toggle (shown only when SSO
  providers are configured).
- Users section gains a Reset 2FA action for admins.

Docs:
- New user guide at features/two-factor-authentication.mdx.
- New admin guide at operations/two-factor-admin.mdx.
- SSO page cross-links to the 2FA doc.

* fix(mfa): drop unused TEST_PASSWORD import and stale eslint disable

* fix(mfa): simplify e2e openAccountSettings helper to match working pattern

* fix(mfa): make e2e suite self-contained and always clean up

Test #2 called loginAs() before the MFA challenge step, which waited for
the dashboard indicator that never appears once the previous test enrolled
the user. That timeout skipped the rest of the serial block, including
the disable step, leaving MFA enabled and breaking every later spec.

Two fixes:

- Tests #2 and #3 now navigate directly to the login page instead of
  piggybacking on loginAs, which only handles the password-only path.
- A new afterAll hook unconditionally disables MFA via the API using two
  unused backup codes, so the DB is reset even if a test fails midway.

* fix(e2e): use backup code for mfa recovery to avoid totp replay race

The final recovery step in the backup-code replay test previously
generated a fresh TOTP to sign back in. When the timing landed inside
the same 30-second window that test #2 consumed, the server's replay
blacklist correctly rejected it, producing a ~50% flake rate. Backup
codes are single-use and sidestep the replay window, so the recovery
becomes deterministic.

* fix(e2e): drive mfa disable test through the challenge screen

Test #4 called loginAs after test #3 left MFA enabled, but loginAs
waits for the dashboard indicator and does not handle the challenge
screen, so it timed out. Drive the login manually, satisfy the
challenge with a backup code, and use a backup code for the disable
step too to avoid any TOTP replay-window race against earlier tests
in the serial block.
2026-04-15 18:45:51 -04:00
sencho-token-app[bot] 215a3a8f99 chore(main): release 0.50.0 (#610)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 11:35:03 -04:00
sencho-token-app[bot] 3da17905ba chore(main): release 0.49.0 (#607)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 08:06:18 -04:00
sencho-token-app[bot] 3dbfb6604e chore(main): release 0.48.1 (#604)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 22:33:28 -04:00
sencho-token-app[bot] 9ea8dcf44c chore(main): release 0.48.0 (#601)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 21:13:59 -04:00
sencho-token-app[bot] 5f82796a2a chore(main): release 0.47.0 (#598)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 18:21:21 -04:00
sencho-token-app[bot] 64f9d4f3e8 chore(main): release 0.46.20 (#595)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 16:42:56 -04:00
sencho-token-app[bot] baafc955eb chore(main): release 0.46.19 (#592)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 14:38:14 -04:00
sencho-token-app[bot] 7615a6068d chore(main): release 0.46.18 (#589)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 13:52:57 -04:00
sencho-token-app[bot] 6ffac2a0db chore(main): release 0.46.17 (#587)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 11:58:48 -04:00
sencho-token-app[bot] 819ca8a213 chore(main): release 0.46.16 (#584)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 11:05:09 -04:00
sencho-token-app[bot] bf0e8e14ed chore(main): release 0.46.15 (#581)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 10:12:29 -04:00
sencho-token-app[bot] 816a69034d chore(main): release 0.46.14 (#578)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 08:32:08 -04:00
sencho-token-app[bot] 0324578827 chore(main): release 0.46.13 (#574)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 22:17:54 -04:00
sencho-token-app[bot] eaa4ab7841 chore(main): release 0.46.12 (#571)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 21:42:03 -04:00
sencho-token-app[bot] b541b1168c chore(main): release 0.46.11 (#568)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 18:56:20 -04:00
sencho-token-app[bot] 1d9fdd9f25 chore(main): release 0.46.10 (#565)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 17:49:03 -04:00
sencho-token-app[bot] 98225d540f chore(main): release 0.46.9 (#562)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 15:50:56 -04:00
sencho-token-app[bot] 1a8ce3a3c9 chore(main): release 0.46.8 (#559)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 14:34:41 -04:00
sencho-token-app[bot] c703e196a4 chore(main): release 0.46.7 (#556)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 13:28:00 -04:00
sencho-token-app[bot] 4c6c1c7481 chore(main): release 0.46.6 (#553)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 12:50:17 -04:00
sencho-token-app[bot] 0df877c6e6 chore(main): release 0.46.5 (#550)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 11:39:10 -04:00
sencho-token-app[bot] 0cfd43cb80 chore(main): release 0.46.4 (#546)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 10:04:31 -04:00
sencho-token-app[bot] 4eed8cde85 chore(main): release 0.46.3 (#543)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 22:08:21 -04:00
sencho-token-app[bot] 6002a5b630 chore(main): release 0.46.2 (#540)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 21:25:59 -04:00
sencho-token-app[bot] b494edaf7d chore(main): release 0.46.1 (#537)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 20:30:59 -04:00
sencho-token-app[bot] b76029e05d chore(main): release 0.46.0 (#534)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 19:58:39 -04:00
sencho-token-app[bot] 2c2d76d241 chore(main): release 0.45.6 (#531)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 19:31:04 -04:00
sencho-token-app[bot] 04bac48c68 chore(main): release 0.45.5 (#528)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 15:35:23 -04:00
sencho-token-app[bot] fd31b87598 chore(main): release 0.45.4 (#524)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 14:32:14 -04:00
sencho-token-app[bot] 9aadfcebed chore(main): release 0.45.3 (#521)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 05:46:21 -04:00
sencho-token-app[bot] c02f8a5de0 chore(main): release 0.45.2 (#518)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 04:27:01 -04:00
sencho-token-app[bot] 98a712657a chore(main): release 0.45.1 (#515)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 03:20:27 -04:00
sencho-token-app[bot] c18f5258e5 chore(main): release 0.45.0 (#511)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 02:27:38 -04:00