mirror of https://github.com/keeweb/keeweb.git
103 lines
3.1 KiB
JavaScript
103 lines
3.1 KiB
JavaScript
import kdbxweb from 'kdbxweb';
|
|
import { phonetic } from 'util/generators/phonetic';
|
|
|
|
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
|
|
};
|
|
|
|
const PasswordGenerator = {
|
|
generate(opts) {
|
|
if (!opts || typeof opts.length !== 'number' || opts.length < 0) {
|
|
return '';
|
|
}
|
|
if (opts.name === 'Pronounceable') {
|
|
return this.generatePronounceable(opts);
|
|
}
|
|
const ranges = Object.keys(CharRanges)
|
|
.filter((r) => opts[r])
|
|
.map((r) => CharRanges[r]);
|
|
if (opts.include && opts.include.length) {
|
|
ranges.push(opts.include);
|
|
}
|
|
if (!ranges.length) {
|
|
return '';
|
|
}
|
|
const rangesByPatternChar = {
|
|
...DefaultCharRangesByPattern,
|
|
'X': ranges.join(''),
|
|
'I': opts.include || ''
|
|
};
|
|
const pattern = opts.pattern || 'X';
|
|
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];
|
|
const patternChar = pattern[i % pattern.length];
|
|
const range = rangesByPatternChar[patternChar];
|
|
const char = range ? range[rand % range.length] : patternChar;
|
|
chars.push(char);
|
|
}
|
|
return chars.join('');
|
|
},
|
|
|
|
generatePronounceable(opts) {
|
|
const pass = phonetic.generate({
|
|
length: opts.length
|
|
});
|
|
let result = '';
|
|
const upper = [];
|
|
let i;
|
|
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++) {
|
|
let ch = pass[i];
|
|
if (upper.indexOf(i) >= 0) {
|
|
ch = ch.toUpperCase();
|
|
}
|
|
result += ch;
|
|
}
|
|
return result.substr(0, opts.length);
|
|
},
|
|
|
|
deriveOpts(password) {
|
|
const opts = {};
|
|
let length = 0;
|
|
if (password) {
|
|
const charRanges = CharRanges;
|
|
password.forEachChar((ch) => {
|
|
length++;
|
|
ch = String.fromCharCode(ch);
|
|
for (const [range, chars] of Object.entries(charRanges)) {
|
|
if (chars.indexOf(ch) >= 0) {
|
|
opts[range] = true;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
opts.length = length;
|
|
return opts;
|
|
}
|
|
};
|
|
|
|
export { PasswordGenerator, CharRanges };
|