diff --git a/packages/utils/src/misc.ts b/packages/utils/src/misc.ts index a474c8e157e4..9799df421c31 100644 --- a/packages/utils/src/misc.ts +++ b/packages/utils/src/misc.ts @@ -25,13 +25,19 @@ export function uuid4(): string { const gbl = GLOBAL_OBJ as typeof GLOBAL_OBJ & CryptoGlobal; const crypto = gbl.crypto || gbl.msCrypto; - if (crypto && crypto.randomUUID) { - return crypto.randomUUID().replace(/-/g, ''); + let getRandomByte = (): number => Math.random() * 16; + try { + if (crypto && crypto.randomUUID) { + return crypto.randomUUID().replace(/-/g, ''); + } + if (crypto && crypto.getRandomValues) { + getRandomByte = () => crypto.getRandomValues(new Uint8Array(1))[0]; + } + } catch (_) { + // some runtimes can crash invoking crypto + // https://github.com/getsentry/sentry-javascript/issues/8935 } - const getRandomByte = - crypto && crypto.getRandomValues ? () => crypto.getRandomValues(new Uint8Array(1))[0] : () => Math.random() * 16; - // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 // Concatenating the following numbers as strings results in '10000000100040008000100000000000' return (([1e7] as unknown as string) + 1e3 + 4e3 + 8e3 + 1e11).replace(/[018]/g, c => diff --git a/packages/utils/test/misc.test.ts b/packages/utils/test/misc.test.ts index aaac0d46c0b0..dc75b70d4286 100644 --- a/packages/utils/test/misc.test.ts +++ b/packages/utils/test/misc.test.ts @@ -290,11 +290,12 @@ describe('checkOrSetAlreadyCaught()', () => { }); describe('uuid4 generation', () => { + const uuid4Regex = /^[0-9A-F]{12}[4][0-9A-F]{3}[89AB][0-9A-F]{15}$/i; // Jest messes with the global object, so there is no global crypto object in any node version // For this reason we need to create our own crypto object for each test to cover all the code paths it('returns valid uuid v4 ids via Math.random', () => { for (let index = 0; index < 1_000; index++) { - expect(uuid4()).toMatch(/^[0-9A-F]{12}[4][0-9A-F]{3}[89AB][0-9A-F]{15}$/i); + expect(uuid4()).toMatch(uuid4Regex); } }); @@ -305,7 +306,7 @@ describe('uuid4 generation', () => { (global as any).crypto = { getRandomValues: cryptoMod.getRandomValues }; for (let index = 0; index < 1_000; index++) { - expect(uuid4()).toMatch(/^[0-9A-F]{12}[4][0-9A-F]{3}[89AB][0-9A-F]{15}$/i); + expect(uuid4()).toMatch(uuid4Regex); } }); @@ -316,7 +317,30 @@ describe('uuid4 generation', () => { (global as any).crypto = { randomUUID: cryptoMod.randomUUID }; for (let index = 0; index < 1_000; index++) { - expect(uuid4()).toMatch(/^[0-9A-F]{12}[4][0-9A-F]{3}[89AB][0-9A-F]{15}$/i); + expect(uuid4()).toMatch(uuid4Regex); + } + }); + + it("return valid uuid v4 even if crypto doesn't exists", () => { + (global as any).crypto = { getRandomValues: undefined, randomUUID: undefined }; + + for (let index = 0; index < 1_000; index++) { + expect(uuid4()).toMatch(uuid4Regex); + } + }); + + it('return valid uuid v4 even if crypto invoked causes an error', () => { + (global as any).crypto = { + getRandomValues: () => { + throw new Error('yo'); + }, + randomUUID: () => { + throw new Error('yo'); + }, + }; + + for (let index = 0; index < 1_000; index++) { + expect(uuid4()).toMatch(uuid4Regex); } }); });