UNPKG

2.78 kBJavaScriptView Raw
1(function () {
2 "use strict";
3
4 var crypto = require('crypto'),
5 assert = require('assert'),
6 _ = require('lodash');
7
8 var numeric = '0123456789';
9 var alphaLower = 'abcdefghijklmnopqrstuvwxyz';
10 var alphaUpper = alphaLower.toUpperCase();
11 var alphaNumeric = numeric + alphaLower + alphaUpper;
12
13 var defaults = {
14 "chars": 'default',
15 "source": 'default'
16 };
17
18 function validateTokenChars(tokenChars) {
19 assert(tokenChars);
20 assert(_.isString(tokenChars));
21 assert(tokenChars.length > 0);
22 assert(tokenChars.length < 256);
23 }
24
25 function buildGenerator(options) {
26 assert(!options || _.isObject(options));
27 options = _.defaults(options || {}, defaults);
28
29 // Allowed characters
30 switch( options.chars ) {
31 case 'default':
32 options.chars = alphaNumeric;
33 break;
34 case 'a-z':
35 case 'alpha':
36 options.chars = alphaLower;
37 break;
38 case 'A-Z':
39 case 'ALPHA':
40 options.chars = alphaUpper;
41 break;
42 case '0-9':
43 case 'numeric':
44 options.chars = numeric;
45 break;
46 case 'base32':
47 options.chars = alphaUpper + "234567";
48 break;
49 default:
50 // use the characters as is
51 }
52 validateTokenChars(options.chars);
53
54 // Source of randomness:
55 switch( options.source ) {
56 case 'default':
57 options.source = function(size, cb) {
58 return crypto.pseudoRandomBytes(size, !cb ? null : function (buf){
59 return cb(null, buf);
60 });
61 };
62 break;
63 case 'crypto':
64 options.source = crypto.randomBytes;
65 break;
66 case 'math':
67 options.source = function(size, cb) {
68 var buf = new Buffer(size);
69 for(var i=0;i<size;i++) {
70 buf.writeUInt8(Math.floor(256 * Math.random()), i);
71 }
72 if( cb ) {
73 cb(null, buf);
74 } else {
75 return buf;
76 }
77 };
78 break;
79 default:
80 assert(_.isFunction(options.source));
81 }
82
83 return {
84 "generate": function(size, chars) {
85 if( chars ) {
86 validateTokenChars(chars);
87 } else {
88 chars = options.chars;
89 }
90 var max = Math.floor(256 / chars.length) * chars.length;
91 var ret = "";
92 while( ret.length < size ) {
93 var buf = options.source(size - ret.length);
94 for(var i=0;i<buf.length;i++) {
95 var x = buf.readUInt8(i);
96 if( x < max ) {
97 ret += chars[x % chars.length];
98 }
99 }
100 }
101 return ret;
102 }
103 };
104 }
105
106 var defaultGenerator = buildGenerator();
107
108 module.exports = {
109 "generator": buildGenerator,
110 "generate": defaultGenerator.generate
111 };
112})();