Yang Guo | 4fd355c | 2019-09-19 08:59:03 | [diff] [blame] | 1 | 'use strict' |
| 2 | |
| 3 | function oldBrowser () { |
| 4 | throw new Error('secure random number generation not supported by this browser\nuse chrome, FireFox or Internet Explorer 11') |
| 5 | } |
| 6 | var safeBuffer = require('safe-buffer') |
| 7 | var randombytes = require('randombytes') |
| 8 | var Buffer = safeBuffer.Buffer |
| 9 | var kBufferMaxLength = safeBuffer.kMaxLength |
| 10 | var crypto = global.crypto || global.msCrypto |
| 11 | var kMaxUint32 = Math.pow(2, 32) - 1 |
| 12 | function assertOffset (offset, length) { |
| 13 | if (typeof offset !== 'number' || offset !== offset) { // eslint-disable-line no-self-compare |
| 14 | throw new TypeError('offset must be a number') |
| 15 | } |
| 16 | |
| 17 | if (offset > kMaxUint32 || offset < 0) { |
| 18 | throw new TypeError('offset must be a uint32') |
| 19 | } |
| 20 | |
| 21 | if (offset > kBufferMaxLength || offset > length) { |
| 22 | throw new RangeError('offset out of range') |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | function assertSize (size, offset, length) { |
| 27 | if (typeof size !== 'number' || size !== size) { // eslint-disable-line no-self-compare |
| 28 | throw new TypeError('size must be a number') |
| 29 | } |
| 30 | |
| 31 | if (size > kMaxUint32 || size < 0) { |
| 32 | throw new TypeError('size must be a uint32') |
| 33 | } |
| 34 | |
| 35 | if (size + offset > length || size > kBufferMaxLength) { |
| 36 | throw new RangeError('buffer too small') |
| 37 | } |
| 38 | } |
| 39 | if ((crypto && crypto.getRandomValues) || !process.browser) { |
| 40 | exports.randomFill = randomFill |
| 41 | exports.randomFillSync = randomFillSync |
| 42 | } else { |
| 43 | exports.randomFill = oldBrowser |
| 44 | exports.randomFillSync = oldBrowser |
| 45 | } |
| 46 | function randomFill (buf, offset, size, cb) { |
| 47 | if (!Buffer.isBuffer(buf) && !(buf instanceof global.Uint8Array)) { |
| 48 | throw new TypeError('"buf" argument must be a Buffer or Uint8Array') |
| 49 | } |
| 50 | |
| 51 | if (typeof offset === 'function') { |
| 52 | cb = offset |
| 53 | offset = 0 |
| 54 | size = buf.length |
| 55 | } else if (typeof size === 'function') { |
| 56 | cb = size |
| 57 | size = buf.length - offset |
| 58 | } else if (typeof cb !== 'function') { |
| 59 | throw new TypeError('"cb" argument must be a function') |
| 60 | } |
| 61 | assertOffset(offset, buf.length) |
| 62 | assertSize(size, offset, buf.length) |
| 63 | return actualFill(buf, offset, size, cb) |
| 64 | } |
| 65 | |
| 66 | function actualFill (buf, offset, size, cb) { |
| 67 | if (process.browser) { |
| 68 | var ourBuf = buf.buffer |
| 69 | var uint = new Uint8Array(ourBuf, offset, size) |
| 70 | crypto.getRandomValues(uint) |
| 71 | if (cb) { |
| 72 | process.nextTick(function () { |
| 73 | cb(null, buf) |
| 74 | }) |
| 75 | return |
| 76 | } |
| 77 | return buf |
| 78 | } |
| 79 | if (cb) { |
| 80 | randombytes(size, function (err, bytes) { |
| 81 | if (err) { |
| 82 | return cb(err) |
| 83 | } |
| 84 | bytes.copy(buf, offset) |
| 85 | cb(null, buf) |
| 86 | }) |
| 87 | return |
| 88 | } |
| 89 | var bytes = randombytes(size) |
| 90 | bytes.copy(buf, offset) |
| 91 | return buf |
| 92 | } |
| 93 | function randomFillSync (buf, offset, size) { |
| 94 | if (typeof offset === 'undefined') { |
| 95 | offset = 0 |
| 96 | } |
| 97 | if (!Buffer.isBuffer(buf) && !(buf instanceof global.Uint8Array)) { |
| 98 | throw new TypeError('"buf" argument must be a Buffer or Uint8Array') |
| 99 | } |
| 100 | |
| 101 | assertOffset(offset, buf.length) |
| 102 | |
| 103 | if (size === undefined) size = buf.length - offset |
| 104 | |
| 105 | assertSize(size, offset, buf.length) |
| 106 | |
| 107 | return actualFill(buf, offset, size) |
| 108 | } |