feat: release authentication diagnostics 0.2.0
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { utf8ToBytes } from "../../src/crypto/encoding";
|
||||
import {
|
||||
decryptOtpBackup,
|
||||
encryptOtpBackup,
|
||||
} from "../../src/otp/encrypted-backup";
|
||||
import type { OtpProfile } from "../../src/otp/profile";
|
||||
|
||||
const profile: OtpProfile = {
|
||||
kind: "totp",
|
||||
secret: utf8ToBytes("12345678901234567890"),
|
||||
issuer: "Example",
|
||||
account: "alice",
|
||||
algorithm: "SHA-256",
|
||||
digits: 8,
|
||||
period: 45,
|
||||
epoch: 12,
|
||||
counter: 0n,
|
||||
extensions: new Map([["image", "none"]]),
|
||||
};
|
||||
|
||||
describe("encrypted OTP backups", () => {
|
||||
it("round-trips profiles through authenticated encryption", async () => {
|
||||
const encrypted = await encryptOtpBackup(
|
||||
[profile],
|
||||
"correct horse battery staple",
|
||||
);
|
||||
expect(encrypted).not.toContain("JBSWY");
|
||||
const restored = await decryptOtpBackup(
|
||||
encrypted,
|
||||
"correct horse battery staple",
|
||||
);
|
||||
expect(restored[0]).toMatchObject({
|
||||
issuer: "Example",
|
||||
account: "alice",
|
||||
epoch: 12,
|
||||
counter: 0n,
|
||||
});
|
||||
expect([...restored[0]!.secret]).toEqual([...profile.secret]);
|
||||
});
|
||||
|
||||
it("rejects a wrong password and tampering", async () => {
|
||||
const encrypted = await encryptOtpBackup(
|
||||
[profile],
|
||||
"correct horse battery staple",
|
||||
);
|
||||
await expect(
|
||||
decryptOtpBackup(encrypted, "different secure password"),
|
||||
).rejects.toThrow(/authentication failed/iu);
|
||||
const parsed = JSON.parse(encrypted) as { ciphertext: string };
|
||||
parsed.ciphertext = `${parsed.ciphertext.slice(0, -2)}AA`;
|
||||
await expect(
|
||||
decryptOtpBackup(JSON.stringify(parsed), "correct horse battery staple"),
|
||||
).rejects.toThrow(/authentication failed/iu);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user