index.js
1 /*! 2 * random-bytes 3 * Copyright(c) 2016 Douglas Christopher Wilson 4 * MIT Licensed 5 */ 6 7 'use strict' 8 9 /** 10 * Module dependencies. 11 * @private 12 */ 13 14 var crypto = require('crypto') 15 16 /** 17 * Module variables. 18 * @private 19 */ 20 21 var generateAttempts = crypto.randomBytes === crypto.pseudoRandomBytes ? 1 : 3 22 23 /** 24 * Module exports. 25 * @public 26 */ 27 28 module.exports = randomBytes 29 module.exports.sync = randomBytesSync 30 31 /** 32 * Generates strong pseudo-random bytes. 33 * 34 * @param {number} size 35 * @param {function} [callback] 36 * @return {Promise} 37 * @public 38 */ 39 40 function randomBytes(size, callback) { 41 // validate callback is a function, if provided 42 if (callback !== undefined && typeof callback !== 'function') { 43 throw new TypeError('argument callback must be a function') 44 } 45 46 // require the callback without promises 47 if (!callback && !global.Promise) { 48 throw new TypeError('argument callback is required') 49 } 50 51 if (callback) { 52 // classic callback style 53 return generateRandomBytes(size, generateAttempts, callback) 54 } 55 56 return new Promise(function executor(resolve, reject) { 57 generateRandomBytes(size, generateAttempts, function onRandomBytes(err, str) { 58 if (err) return reject(err) 59 resolve(str) 60 }) 61 }) 62 } 63 64 /** 65 * Generates strong pseudo-random bytes sync. 66 * 67 * @param {number} size 68 * @return {Buffer} 69 * @public 70 */ 71 72 function randomBytesSync(size) { 73 var err = null 74 75 for (var i = 0; i < generateAttempts; i++) { 76 try { 77 return crypto.randomBytes(size) 78 } catch (e) { 79 err = e 80 } 81 } 82 83 throw err 84 } 85 86 /** 87 * Generates strong pseudo-random bytes. 88 * 89 * @param {number} size 90 * @param {number} attempts 91 * @param {function} callback 92 * @private 93 */ 94 95 function generateRandomBytes(size, attempts, callback) { 96 crypto.randomBytes(size, function onRandomBytes(err, buf) { 97 if (!err) return callback(null, buf) 98 if (!--attempts) return callback(err) 99 setTimeout(generateRandomBytes.bind(null, size, attempts, callback), 10) 100 }) 101 }