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 |
|
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 |
|
51 | }
|
52 | validateTokenChars(options.chars);
|
53 |
|
54 |
|
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 | })();
|