74 lines
2.3 KiB
TypeScript
74 lines
2.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
compareTraces,
|
|
parseTrace,
|
|
redactTrace,
|
|
type AuthenticationTrace,
|
|
} from "../../src/webauthn/trace";
|
|
|
|
function trace(): AuthenticationTrace {
|
|
return {
|
|
schema: "de.add-ideas.auth-tools.webauthn-trace",
|
|
version: 1,
|
|
kind: "authentication",
|
|
recordedAt: "2026-08-19T12:00:00.000Z",
|
|
request: {
|
|
user: { id: "user-id", name: "Alice", displayName: "Alice Example" },
|
|
extensions: { prf: true },
|
|
},
|
|
expectations: {
|
|
challenge: "AQID",
|
|
origin: "https://auth.example.test",
|
|
rpId: "auth.example.test",
|
|
},
|
|
credentialPublicKey: { "1": 2, "3": -7, "-1": 1 },
|
|
response: {
|
|
id: "credential-id",
|
|
rawId: "credential-id",
|
|
clientDataJSON: "e30",
|
|
authenticatorData: "AQID",
|
|
signature: "BAUG",
|
|
userHandle: "user-handle",
|
|
clientExtensionResults: { prf: { enabled: true } },
|
|
},
|
|
privacy: [],
|
|
};
|
|
}
|
|
|
|
describe("WebAuthn ceremony traces", () => {
|
|
it("parses the bounded versioned schema", () => {
|
|
expect(parseTrace(JSON.stringify(trace()))).toMatchObject({
|
|
kind: "authentication",
|
|
version: 1,
|
|
});
|
|
expect(() => parseTrace('{"version":2}')).toThrow(/schema/u);
|
|
let nested: Record<string, unknown> = {};
|
|
for (let depth = 0; depth < 70; depth += 1) nested = { nested };
|
|
expect(() =>
|
|
parseTrace(JSON.stringify({ ...trace(), request: nested })),
|
|
).toThrow(/depth limit/u);
|
|
});
|
|
|
|
it("redacts labels and top-level identifiers while preserving evidence", async () => {
|
|
const redacted = await redactTrace(trace());
|
|
expect(redacted.response.id).toMatch(/^sha256:/u);
|
|
expect(redacted.response.clientDataJSON).toBe("e30");
|
|
expect(
|
|
redacted.kind === "authentication" && redacted.response.userHandle,
|
|
).toBe("[redacted]");
|
|
expect((redacted.request.user as Record<string, string>).displayName).toBe(
|
|
"[redacted]",
|
|
);
|
|
});
|
|
|
|
it("compares nested trace state", () => {
|
|
const right = trace();
|
|
right.expectations.rpId = "other.example.test";
|
|
right.response.clientExtensionResults = { prf: { enabled: false } };
|
|
expect(compareTraces(trace(), right).map(({ path }) => path)).toEqual([
|
|
"expectations.rpId",
|
|
"response.clientExtensionResults.prf.enabled",
|
|
]);
|
|
});
|
|
});
|