From 59395dc149654128f2996f4999bccb66270f54e4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sun, 22 Jan 2023 20:32:29 +0100 Subject: [PATCH] Use crypto unbiased random integer generator MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/utils/Constants.ts | 2 ++ src/utils/Utils.ts | 11 +++++------ test/utils/UtilsTest.ts | 17 +++++++++++++---- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index c7e767eb..241018fc 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -45,6 +45,8 @@ export default class Constants { static readonly UNKNOWN_COMMAND = 'unknown command'; + static readonly MAX_RANDOM_INTEGER = 281474976710654; + private constructor() { // This is intentional } diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 8f63eb68..203054dc 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -3,6 +3,7 @@ import util from 'node:util'; import clone from 'just-clone'; +import Constants from './Constants'; import { WebSocketCloseEventStatusString } from '../types/WebSocket'; export default class Utils { @@ -129,16 +130,13 @@ export default class Utils { return sign * (randomPositiveFloat * (max - min) + min); } - public static getRandomInteger(max = Number.MAX_SAFE_INTEGER, min = 0): number { - if (max < min || max < 0 || min < 0) { - throw new RangeError('Invalid interval'); - } + public static getRandomInteger(max = Constants.MAX_RANDOM_INTEGER, min = 0): number { max = Math.floor(max); if (!Utils.isNullOrUndefined(min) && min !== 0) { min = Math.ceil(min); - return Math.floor(Utils.secureRandom() * (max - min + 1)) + min; + return Math.floor(crypto.randomInt(min, max + 1)); } - return Math.floor(Utils.secureRandom() * (max + 1)); + return Math.floor(crypto.randomInt(max + 1)); } public static roundTo(numberValue: number, scale: number): number { @@ -259,6 +257,7 @@ export default class Utils { setTimeout(() => { if (Utils.isPromisePending(promise)) { timeoutCallback(); + // FIXME: The original promise shall be canceled } reject(timeoutError); }, timeoutMs); diff --git a/test/utils/UtilsTest.ts b/test/utils/UtilsTest.ts index 45ba4eb0..a826b367 100644 --- a/test/utils/UtilsTest.ts +++ b/test/utils/UtilsTest.ts @@ -1,5 +1,6 @@ import expect from 'expect'; +import Constants from '../../src/utils/Constants'; import Utils from '../../src/utils/Utils'; describe('Utils test suite', () => { @@ -107,11 +108,19 @@ describe('Utils test suite', () => { let randomInteger = Utils.getRandomInteger(); expect(Number.isSafeInteger(randomInteger)).toBe(true); expect(randomInteger).toBeGreaterThanOrEqual(0); - expect(randomInteger).toBeLessThanOrEqual(Number.MAX_SAFE_INTEGER); + expect(randomInteger).toBeLessThanOrEqual(Constants.MAX_RANDOM_INTEGER); expect(randomInteger).not.toEqual(Utils.getRandomInteger()); - expect(() => Utils.getRandomInteger(0, 1)).toThrowError(new RangeError('Invalid interval')); - expect(() => Utils.getRandomInteger(-1)).toThrowError(new RangeError('Invalid interval')); - expect(() => Utils.getRandomInteger(0, -1)).toThrowError(new RangeError('Invalid interval')); + expect(() => Utils.getRandomInteger(0, 1)).toThrowError( + 'The value of "max" is out of range. It must be greater than the value of "min" (1). Received 1' + ); + expect(() => Utils.getRandomInteger(-1)).toThrowError( + 'The value of "max" is out of range. It must be greater than the value of "min" (0). Received 0' + ); + expect(() => Utils.getRandomInteger(Constants.MAX_RANDOM_INTEGER + 1)).toThrowError( + `The value of "max" is out of range. It must be <= ${ + Constants.MAX_RANDOM_INTEGER + 1 + }. Received 281_474_976_710_656` + ); randomInteger = Utils.getRandomInteger(2, 1); expect(randomInteger).toBeGreaterThanOrEqual(1); expect(randomInteger).toBeLessThanOrEqual(2); -- 2.34.1