feat: release OTP and Passkey Tools 0.1.0

This commit is contained in:
2026-08-19 12:19:35 +02:00
commit f1cb2d7151
67 changed files with 12802 additions and 0 deletions
+61
View File
@@ -0,0 +1,61 @@
import { describe, expect, it } from "vitest";
import { parseOtpAuth, serializeOtpAuth } from "../../src/otp/profile";
describe("otpauth profiles", () => {
it("parses and serializes a TOTP profile without losing extensions", () => {
const parsed = parseOtpAuth(
"otpauth://totp/Example:alice%40example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example&algorithm=SHA256&digits=8&period=45&image=ignored",
);
expect(parsed.profile).toMatchObject({
kind: "totp",
issuer: "Example",
account: "alice@example.com",
algorithm: "SHA-256",
digits: 8,
period: 45,
});
expect(parsed.profile.extensions.get("image")).toBe("ignored");
expect(serializeOtpAuth(parsed.profile)).toContain("image=ignored");
});
it("requires an HOTP counter and preserves 64-bit values", () => {
expect(() =>
parseOtpAuth("otpauth://hotp/Example?secret=JBSWY3DPEHPK3PXP"),
).toThrow(/counter/iu);
const parsed = parseOtpAuth(
"otpauth://hotp/Example?secret=JBSWY3DPEHPK3PXP&counter=18446744073709551615",
);
expect(parsed.profile.counter).toBe((1n << 64n) - 1n);
});
it("rejects duplicate known parameters", () => {
expect(() =>
parseOtpAuth(
"otpauth://totp/Example?secret=JBSWY3DPEHPK3PXP&secret=JBSWY3DPEHPK3PXP",
),
).toThrow(/duplicate/iu);
});
it("rejects partially numeric parameters and unsafe labels", () => {
expect(() =>
parseOtpAuth(
"otpauth://totp/Example?secret=JBSWY3DPEHPK3PXP&digits=6oops",
),
).toThrow(/integer/iu);
const parsed = parseOtpAuth(
"otpauth://totp/Example?secret=JBSWY3DPEHPK3PXP",
);
parsed.profile.account = "unsafe:label";
expect(() => serializeOtpAuth(parsed.profile)).toThrow(/colon/iu);
});
it("warns without silently reconciling issuer mismatch", () => {
const result = parseOtpAuth(
"otpauth://totp/Display:alice?secret=JBSWY3DPEHPK3PXP&issuer=canonical.example",
);
expect(result.profile.issuer).toBe("canonical.example");
expect(result.warnings.some(({ code }) => code === "issuer-mismatch")).toBe(
true,
);
});
});