mfa.test.ts30 lines · main
| 1 | import { describe, expect, test } from 'bun:test'; |
| 2 | |
| 3 | import { generateTotpCode, verifyTotpCode } from './mfa.js'; |
| 4 | |
| 5 | describe('TOTP pure helpers (Phase 5)', () => { |
| 6 | // Fixed secret for deterministic tests (base32 of known bytes) |
| 7 | const secret = 'JBSWY3DPEHPK3PXP'; |
| 8 | |
| 9 | test('generates 6-digit codes', () => { |
| 10 | const code = generateTotpCode(secret, 1_700_000_000_000); |
| 11 | expect(code).toMatch(/^\d{6}$/); |
| 12 | }); |
| 13 | |
| 14 | test('verifies matching code', () => { |
| 15 | const at = 1_700_000_000_000; |
| 16 | const code = generateTotpCode(secret, at); |
| 17 | expect(verifyTotpCode(secret, code, 1, at)).toBe(true); |
| 18 | }); |
| 19 | |
| 20 | test('rejects wrong code', () => { |
| 21 | expect(verifyTotpCode(secret, '000000', 1, 1_700_000_000_000)).toBe(false); |
| 22 | }); |
| 23 | |
| 24 | test('accepts within time window', () => { |
| 25 | const at = 1_700_000_000_000; |
| 26 | const code = generateTotpCode(secret, at); |
| 27 | // one step later still within window=1 |
| 28 | expect(verifyTotpCode(secret, code, 1, at + 30_000)).toBe(true); |
| 29 | }); |
| 30 | }); |