From 397c5491b6a8c73da91c00a0ae3568dc4e51ef12 Mon Sep 17 00:00:00 2001 From: Arutyunyan Artyom Date: Tue, 11 Jan 2022 10:50:58 +0000 Subject: [PATCH] fix collision by proxy number --- index.js | 6 ++++-- test/index.test.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 19306b10..93ffabf7 100644 --- a/index.js +++ b/index.js @@ -23,7 +23,8 @@ let fillPool = bytes => { } let random = bytes => { - fillPool(bytes) + // `-=` convert `bytes` to number to prevent `valueOf` abusing + fillPool((bytes -= 0)) return pool.subarray(poolOffset - bytes, poolOffset) } @@ -65,7 +66,8 @@ let customRandom = (alphabet, size, getRandom) => { let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random) let nanoid = (size = 21) => { - fillPool(size) + // `-=` convert `size` to number to prevent `valueOf` abusing + fillPool((size -= 0)) let id = '' // We are reading directly from the random pool to avoid creating new array for (let i = poolOffset - size; i < poolOffset; i++) { diff --git a/test/index.test.js b/test/index.test.js index 18043e0f..2a6e91c1 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -151,5 +151,41 @@ for (let type of ['node', 'browser']) { } }) }) + + if (type === 'node') { + describe('proxy number', () => { + it('prevent collision', () => { + let makeProxyNumberToReproducePreviousID = () => { + let step = 0 + return { + valueOf() { + // "if (!pool || pool.length < bytes) {" + if (step === 0) { + step++ + return 0 + } + // "} else if (poolOffset + bytes > pool.length) {" + if (step === 1) { + step++ + return -Infinity + } + // "poolOffset += bytes" + if (step === 2) { + step++ + return 0 + } + + return 21 + } + } + } + + let ID1 = nanoid() + let ID2 = nanoid(makeProxyNumberToReproducePreviousID()) + + expect(ID1).not.toBe(ID2) + }) + }) + } }) }