Skip to content

Instantly share code, notes, and snippets.

@intrnl
Created March 10, 2022 07:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save intrnl/00d49a0c9e7306d9f17774bd428cc358 to your computer and use it in GitHub Desktop.
Save intrnl/00d49a0c9e7306d9f17774bd428cc358 to your computer and use it in GitHub Desktop.
Dashlane's random password generator
/**
* @fileoverview
* Dashlane's password generator
* https://www.dashlane.com/features/password-generator
*/
/**
* Generates a password
* @param {PasswordGeneratorOptions} options
* @returns {string}
*/
function generate (options) {
const { length, digits, letters, symbols, avoidAmbiguous } = options;
if (length < 4) {
throw new Error('The length of password cannot be below 4 chars');
}
if (!digits && !letters && !symbols) {
throw new Error('You need to have atleast one kind of char selected');
}
let result = generateWithMandatoryChars({
digits,
letters,
symbols,
avoidAmbiguous,
});
const charset = generateAllPossibleChars({
digits,
letters,
symbols,
avoidAmbiguous,
});
for (; result.length < length;) {
result += getRandomCharFrom(charset);
}
return shuffle(result);
}
/**
* @typedef {object} PasswordGeneratorOptions
* @property {boolean} digits Include numerical digits
* @property {boolean} letters Include alphabetical letters
* @property {boolean} symbols Include symbols
* @property {boolean} avoidAmbiguous Avoid ambiguous characters
*/
/**
* @param {boolean} avoidAmbiguous
* @returns {string}
*/
function getNumerals (avoidAmbiguous) {
return avoidAmbiguous ? '3456789' : '1234567890';
}
/**
* @param {boolean} avoidAmbiguous
* @returns {string}
*/
function getAlphaLower (avoidAmbiguous) {
return avoidAmbiguous ? 'abcdefghijkmnopqrstxyz' : 'abcdefghijklmnopqrstuvwxyz';
}
/**
* @param {boolean} avoidAmbiguous
* @returns {string}
*/
function getAlphaUpper (avoidAmbiguous) {
return avoidAmbiguous ? 'ABCDEFGHJKLMNPQRSTXY' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
}
/**
* @returns {string}
*/
function getSymbols () {
return '&@$!#?';
}
/**
* @param {GeneratorOptions} options
* @returns {string}
*/
function generateWithMandatoryChars (options) {
const { avoidAmbiguous } = options;
let result = '';
if (options.digits) {
result += getRandomCharFrom(getNumerals(avoidAmbiguous));
}
if (options.letters) {
result += getRandomCharFrom(getAlphaLower(avoidAmbiguous));
result += getRandomCharFrom(getAlphaUpper(avoidAmbiguous));
}
if (options.symbols) {
result += getRandomCharFrom(getSymbols());
}
return result;
}
/**
* @param {GeneratorOptions} options
* @returns {string}
*/
function getAllPossibleChars (options) {
const { avoidAmbiguous } = options;
let charset = '';
if (options.digits) {
charset += getNumerals(avoidAmbiguous);
}
if (options.letters) {
charset += getAlphaLower(avoidAmbiguous);
charset += getAlphaUpper(avoidAmbiguous);
}
if (options.symbols) {
charset += getSymbols();
}
return charset;
}
/**
* @typedef {object} GeneratorOptions
* @property {boolean} digits Include numerical digits
* @property {boolean} letters Include alphabetical letters
* @property {boolean} symbols Include symbols
* @property {boolean} avoidAmbiguous Avoid ambiguous characters
*/
/**
* @param {string} str
* @returns {string}
*/
function shuffle (str) {
const arr = str.split('');
for (let idx = arr.length - 1; idx > 0; idx--) {
const rand = getCryptoStrongRandomInteger(idx + 1);
const tmp = arr[rand];
arr[rand] = arr[idx];
arr[idx] = tmp;
}
return arr.join('');
}
/**
* @param {string} charset
* @returns {string}
*/
function getRandomCharFrom (charset) {
return charset.charAt(getCryptoStrongRandomInteger(charset.length));
}
/**
* @param {number} max
* @returns {number}
*/
function getCryptoStrongRandomInteger (max) {
// there's a function that retrieves the Web Crypto API
// which defers to importing a polyfill of Node's crypto module,
// that requires the Web Crypto API.
// but we're skipping all of that here.
const buf = new Uint16Array(1);
crypto.getRandomValues(buf);
return buf[0] % max;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment