keeweb/app/scripts/util/generators/password-generator.js

103 lines
3.1 KiB
JavaScript
Raw Normal View History

2019-09-15 14:16:32 +02:00
import kdbxweb from 'kdbxweb';
import { phonetic } from 'util/generators/phonetic';
2015-10-19 23:24:32 +02:00
2020-03-15 11:20:01 +01:00
const CharRanges = {
upper: 'ABCDEFGHJKLMNPQRSTUVWXYZ',
lower: 'abcdefghijkmnpqrstuvwxyz',
digits: '123456789',
special: '!@#$%^&*_+-=,./?;:`"~\'\\',
brackets: '(){}[]<>',
high:
'¡¢£¤¥¦§©ª«¬®¯°±²³´µ¶¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ',
ambiguous: 'O0oIl'
};
const DefaultCharRangesByPattern = {
'A': CharRanges.upper,
'a': CharRanges.lower,
'1': CharRanges.digits,
'*': CharRanges.special,
'[': CharRanges.brackets,
'Ä': CharRanges.high,
'0': CharRanges.ambiguous
};
2016-02-15 22:06:11 +01:00
2020-03-15 11:20:01 +01:00
const PasswordGenerator = {
2019-08-18 10:17:09 +02:00
generate(opts) {
2015-10-19 23:24:32 +02:00
if (!opts || typeof opts.length !== 'number' || opts.length < 0) {
return '';
}
2020-03-15 11:20:01 +01:00
if (opts.name === 'Pronounceable') {
return this.generatePronounceable(opts);
2016-02-15 22:06:11 +01:00
}
2020-03-15 11:20:01 +01:00
const ranges = Object.keys(CharRanges)
2020-06-01 16:53:51 +02:00
.filter((r) => opts[r])
.map((r) => CharRanges[r]);
2016-08-14 18:18:51 +02:00
if (opts.include && opts.include.length) {
ranges.push(opts.include);
}
2015-10-19 23:24:32 +02:00
if (!ranges.length) {
return '';
}
2020-03-15 11:20:01 +01:00
const rangesByPatternChar = {
...DefaultCharRangesByPattern,
'X': ranges.join(''),
'I': opts.include || ''
};
const pattern = opts.pattern || 'X';
2017-01-31 07:50:28 +01:00
const randomBytes = kdbxweb.Random.getBytes(opts.length);
const chars = [];
for (let i = 0; i < opts.length; i++) {
const rand = Math.round(Math.random() * 1000) + randomBytes[i];
2020-03-15 11:20:01 +01:00
const patternChar = pattern[i % pattern.length];
const range = rangesByPatternChar[patternChar];
const char = range ? range[rand % range.length] : patternChar;
chars.push(char);
2015-10-19 23:24:32 +02:00
}
return chars.join('');
},
2016-02-15 22:06:11 +01:00
2019-08-18 10:17:09 +02:00
generatePronounceable(opts) {
2017-01-31 07:50:28 +01:00
const pass = phonetic.generate({
2020-03-15 11:20:01 +01:00
length: opts.length
});
2017-01-31 07:50:28 +01:00
let result = '';
const upper = [];
let i;
2016-02-15 22:06:11 +01:00
if (opts.upper) {
for (i = 0; i < pass.length; i += 8) {
upper.push(Math.floor(Math.random() * opts.length));
}
}
for (i = 0; i < pass.length; i++) {
2017-01-31 07:50:28 +01:00
let ch = pass[i];
2016-02-15 22:06:11 +01:00
if (upper.indexOf(i) >= 0) {
ch = ch.toUpperCase();
}
result += ch;
}
return result.substr(0, opts.length);
},
2019-08-18 10:17:09 +02:00
deriveOpts(password) {
2017-01-31 07:50:28 +01:00
const opts = {};
let length = 0;
2016-02-15 22:06:11 +01:00
if (password) {
2020-03-15 11:20:01 +01:00
const charRanges = CharRanges;
2020-06-01 16:53:51 +02:00
password.forEachChar((ch) => {
2016-02-15 22:06:11 +01:00
length++;
ch = String.fromCharCode(ch);
2019-09-17 22:17:40 +02:00
for (const [range, chars] of Object.entries(charRanges)) {
2016-02-15 22:06:11 +01:00
if (chars.indexOf(ch) >= 0) {
opts[range] = true;
}
2019-09-17 22:17:40 +02:00
}
2016-02-15 22:06:11 +01:00
});
}
opts.length = length;
return opts;
2015-10-19 23:24:32 +02:00
}
};
2020-03-15 11:20:01 +01:00
export { PasswordGenerator, CharRanges };