UNPKG

@hixbe/otp-pass-kit

Version:

A secure, cryptographically-strong OTP and password generator for Node.js with CLI support. Generate customizable one-time passwords and strong passwords with TypeScript support.

189 lines (183 loc) 5.99 kB
#!/usr/bin/env node "use strict"; // src/functions.ts var import_crypto = require("crypto"); var DIGITS = "0123456789"; var LOWERCASE_ALPHABETS = "abcdefghijklmnopqrstuvwxyz"; var UPPERCASE_ALPHABETS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; var SPECIAL_CHARS = "!@#$%^&*()_+-=[]{}|;:,.<>?"; function validateLength(length) { if (!Number.isInteger(length) || length <= 0) { throw new Error("Length must be a positive integer"); } if (length > 1e3) { throw new Error("Length cannot exceed 1000 characters"); } } function buildCharacterPool(options) { let pool = ""; if (options.digits) pool += DIGITS; if (options.lowerCaseAlphabets) pool += LOWERCASE_ALPHABETS; if (options.upperCaseAlphabets) pool += UPPERCASE_ALPHABETS; if (options.specialChars) pool += SPECIAL_CHARS; if (!pool) { throw new Error("At least one character set must be enabled"); } return pool; } function generateRandomString(length, characterPool, options) { const chars = new Array(length); if (options?.ensureEachType && length >= 4) { const sets = []; if (options.digits) sets.push(DIGITS); if (options.lowerCaseAlphabets) sets.push(LOWERCASE_ALPHABETS); if (options.upperCaseAlphabets) sets.push(UPPERCASE_ALPHABETS); if (options.specialChars) sets.push(SPECIAL_CHARS); for (let i = 0; i < sets.length && i < length; i++) { const set = sets[i]; chars[i] = set[(0, import_crypto.randomInt)(0, set.length)]; } for (let i = sets.length; i < length; i++) { const randomIndex = (0, import_crypto.randomInt)(0, characterPool.length); chars[i] = characterPool[randomIndex]; } for (let i = length - 1; i > 0; i--) { const j = (0, import_crypto.randomInt)(0, i + 1); [chars[i], chars[j]] = [chars[j], chars[i]]; } } else { for (let i = 0; i < length; i++) { const randomIndex = (0, import_crypto.randomInt)(0, characterPool.length); chars[i] = characterPool[randomIndex]; } } return chars.join(""); } function generateOtp(length = 6, options) { validateLength(length); const defaultOptions = { lowerCaseAlphabets: false, upperCaseAlphabets: false, specialChars: false, digits: true, ...options }; const characterPool = buildCharacterPool(defaultOptions); return generateRandomString(length, characterPool, defaultOptions); } function generatePass(length = 8, options) { validateLength(length); const defaultOptions = { lowerCaseAlphabets: true, upperCaseAlphabets: true, specialChars: true, digits: true, ...options }; const characterPool = buildCharacterPool(defaultOptions); return generateRandomString(length, characterPool, defaultOptions); } // src/cli.ts function parseArgs() { const args = process.argv.slice(2); if (args.includes("-h") || args.includes("--help")) { console.log(` Usage: otp-pass-kit <command> [options] Commands: otp Generate an OTP (One-Time Password) pass Generate a password Options: -l, --length <number> Length of the generated string (default: 6 for otp, 8 for pass) -d, --digits Include digits (default: true for otp, true for pass) --no-digits Exclude digits -u, --uppercase Include uppercase letters (default: false for otp, true for pass) --no-uppercase Exclude uppercase letters -w, --lowercase Include lowercase letters (default: false for otp, true for pass) --no-lowercase Exclude lowercase letters -s, --special Include special characters (default: false for otp, true for pass) --no-special Exclude special characters -e, --ensure-each-type Ensure at least one character from each enabled set -h, --help Show this help message Examples: otp-pass-kit otp otp-pass-kit otp -l 8 -u -d otp-pass-kit pass otp-pass-kit pass -l 12 --ensure-each-type otp-pass-kit pass -l 10 -u -w -d --no-special `); process.exit(0); } const command = args[0]; if (!command || command !== "otp" && command !== "pass") { console.error("Error: Invalid command. Use --help for usage information."); process.exit(1); } const options = {}; let length = command === "otp" ? 6 : 8; for (let i = 1; i < args.length; i++) { const arg = args[i]; switch (arg) { case "-l": case "--length": length = parseInt(args[++i]); if (isNaN(length) || length <= 0) { console.error("Error: Length must be a positive integer"); process.exit(1); } break; case "-d": case "--digits": options.digits = true; break; case "--no-digits": options.digits = false; break; case "-u": case "--uppercase": options.upperCaseAlphabets = true; break; case "--no-uppercase": options.upperCaseAlphabets = false; break; case "-w": case "--lowercase": options.lowerCaseAlphabets = true; break; case "--no-lowercase": options.lowerCaseAlphabets = false; break; case "-s": case "--special": options.specialChars = true; break; case "--no-special": options.specialChars = false; break; case "-e": case "--ensure-each-type": options.ensureEachType = true; break; default: console.error(`Unknown option: ${arg}`); console.log("Use --help for usage information"); process.exit(1); } } return { command, length, options }; } function main() { try { const { command, length, options } = parseArgs(); let result; if (command === "otp") { result = generateOtp(length, options); } else { result = generatePass(length, options); } console.log(result); } catch (error) { console.error(`Error: ${error instanceof Error ? error.message : "Unknown error"}`); process.exit(1); } } main();