forked from jappel/leistungsbilanz-ts
crypto.randomUUID() is only defined in secure contexts (HTTPS or localhost). Opened over plain HTTP from another machine in the LAN, the circuit list editor failed with "crypto.randomUUID is not a function" whenever it created a circuit, device row, circuit group or distribution board component, including typing into the -frei- row. createClientId() uses crypto.randomUUID() where available and otherwise builds an RFC 4122 version 4 UUID from crypto.getRandomValues(), which works in every context. AGENTS.md notes the rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { webcrypto } from "node:crypto";
|
|
import { describe, it } from "node:test";
|
|
import { z } from "zod";
|
|
import { createClientId } from "../src/frontend/utils/client-id.js";
|
|
|
|
const uuidV4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
|
|
describe("client id", () => {
|
|
it("uses crypto.randomUUID when the context provides it", () => {
|
|
const id = createClientId({
|
|
getRandomValues: () => {
|
|
throw new Error("fallback must not be used");
|
|
},
|
|
randomUUID: () => "11111111-2222-4333-8444-555555555555",
|
|
});
|
|
assert.equal(id, "11111111-2222-4333-8444-555555555555");
|
|
});
|
|
|
|
it("falls back to getRandomValues outside a secure context", () => {
|
|
const insecure = {
|
|
getRandomValues: webcrypto.getRandomValues.bind(webcrypto),
|
|
} as Pick<Crypto, "getRandomValues">;
|
|
const ids = new Set<string>();
|
|
for (let index = 0; index < 200; index += 1) {
|
|
const id = createClientId(insecure);
|
|
assert.match(id, uuidV4);
|
|
assert.equal(z.string().uuid().safeParse(id).success, true);
|
|
ids.add(id);
|
|
}
|
|
assert.equal(ids.size, 200);
|
|
});
|
|
|
|
it("sets version and variant bits regardless of the random bytes", () => {
|
|
const allOnes = {
|
|
getRandomValues: <T extends ArrayBufferView | null>(array: T) => {
|
|
if (array instanceof Uint8Array) {
|
|
array.fill(0xff);
|
|
}
|
|
return array;
|
|
},
|
|
} as Pick<Crypto, "getRandomValues">;
|
|
assert.equal(createClientId(allOnes), "ffffffff-ffff-4fff-bfff-ffffffffffff");
|
|
});
|
|
});
|