chore: patch deps, CSP style nonces, otplib 13, and PR CI
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m35s

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-21 20:46:02 +02:00
1 parent 87bda8dbef
commit 2ff08e5127
11 files changed
+239 -160

No files matched your search

+28 -8
View File
@@ -1,13 +1,29 @@
import { authenticator } from "otplib";
import {
createGuardrails,
generateSecret,
generateSync,
generateURI,
verifySync,
} from "otplib";
// Laravel Fortify uses pragmarx/google2fa: HMAC-SHA1, 6 digits, 30s period.
// otplib already defaults to SHA1/6/30; window=1 tolerates one step of skew.
authenticator.options = { window: 1 };
// Laravel Fortify / pragmarx google2fa: HMAC-SHA1, 6 digits, 30s period.
// Allow legacy secrets shorter than otplib v13's default 16-byte minimum
// (many existing AtomCMS/Fortify secrets decode to ~10 bytes).
const guardrails = createGuardrails({ MIN_SECRET_BYTES: 10 });
// ±1 time-step of clock skew (30s period → epochTolerance 30).
const EPOCH_TOLERANCE = 30;
/** Verify a 6-digit TOTP code against a base32 secret. */
export function verifyTotp(token: string, secret: string): boolean {
try {
return authenticator.check(token, secret);
const result = verifySync({
secret,
token,
epochTolerance: EPOCH_TOLERANCE,
guardrails,
});
return result.valid === true;
} catch {
return false;
}
@@ -15,12 +31,12 @@ export function verifyTotp(token: string, secret: string): boolean {
/** Current TOTP code for a secret (used in tests / tooling). */
export function generateTotp(secret: string): string {
return authenticator.generate(secret);
return generateSync({ secret, guardrails });
}
/** Generate a fresh base32 secret for enrolling a new authenticator. */
export function generateTotpSecret(): string {
return authenticator.generateSecret();
return generateSecret();
}
/** otpauth:// URI for provisioning a QR code. */
@@ -29,5 +45,9 @@ export function totpKeyUri(
accountName: string,
issuer: string,
): string {
return authenticator.keyuri(accountName, issuer, secret);
return generateURI({
issuer,
label: accountName,
secret,
});
}