1import {2 backupSecretWithPasskey,3 mapPasskeyBackupError,4 restoreSecretWithPasskey,5} from "./passkey-recovery.ts";6import { assert } from "./test-assert.ts";78function domError(name: string): DOMException {9 return new DOMException("vendor detail must not reach the UI", name);10}1112Deno.test("passkey backup errors become actionable non-secret recovery errors", () => {13 const cases = [14 [new PasskeyBackupError("not-supported"), "unsupported"],15 [new PasskeyBackupError("no-credential"), "credential-missing"],16 [new PasskeyBackupError("verification-failed"), "verification-failed"],17 [new PasskeyBackupError("invalid-credential"), "invalid-credential"],18 [new PasskeyBackupError("get-failed", domError("SecurityError")), "rp-id-mismatch"],19 [new PasskeyBackupError("get-failed", domError("NotAllowedError")), "cancelled"],20 ] as const;21 for (const [input, code] of cases) {22 const mapped = mapPasskeyBackupError(input, "restore");23 assert(mapped.code === code, `${input.code} mapped to ${mapped.code}, expected ${code}`);24 assert(25 !mapped.message.includes("vendor detail"),26 "vendor detail leaked into public error text",27 );28 }29});3031Deno.test("passkey adapter backs up and restores the exact account secret", async () => {32 const expected = "account-secret";33 let backedUp: { secret: string; displayName: string } | undefined;34 const adapter = {35 backup(secret: string, displayName: string) {36 backedUp = { secret, displayName };37 return Promise.resolve();38 },39 restore() {40 return Promise.resolve(expected);41 },42 };43 await backupSecretWithPasskey(adapter, expected, "Account recovery");44 assert(backedUp?.secret === expected, "backup changed the account secret");45 assert(backedUp?.displayName === "Account recovery", "backup changed the display name");46 assert(47 await restoreSecretWithPasskey(adapter) === expected,48 "restore changed the account secret",49 );50});5152Deno.test("unknown passkey failures distinguish backup from restore without leaking causes", () => {53 assert(54 mapPasskeyBackupError(new Error("secret payload"), "backup").code === "backup-failed",55 "unknown backup failure was misclassified",56 );57 assert(58 mapPasskeyBackupError(new Error("secret payload"), "restore").code === "restore-failed",59 "unknown restore failure was misclassified",60 );61});62class PasskeyBackupError extends Error {63 override readonly name = "PasskeyBackupError";64 constructor(readonly code: string, override readonly cause?: unknown) {65 super(code);66 }67}