Skip to content

Commit 1a33bb7

Browse files
committed
feat(client,utils) refactor random char generation
- Generate actually unique GUIDs - Use a better random character generator - Use a better alphabet for join codes which eliminates ambiguity
1 parent ecde249 commit 1a33bb7

File tree

2 files changed

+81
-42
lines changed

2 files changed

+81
-42
lines changed
Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,9 @@
11
/**
2-
* Generates a random 8 character long string.
3-
*
4-
* @returns {string}
5-
*/
6-
export function generate8Characters() {
7-
const buf = new Uint16Array(2);
8-
9-
window.crypto.getRandomValues(buf);
10-
11-
return `${s4(buf[0])}${s4(buf[1])}`;
12-
}
13-
14-
/**
15-
* Generate a likely-to-be-unique guid.
2+
* Generate a GUID.
163
*
174
* @private
185
* @returns {string} The generated string.
196
*/
207
export function generateGuid() {
21-
const buf = new Uint16Array(8);
22-
23-
window.crypto.getRandomValues(buf);
24-
25-
return `${s4(buf[0])}${s4(buf[1])}-${s4(buf[2])}-${s4(buf[3])}-${
26-
s4(buf[4])}-${s4(buf[5])}${s4(buf[6])}${s4(buf[7])}`;
27-
}
28-
29-
/**
30-
* Converts the passed in number to a string and ensure it is at least 4
31-
* characters in length, prepending 0's as needed.
32-
*
33-
* @param {number} num - The number to pad and convert to a string.
34-
* @private
35-
* @returns {string} - The number converted to a string.
36-
*/
37-
function s4(num) {
38-
let ret = num.toString(16);
39-
40-
while (ret.length < 4) {
41-
ret = `0${ret}`;
42-
}
43-
44-
return ret;
8+
return window.crypto.randomUUID();
459
}
Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,87 @@
1+
/**
2+
* Helper class to generate random values one by one, using an auxiliary
3+
* pool to avoid calling getRandomValues every time.
4+
*/
5+
class RandomPool {
6+
/**
7+
* Default size for the pool.
8+
*/
9+
SIZE = 256;
10+
11+
/**
12+
* Build a new pool.
13+
*/
14+
constructor() {
15+
this._rArray = new Uint8Array(this.SIZE);
16+
this._idx = this.SIZE; // Fill the pool on first use.
17+
}
18+
19+
/**
20+
* Gets a random number in the Uint8 range.
21+
*
22+
* @returns {number}
23+
*/
24+
getValue() {
25+
if (this._idx > this.SIZE - 1) {
26+
// Fill the pool.
27+
window.crypto.getRandomValues(this._rArray);
28+
this._idx = 0;
29+
}
30+
31+
return this._rArray[this._idx++];
32+
}
33+
}
34+
35+
const pool = new RandomPool();
36+
37+
/**
38+
* Choose `num` elements from `seq`, randomly.
39+
*
40+
* @param {string} seq - Sequence of characters, the alphabet.
41+
* @param {number} num - The amount of characters from the alphabet we want.
42+
* @returns {string}
43+
*/
44+
function randomChoice(seq, num) {
45+
const x = seq.length - 1;
46+
const r = new Array(num);
47+
let len = num;
48+
49+
while (len--) {
50+
// Make sure the random value is in our alphabet's range.
51+
// eslint-disable-next-line no-bitwise
52+
const idx = pool.getValue() & x;
53+
54+
r.push(seq[idx]);
55+
}
56+
57+
return r.join('');
58+
}
59+
60+
/**
61+
* This alphabet removes all potential ambiguous symbols, so it's well suited for a code.
62+
*/
63+
const BASE32 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
64+
165
/**
266
* A method to generate a random string, intended to be used to create a random join code.
367
*
468
* @param {number} length - The desired length of the random string.
569
* @returns {string}
670
*/
771
export function generateRandomString(length) {
8-
// XXX the method may not always give desired length above 9
9-
return Math.random()
10-
.toString(36)
11-
.slice(2, 2 + length);
72+
return randomChoice(BASE32, length);
73+
}
74+
75+
/**
76+
* This alphabet is similar to BASE32 above, but includes lowercase characters too.
77+
*/
78+
const BASE58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
79+
80+
/**
81+
* Generates a random 8 character long string.
82+
*
83+
* @returns {string}
84+
*/
85+
export function generate8Characters() {
86+
return randomChoice(BASE58, 8);
1287
}

0 commit comments

Comments
 (0)