diff --git a/src/util.js b/src/util.js index 8135f2a08..28239efa9 100644 --- a/src/util.js +++ b/src/util.js @@ -6,10 +6,10 @@ // // Backend uses the compiled file util.js // Frontend uses util.ts -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getMonitorRelativeURL = exports.genSecret = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0; -const _dayjs = require("dayjs"); -const dayjs = _dayjs; +exports.__esModule = true; +exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0; +var _dayjs = require("dayjs"); +var dayjs = _dayjs; exports.isDev = process.env.NODE_ENV === "development"; exports.appName = "Uptime Kuma"; exports.DOWN = 0; @@ -102,20 +102,61 @@ function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } exports.getRandomInt = getRandomInt; +/** + * Returns either the NodeJS crypto.randomBytes() function or its + * browser equivalent implemented via window.crypto.getRandomValues() + */ +var getRandomBytes = ((typeof window !== 'undefined' && window.crypto) + // Browsers + ? function () { + return function (numBytes) { + var randomBytes = new Uint8Array(numBytes); + for (var i = 0; i < numBytes; i += 65536) { + window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536))); + } + return randomBytes; + }; + } + // Node + : function () { + return require("crypto").randomBytes; + })(); function getCryptoRandomInt(min, max) { - const randomBuffer = new Uint32Array(1); - crypto.getRandomValues(randomBuffer); - const randomNumber = randomBuffer[0] / (0xffffffff + 1); - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(randomNumber * (max - min + 1)) + min; + // synchronous version of: https://github.com/joepie91/node-random-number-csprng + var range = max - min; + if (range >= Math.pow(2, 32)) + console.log("Warning! Range is too large."); + var tmpRange = range; + var bitsNeeded = 0; + var bytesNeeded = 0; + var mask = 1; + while (tmpRange > 0) { + if (bitsNeeded % 8 === 0) + bytesNeeded += 1; + bitsNeeded += 1; + mask = mask << 1 | 1; + tmpRange = tmpRange >>> 1; + } + var randomBytes = getRandomBytes(bytesNeeded); + var randomValue = 0; + for (var i = 0; i < bytesNeeded; i++) { + randomValue |= randomBytes[i] << 8 * i; + } + randomValue = randomValue & mask; + if (randomValue <= range) { + return min + randomValue; + } + else { + return getCryptoRandomInt(min, max); + } } exports.getCryptoRandomInt = getCryptoRandomInt; -function genSecret(length = 64) { - let secret = ""; - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - const charsLength = chars.length; - for ( let i = 0; i < length; i++ ) { +function genSecret(length) { + if (length === void 0) { length = 64; } + var secret = ""; + var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + var charsLength = chars.length; + for (var i = 0; i < length; i++) { secret += chars.charAt(getCryptoRandomInt(0, charsLength - 1)); } return secret; diff --git a/src/util.ts b/src/util.ts index a1f6f2594..633d933ea 100644 --- a/src/util.ts +++ b/src/util.ts @@ -114,13 +114,64 @@ export function getRandomInt(min: number, max: number) { return Math.floor(Math.random() * (max - min + 1)) + min; } -export function getCryptoRandomInt(min: number, max: number) { - const randomBuffer = new Uint32Array(1); - crypto.getRandomValues(randomBuffer); - const randomNumber = randomBuffer[0] / (0xffffffff + 1); - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(randomNumber * (max - min + 1)) + min; +/** + * Returns either the NodeJS crypto.randomBytes() function or its + * browser equivalent implemented via window.crypto.getRandomValues() + */ +let getRandomBytes = ( + (typeof window !== 'undefined' && window.crypto) + + // Browsers + ? function () { + return (numBytes: number) => { + let randomBytes = new Uint8Array(numBytes); + for (let i = 0; i < numBytes; i += 65536) { + window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536))); + } + return randomBytes; + }; + } + + // Node + : function() { + return require("crypto").randomBytes; + } +)(); + +export function getCryptoRandomInt(min: number, max: number):number { + + // synchronous version of: https://github.com/joepie91/node-random-number-csprng + + const range = max - min + if (range >= Math.pow(2, 32)) + console.log("Warning! Range is too large.") + + let tmpRange = range + let bitsNeeded = 0 + let bytesNeeded = 0 + let mask = 1 + + while (tmpRange > 0) { + if (bitsNeeded % 8 === 0) bytesNeeded += 1 + bitsNeeded += 1 + mask = mask << 1 | 1 + tmpRange = tmpRange >>> 1 + } + + const randomBytes = getRandomBytes(bytesNeeded) + let randomValue = 0 + + for (let i = 0; i < bytesNeeded; i++) { + randomValue |= randomBytes[i] << 8 * i + } + + randomValue = randomValue & mask; + + if (randomValue <= range) { + return min + randomValue + } else { + return getCryptoRandomInt(min, max) + } } export function genSecret(length = 64) {