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();
|
---|