You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
2.3 KiB

7 years ago
  1. /*!
  2. * base64id v0.1.0
  3. */
  4. /**
  5. * Module dependencies
  6. */
  7. var crypto = require('crypto');
  8. /**
  9. * Constructor
  10. */
  11. var Base64Id = function() { };
  12. /**
  13. * Get random bytes
  14. *
  15. * Uses a buffer if available, falls back to crypto.randomBytes
  16. */
  17. Base64Id.prototype.getRandomBytes = function(bytes) {
  18. var BUFFER_SIZE = 4096
  19. var self = this;
  20. bytes = bytes || 12;
  21. if (bytes > BUFFER_SIZE) {
  22. return crypto.randomBytes(bytes);
  23. }
  24. var bytesInBuffer = parseInt(BUFFER_SIZE/bytes);
  25. var threshold = parseInt(bytesInBuffer*0.85);
  26. if (!threshold) {
  27. return crypto.randomBytes(bytes);
  28. }
  29. if (this.bytesBufferIndex == null) {
  30. this.bytesBufferIndex = -1;
  31. }
  32. if (this.bytesBufferIndex == bytesInBuffer) {
  33. this.bytesBuffer = null;
  34. this.bytesBufferIndex = -1;
  35. }
  36. // No buffered bytes available or index above threshold
  37. if (this.bytesBufferIndex == -1 || this.bytesBufferIndex > threshold) {
  38. if (!this.isGeneratingBytes) {
  39. this.isGeneratingBytes = true;
  40. crypto.randomBytes(BUFFER_SIZE, function(err, bytes) {
  41. self.bytesBuffer = bytes;
  42. self.bytesBufferIndex = 0;
  43. self.isGeneratingBytes = false;
  44. });
  45. }
  46. // Fall back to sync call when no buffered bytes are available
  47. if (this.bytesBufferIndex == -1) {
  48. return crypto.randomBytes(bytes);
  49. }
  50. }
  51. var result = this.bytesBuffer.slice(bytes*this.bytesBufferIndex, bytes*(this.bytesBufferIndex+1));
  52. this.bytesBufferIndex++;
  53. return result;
  54. }
  55. /**
  56. * Generates a base64 id
  57. *
  58. * (Original version from socket.io <http://socket.io>)
  59. */
  60. Base64Id.prototype.generateId = function () {
  61. var rand = new Buffer(15); // multiple of 3 for base64
  62. if (!rand.writeInt32BE) {
  63. return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString()
  64. + Math.abs(Math.random() * Math.random() * Date.now() | 0).toString();
  65. }
  66. this.sequenceNumber = (this.sequenceNumber + 1) | 0;
  67. rand.writeInt32BE(this.sequenceNumber, 11);
  68. if (crypto.randomBytes) {
  69. this.getRandomBytes(12).copy(rand);
  70. } else {
  71. // not secure for node 0.4
  72. [0, 4, 8].forEach(function(i) {
  73. rand.writeInt32BE(Math.random() * Math.pow(2, 32) | 0, i);
  74. });
  75. }
  76. return rand.toString('base64').replace(/\//g, '_').replace(/\+/g, '-');
  77. };
  78. /**
  79. * Export
  80. */
  81. exports = module.exports = new Base64Id();