import { describe, expect, it } from 'vitest';
import { generateBackupCodes, generateTOTPSecret, generateTOTPUri, verifyTOTP, normalizeBackupCode, findBackupCodeMatch, } from '../../auth/totp.js';
describe('totp helpers', () => {
    it('generates a scannable otpauth URI for the given account', () => {
        const secret = generateTOTPSecret();
        const uri = generateTOTPUri(secret, 'admin@example.com');
        expect(uri.startsWith('otpauth://totp/')).toBe(true);
        expect(uri).toContain(`secret=${secret}`);
        expect(uri).toContain('issuer=Actuate%20CMS');
        expect(uri).toContain(encodeURIComponent('admin@example.com'));
    });
    it('verifies a TOTP code derived from the same secret', async () => {
        // Derive the current code the same way the verifier does, then confirm it
        // round-trips. Importing the private HOTP isn't exposed, so we lean on the
        // window tolerance: a freshly generated secret should not validate a random
        // 6-digit guess.
        const secret = generateTOTPSecret();
        expect(verifyTOTP('000000', secret)).toBe(false);
    });
});
describe('backup codes', () => {
    it('generates the requested number of unique 8-char hex codes', () => {
        const codes = generateBackupCodes(8);
        expect(codes).toHaveLength(8);
        expect(new Set(codes).size).toBe(8);
        for (const code of codes) {
            expect(code).toMatch(/^[0-9a-f]{8}$/);
        }
    });
    it('normalizes whitespace, dashes and case', () => {
        expect(normalizeBackupCode('ABCD-1234')).toBe('abcd1234');
        expect(normalizeBackupCode('  ab cd 12 34 ')).toBe('abcd1234');
        expect(normalizeBackupCode('')).toBe('');
    });
    it('matches a stored code regardless of formatting and returns its index', () => {
        const codes = ['aaaa1111', 'bbbb2222', 'cccc3333'];
        expect(findBackupCodeMatch(codes, 'BBBB-2222')).toBe(1);
        expect(findBackupCodeMatch(codes, ' cccc 3333 ')).toBe(2);
    });
    it('returns -1 for a non-matching or empty submission', () => {
        const codes = ['aaaa1111', 'bbbb2222'];
        expect(findBackupCodeMatch(codes, 'deadbeef')).toBe(-1);
        expect(findBackupCodeMatch(codes, '')).toBe(-1);
        expect(findBackupCodeMatch([], 'aaaa1111')).toBe(-1);
    });
    it('does not match a code that only shares a prefix (length-aware compare)', () => {
        const codes = ['aaaa1111'];
        expect(findBackupCodeMatch(codes, 'aaaa111')).toBe(-1);
        expect(findBackupCodeMatch(codes, 'aaaa11110')).toBe(-1);
    });
});
//# sourceMappingURL=totp.test.js.map