import * as OTPAuth from 'otpauth'; const ISSUER = 'RareIndex'; export function newTotpSecret(): string { return new OTPAuth.Secret({ size: 20 }).base32; } export function totpUri(secretB32: string, email: string): string { return new OTPAuth.TOTP({ issuer: ISSUER, label: email, algorithm: 'SHA1', digits: 6, period: 30, secret: OTPAuth.Secret.fromBase32(secretB32) }).toString(); } /** Verify a 6-digit TOTP with ±1 step tolerance. Returns the matched step delta or null. */ export function verifyTotp(secretB32: string, token: string, window = 1): number | null { const clean = token.replace(/\s+/g, ''); if (!/^\d{6}$/.test(clean)) return null; const totp = new OTPAuth.TOTP({ issuer: ISSUER, algorithm: 'SHA1', digits: 6, period: 30, secret: OTPAuth.Secret.fromBase32(secretB32) }); return totp.validate({ token: clean, window }); } export function currentTotp(secretB32: string): string { return new OTPAuth.TOTP({ issuer: ISSUER, algorithm: 'SHA1', digits: 6, period: 30, secret: OTPAuth.Secret.fromBase32(secretB32) }).generate(); }