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

121 lines
3.7 KiB
JavaScript
Raw Normal View History

2017-01-31 07:50:28 +01:00
const kdbxweb = require('kdbxweb');
const phonetic = require('./phonetic');
2015-10-19 23:24:32 +02:00
2017-01-31 07:50:28 +01:00
const PasswordGenerator = {
2015-10-19 23:24:32 +02:00
charRanges: {
upper: 'ABCDEFGHJKLMNPQRSTUVWXYZ',
lower: 'abcdefghijkmnpqrstuvwxyz',
2015-10-20 19:17:15 +02:00
digits: '123456789',
2015-10-19 23:24:32 +02:00
special: '!@#$%^&*_+-=,./?;:`"~\'\\',
2015-10-20 19:17:15 +02:00
brackets: '(){}[]<>',
2015-10-19 23:24:32 +02:00
high: '¡¢£¤¥¦§©ª«¬®¯°±²³´µ¶¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ',
2015-10-20 19:17:15 +02:00
ambiguous: 'O0oIl'
2015-10-19 23:24:32 +02:00
},
2016-02-15 22:06:11 +01:00
2015-10-19 23:24:32 +02:00
generate: function(opts) {
if (!opts || typeof opts.length !== 'number' || opts.length < 0) {
return '';
}
2016-02-15 22:06:11 +01:00
switch (opts.name) {
case 'Pronounceable':
return this.generatePronounceable(opts);
case 'Hash128':
return this.generateHash(32);
case 'Hash256':
return this.generateHash(64);
case 'Mac':
return this.generateMac();
}
2017-01-31 07:50:28 +01:00
const ranges = Object.keys(this.charRanges)
2016-07-17 13:30:38 +02:00
.filter(r => opts[r])
2019-08-16 23:05:39 +02:00
.map(function(r) {
return this.charRanges[r];
}, this);
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 '';
}
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 range = ranges[i % ranges.length];
const rand = Math.round(Math.random() * 1000) + randomBytes[i];
2015-10-20 19:17:15 +02:00
chars.push(range[rand % range.length]);
2015-10-19 23:24:32 +02:00
}
2015-10-20 19:17:15 +02:00
return _.shuffle(chars).join('');
},
2016-02-15 22:06:11 +01:00
generateMac: function() {
2017-01-31 07:50:28 +01:00
const segmentsCount = 6;
const randomBytes = kdbxweb.Random.getBytes(segmentsCount);
let result = '';
for (let i = 0; i < segmentsCount; i++) {
let segment = randomBytes[i].toString(16).toUpperCase();
2016-02-15 22:06:11 +01:00
if (segment.length < 2) {
segment = '0' + segment;
}
result += (result ? '-' : '') + segment;
}
return result;
},
generateHash: function(length) {
2017-01-31 07:50:28 +01:00
const randomBytes = kdbxweb.Random.getBytes(length);
let result = '';
for (let i = 0; i < length; i++) {
2016-02-15 22:06:11 +01:00
result += randomBytes[i].toString(16)[0];
}
return result;
},
generatePronounceable: function(opts) {
2017-01-31 07:50:28 +01:00
const pass = phonetic.generate({
length: opts.length,
seed: this.generateHash(1024)
});
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);
},
deriveOpts: function(password) {
2017-01-31 07:50:28 +01:00
const opts = {};
let length = 0;
2016-02-15 22:06:11 +01:00
if (password) {
2017-01-31 07:50:28 +01:00
const charRanges = this.charRanges;
2016-07-17 13:30:38 +02:00
password.forEachChar(ch => {
2016-02-15 22:06:11 +01:00
length++;
ch = String.fromCharCode(ch);
2016-07-17 13:30:38 +02:00
_.forEach(charRanges, (chars, range) => {
2016-02-15 22:06:11 +01:00
if (chars.indexOf(ch) >= 0) {
opts[range] = true;
}
});
});
}
opts.length = length;
return opts;
},
present: function(length) {
return new Array(length + 1).join('•');
2015-10-19 23:24:32 +02:00
}
};
module.exports = PasswordGenerator;