mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 14:16:12 +00:00
feat(security): add a TOTP and security-key setup hub
Introduce a dedicated /settings/security section that gathers every account-protection control in one place: TOTP enrolment (QR plus manual secret, confirm, recovery codes shown once with copy and download), WebAuthn security keys as a second factor (register, list with last-used, rename, step-up-gated removal), recovery-code count and regeneration, and primary passkey management. The second-factor WebAuthn path keeps its own credential store, separate from primary passkeys, and uses non-resident keys so an account can hold many. Relying-party resolution is shared with the passkey path. A status endpoint backs the hub; the step-up gate now recognises a registered security key as an active second factor so a WebAuthn-only account can still reach the gated actions.
This commit is contained in:
1 parent
6d053c3667
commit
402ea90d45
32 files changed
+3246
-401
No files matched your search
@@ -539,8 +539,15 @@ export async function requireFreshMfa(
|
||||
// The user must actually have a second factor active. A single-factor
|
||||
// account cannot produce a fresh-MFA proof, so step-up-gated actions are
|
||||
// unreachable for it by design (the management UI gates enrolment first).
|
||||
// Either factor counts: a confirmed TOTP secret OR a registered WebAuthn
|
||||
// security key — both stamp `Session.mfaVerifiedAt` on a completed login.
|
||||
if (!sessionData.user.totpConfirmedAt) {
|
||||
throw new StepUpRequiredError("auth.stepup.mfa_not_enrolled");
|
||||
const webauthnKeyCount = await prisma.webauthnMfaCredential.count({
|
||||
where: { userId: sessionData.user.id },
|
||||
});
|
||||
if (webauthnKeyCount === 0) {
|
||||
throw new StepUpRequiredError("auth.stepup.mfa_not_enrolled");
|
||||
}
|
||||
}
|
||||
|
||||
// Read the freshness stamp off the live session row — `getSession`'s
|
||||
|
||||
Reference in new issue
Block a user