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