Skip to content

Commit

Permalink
fix: uuid collisions (#594)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mercy811 authored Jun 6, 2023
1 parent d346cba commit a1a2978
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 25 deletions.
6 changes: 5 additions & 1 deletion src/base64Id.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';

const base64Id = () => {
const randomValues = crypto.getRandomValues(new Uint8Array(22));

let str = '';

for (let i = 0; i < 22; ++i) {
str += base64Chars.charAt(Math.floor(Math.random() * 64));
str += base64Chars.charAt(randomValues[i] % 64);
}

return str;
};

Expand Down
36 changes: 12 additions & 24 deletions src/uuid.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,22 @@
/**
* Source: [jed's gist]{@link https://gist.github.com/982883}.
* Source: [jed's gist's comment]{@link https://gist.github.com/jed/982883?permalink_comment_id=3223002#gistcomment-3223002}.
* Returns a random v4 UUID of the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
* where each x is replaced with a random hexadecimal digit from 0 to f, and
* y is replaced with a random hexadecimal digit from 8 to b.
* Used to generate UUIDs for deviceIds.
* @private
*/
var uuid = function (a) {
return a // if the placeholder was passed, return
? // a random number from 0 to 15
(
a ^ // unless b is 8,
((Math.random() * // in which case
16) >> // a random number from
(a / 4))
) // 8 to 11
.toString(16) // in hexadecimal
: // or otherwise a concatenated string:
(
[1e7] + // 10000000 +
-1e3 + // -1000 +
-4e3 + // -4000 +
-8e3 + // -80000000 +
-1e11
) // -100000000000,
.replace(
// replacing
/[018]/g, // zeroes, ones, and eights with
uuid, // random hex digits
);

// hoist hex table out of the function to avoid re-calculation
const hex = [...Array(256).keys()].map((index) => index.toString(16).padStart(2, '0'));

var uuid = () => {
const r = crypto.getRandomValues(new Uint8Array(16));

r[6] = (r[6] & 0x0f) | 0x40;
r[8] = (r[8] & 0x3f) | 0x80;

return [...r.entries()].map(([index, int]) => ([4, 6, 8, 10].includes(index) ? `-${hex[int]}` : hex[int])).join('');
};

export default uuid;
9 changes: 9 additions & 0 deletions test/base64Id.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,13 @@ describe('base64Id', () => {
it('should return an id of safe base64 characters', () => {
assert.equal(true, /^[a-zA-Z0-9\-_]*$/.test(base64Id()));
});

it('should generate a unique base64Id', () => {
const ids = new Set();
const count = 10000;
for (let i = 0; i < count; i++) {
ids.add(base64Id());
}
assert.equal(ids.size, count);
});
});
9 changes: 9 additions & 0 deletions test/uuid.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,13 @@ describe('UUID', function () {
assert.equal(36, uuid.length);
assert.equal('4', uuid.substring(14, 15));
});

it('should generate a unique UUID-4', () => {
const ids = new Set();
const count = 10000;
for (let i = 0; i < count; i++) {
ids.add(UUID());
}
assert.equal(ids.size, count);
});
});

0 comments on commit a1a2978

Please sign in to comment.