node-red-contrib-password-g.../lib/PasswordGenerator.ts

61 lines
1.6 KiB
TypeScript
Raw Permalink Normal View History

2021-07-09 03:49:18 +02:00
import * as crypto from "crypto";
import { promisify } from "util";
const AsciiRange = {
/** space */
min: 32,
/** childe mark ~ */
max: 126,
}
2021-07-11 09:03:32 +02:00
const optRegexes = {
space: " ",
special: "!\"#\\$%&'\\(\\)\\*\\+,-./:;<=>\\?@\\[\\\\\\]\\^_`\\{|\\}~",
number: "\\d",
};
export interface DisableOptions {
space?: boolean;
special?: boolean;
number?: boolean;
}
export async function generatePassword(length: number, disableOpts?: DisableOptions): Promise<string> {
if (length < 5) {
throw new Error("Password length must be longer than 5.");
}
2021-07-09 03:49:18 +02:00
let result = "";
2021-07-11 09:03:32 +02:00
const regex = createRegex(disableOpts)
2021-07-09 03:49:18 +02:00
while (true) {
2021-07-11 06:16:21 +02:00
const bytes = await promisify(crypto.randomBytes)(length * 2);
2021-07-09 03:49:18 +02:00
const byteArray = Array.from(bytes);
const filtered = byteArray.filter(isInAsciiRange);
result += String.fromCharCode(...filtered);
2021-07-11 09:03:32 +02:00
if (regex) {
result = result.replace(regex, "");
}
2021-07-11 06:16:21 +02:00
if (result.length >= length) {
result = result.slice(0, length);
2021-07-09 03:49:18 +02:00
break;
}
}
return result;
}
function isInAsciiRange(value: number) {
return AsciiRange.min <= value && value <= AsciiRange.max;
2021-07-11 09:03:32 +02:00
}
function createRegex(disableOpts?: DisableOptions): RegExp | undefined {
if (!disableOpts) {
return undefined;
}
let reg = "";
if (disableOpts?.space) { reg += optRegexes.space };
if (disableOpts?.special) { reg += optRegexes.special };
if (disableOpts?.number) { reg += optRegexes.number };
return new RegExp(`[${reg}]`, "g");
2021-07-09 03:49:18 +02:00
}