mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
Supersedes #1252 and #872. uuid 14 is ESM-only, apps/web/jest.config.ts only kept v9 working by mapping `^uuid$` at a `wrapper.mjs` that v14 no longer ships, and the specifier also has to be synced in libs/shared/m3u-utils/package.json or @nx/dependency-checks fails lint. All four call sites only used `v4()`, so the dependency goes away instead. `createRandomId()` prefers `crypto.randomUUID()` and falls back to building the same v4 shape from `crypto.getRandomValues()` — that fallback is load-bearing, because randomUUID is only exposed in secure contexts and the self-hosted PWA is regularly served over plain http on a LAN address. getRandomValues stays available there, and it is what uuid's own v4 used. `@types/uuid` goes too; it only existed for the untyped v9 package.
85 lines
2.4 KiB
TypeScript
85 lines
2.4 KiB
TypeScript
import { createRandomId } from './random-id.util';
|
|
|
|
const UUID_V4 =
|
|
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
|
|
describe('createRandomId', () => {
|
|
const nativeRandomUUID = crypto.randomUUID;
|
|
|
|
afterEach(() => {
|
|
Object.defineProperty(crypto, 'randomUUID', {
|
|
configurable: true,
|
|
value: nativeRandomUUID,
|
|
});
|
|
});
|
|
|
|
it('returns a v4 uuid', () => {
|
|
expect(createRandomId()).toMatch(UUID_V4);
|
|
});
|
|
|
|
it('returns unique ids', () => {
|
|
const ids = new Set(
|
|
Array.from({ length: 500 }, () => createRandomId())
|
|
);
|
|
|
|
expect(ids.size).toBe(500);
|
|
});
|
|
|
|
it('uses the native randomUUID when the context exposes it', () => {
|
|
const randomUUID = jest
|
|
.fn()
|
|
.mockReturnValue('11111111-1111-4111-8111-111111111111');
|
|
Object.defineProperty(crypto, 'randomUUID', {
|
|
configurable: true,
|
|
value: randomUUID,
|
|
});
|
|
|
|
expect(createRandomId()).toBe('11111111-1111-4111-8111-111111111111');
|
|
expect(randomUUID).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
describe('without randomUUID (insecure context)', () => {
|
|
beforeEach(() => {
|
|
Object.defineProperty(crypto, 'randomUUID', {
|
|
configurable: true,
|
|
value: undefined,
|
|
});
|
|
});
|
|
|
|
it('still returns a v4 uuid from getRandomValues', () => {
|
|
expect(createRandomId()).toMatch(UUID_V4);
|
|
});
|
|
|
|
it('returns unique ids', () => {
|
|
const ids = new Set(
|
|
Array.from({ length: 500 }, () => createRandomId())
|
|
);
|
|
|
|
expect(ids.size).toBe(500);
|
|
});
|
|
|
|
it('sets the version and variant bits on all-zero randomness', () => {
|
|
jest.spyOn(crypto, 'getRandomValues').mockImplementation(
|
|
(buffer) => buffer
|
|
);
|
|
|
|
expect(createRandomId()).toBe(
|
|
'00000000-0000-4000-8000-000000000000'
|
|
);
|
|
});
|
|
|
|
it('keeps the remaining bits from getRandomValues', () => {
|
|
jest.spyOn(crypto, 'getRandomValues').mockImplementation(
|
|
(buffer) => {
|
|
(buffer as Uint8Array).fill(0xff);
|
|
return buffer;
|
|
}
|
|
);
|
|
|
|
expect(createRandomId()).toBe(
|
|
'ffffffff-ffff-4fff-bfff-ffffffffffff'
|
|
);
|
|
});
|
|
});
|
|
});
|