-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathindex.js
136 lines (112 loc) · 4.03 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
'use strict';
var random = require('./lib/random').default;
var sets = require('./lib/character-sets');
var util = require('./lib/util');
Object.keys(sets).forEach(function (k) {
exports[k] = sets[k];
});
var defaultAmbiguousSets = [
'Il1|',
'O0'
];
function randomPassword(opts) {
var defaults = {
avoidAmbiguous: true,
characters: [
sets.lower,
{ characters: sets.upper, exactly: 1 },
{ characters: sets.symbols, exactly: 1 }
],
length: 12,
predicate: function () { return true },
random: random,
};
opts = util.assign({}, defaults, opts);
var characterRules = translateRules(opts);
if (!util.isInteger(opts.length)) {
throw new Error('length must be an integer');
}
if (opts.length < 1) {
throw new Error('length must be > 0');
}
if (opts.length < characterRules.length) {
throw new Error('length must be >= # of character sets passed');
}
if (characterRules.some(function (rule) { return !rule.characters })) {
throw new Error('No character set may be empty');
}
if (characterRules.length === 0) {
throw new Error('Must pass one or more character sets');
}
if (typeof opts.predicate !== 'function') {
throw new Error('predicate must be a function');
}
var minimumLength = characterRules
.map(function (rule) { return rule.exactly || 1 })
.reduce(function (l, r) { return l + r }, 0);
if (opts.length < minimumLength) {
throw new Error('length is too short for character set rules');
}
var allExactly = characterRules.every(function (rule) { return rule.exactly });
if (allExactly) {
var exactlyLength = characterRules.reduce(function (acc, r) { return acc + r.exactly }, 0);
if (exactlyLength !== opts.length) {
throw new Error('Must pass a set without exactly rule to generate the specified length');
}
}
var result;
do {
result = generatePassword(characterRules, opts.length, opts.random);
} while (!opts.predicate(result));
return result;
}
exports.randomPassword = randomPassword;
function generatePassword(characterRules, length, random) {
var requiredSetsWithRepeats = characterRules
.map(function (rule) { return rule.exactly ? util.repeat(rule.characters, rule.exactly) : [rule.characters] })
.reduce(function (l, r) { return l.concat(r) }); // flatten back to array of strings
var requiredChoices = requiredSetsWithRepeats
.map(function (characters) { return random.choose(characters) });
var fillCharcters = characterRules
.filter(function (rule) { return !rule.exactly })
.map(function (rule) { return rule.characters })
.join('');
var randomChoices = util.range(length - requiredChoices.length)
.map(function () { return random.choose(fillCharcters) });
var shuffled = random.shuffle(requiredChoices.concat(randomChoices));
return shuffled.join('');
}
function translateRules(opts) {
if (!opts.characters) {
return [];
}
var result = Array.isArray(opts.characters)
? opts.characters
: [opts.characters];
result = result.map(function (x) { return util.isString(x) ? { characters: x } : x });
var ambiguousSets = opts.avoidAmbiguous === true
? defaultAmbiguousSets
: (opts.avoidAmbiguous || []);
stripAmbiguous(result, ambiguousSets);
return result;
}
function stripAmbiguous(characterRules, ambiguousSets) {
var allCharacters = characterRules.map(function (rule) { return rule.characters }).join('');
var ambiguousCharacters = ambiguousSets
.filter(function (ambiguousSet) { return util.intersection(ambiguousSet, allCharacters).length > 1 })
.join('');
characterRules.forEach(function (rule) {
rule.characters = util.toArray(rule.characters)
.filter(function(ch) { return ambiguousCharacters.indexOf(ch) < 0 }).join('');
});
}
function randomString(opts) {
var defaults = {
characters: [sets.lower, sets.upper, sets.digits, sets.symbols],
length: 20
};
opts = util.assign({}, defaults, opts);
opts.avoidAmbiguous = false; // hard override
return randomPassword(opts);
}
exports.randomString = randomString;