From c9d9522f3e1c1e3e47bc5406cb706d0bea90f2cc Mon Sep 17 00:00:00 2001 From: David Brownman <109395161+xavdid-stripe@users.noreply.github.com> Date: Tue, 18 Oct 2022 10:15:29 -0700 Subject: [PATCH] use native UUID method if available (#1585) * use native UUID method if available Co-authored-by: Richard Marmorstein --- lib/utils.js | 5 +++++ src/utils.ts | 6 ++++++ test/utils.spec.js | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/lib/utils.js b/lib/utils.js index a17afff790..2ed6fb43cf 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -369,6 +369,11 @@ const utils = { * https://stackoverflow.com/a/2117523 */ uuid4: () => { + // available in: v14.17.x+ + if (crypto.randomUUID) { + return crypto.randomUUID(); + } + // legacy behavior if native UUIDs aren't available return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; diff --git a/src/utils.ts b/src/utils.ts index b3ac274cbc..40b12656bd 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -428,6 +428,12 @@ const utils = { * https://stackoverflow.com/a/2117523 */ uuid4: () => { + // available in: v14.17.x+ + if (crypto.randomUUID) { + return crypto.randomUUID(); + } + + // legacy behavior if native UUIDs aren't available return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; diff --git a/test/utils.spec.js b/test/utils.spec.js index c20f709c59..91a6e1f9f9 100644 --- a/test/utils.spec.js +++ b/test/utils.spec.js @@ -609,6 +609,45 @@ describe('utils', () => { }).to.throw(); }); }); + + describe('uuid', () => { + describe('crypto.randomUUID', () => { + const crypto = require('crypto'); + let randomUUID$; + let called; + beforeEach(() => { + // if it's available, mock it and ensure it's called + // otherwise, skip this whole operation + if (crypto.randomUUID) { + called = false; + randomUUID$ = crypto.randomUUID; + crypto.randomUUID = () => { + called = true; + return 'no, YOU you id'; + }; + } + }); + afterEach(() => { + if (randomUUID$) { + crypto.randomUUID = randomUUID$; + } + }); + it('is called if available', () => { + if (randomUUID$) { + expect(utils.uuid4()).to.equal('no, YOU you id'); + expect(called).to.equal(true); + } + }); + }); + it('should return a well-formatted v4 UUID', () => { + expect(utils.uuid4()).to.match( + // regex from https://createuuid.com/validator/, specifically for v4 + /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i + ); + // further test: could spy on crypto.randomUUID to ensure it's being used, if available + // whether that's useful is a race between using jest/sinon for these tests and dropping support for node < 14 + }); + }); }); function handleWarnings(doWithShimmedConsoleWarn, onWarn) {