Files
WRNexusJS/packages/auth/test/totp.test.ts
T
2026-07-29 12:51:10 +05:30

42 lines
1.5 KiB
TypeScript

import { expect, test } from "bun:test";
import {
decodeBase32,
generateTotp,
generateTotpSecret,
totpUri,
verifyTotp,
} from "../src/totp/index.ts";
test("TOTP matches the RFC 6238 SHA-1 vector", async () => {
const secret = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ";
expect(await generateTotp(secret, { timestamp: 59_000, digits: 8 })).toBe("94287082");
expect(await verifyTotp(secret, "94287082", { timestamp: 59_000, digits: 8, window: 0 })).toEqual(
{ valid: true, counter: 1 },
);
});
test("TOTP rejects malformed secrets, tokens, and unsafe options", async () => {
expect(() => decodeBase32("JBSW0Y3P")).toThrow("Invalid base32 secret");
expect(() => decodeBase32("====")).toThrow("Invalid base32 secret");
expect(() => generateTotpSecret(() => new Uint8Array(19))).toThrow(
"must return exactly 20 bytes",
);
await expect(generateTotp("JBSWY3DPEHPK3PXP", { period: 0 })).rejects.toThrow("TOTP period");
expect(await verifyTotp("JBSWY3DPEHPK3PXP", "12ab56", { timestamp: 59_000 })).toEqual({
valid: false,
});
});
test("TOTP URI validates and normalizes configuration", () => {
const uri = totpUri({
issuer: " WorkRoot ",
accountName: " user@example.com ",
secret: "JBSW Y3DP-EHPK3PXP",
});
expect(uri).toContain("secret=JBSWY3DPEHPK3PXP");
expect(uri).toContain("issuer=WorkRoot");
expect(() =>
totpUri({ issuer: "", accountName: "user@example.com", secret: "JBSWY3DPEHPK3PXP" }),
).toThrow("issuer and account name");
});