Как-то так.
UPD: провел
тесты, и переделал логику «сборки» итогового значения.
const createKeyGenerator = (groupSize, groupCount) => {
const dictionary = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
const length = groupSize * groupCount;
return () => {
const values = new Uint32Array(length);
crypto.getRandomValues(values);
const chars = [...values].map(value => dictionary[value % dictionary.length]);
const key = new Array(groupCount)
.fill(null)
.map((_, index) => {
const offset = index * groupSize;
return chars
.slice(offset, offset + groupSize)
.join('');
})
.join('-');
return key;
};
};
const createKey = createKeyGenerator(4, 3);
console.log(createKey()); // FO4V-P2ZV-JYH4
console.log(createKey()); // TTMR-EBVC-8TUW
Также, по-хорошему если данные коды будут хранится в БД, неплохо бы на существование проверять.
Предыдущая версия
const createKeyGenerator = (groupSize, groupCount) => {
const dictionary = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
const length = groupSize * groupCount;
const group = new RegExp(`.{${groupSize}}`, 'g');
return () => {
const values = new Uint32Array(length);
crypto.getRandomValues(values);
const chars = [...values].map(value => dictionary[value % dictionary.length]);
const key = '_'
.repeat(length)
.replace(/\w/g, (match, index) => chars[index])
.match(group)
.join('-');
return key;
};
};
Хочу заметить: не могу гарантировать 100%, что алгоритм будет устойчивым (без повторов). Проверял на
Set
коллекции, по итогу размер коллекции превысил (
16^6
значений) и получил исключение. При этом не было ни одного повтора.