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