bcrypt-gen
Version:
bcrypt-gen is a command-line tool designed to generate bcrypt hashes conveniently and securely. It provides an easy-to-use interface for hashing passwords directly from the terminal, ensuring enhanced security for your applications.
221 lines (209 loc) • 7.76 kB
JavaScript
#!/usr/bin/env node
const bcrypt = require('bcrypt');
const yargs = require('yargs');
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
async function generateHash(password, saltRounds = 10) {
try {
const salt = await bcrypt.genSalt(saltRounds);
return await bcrypt.hash(password, salt);
} catch (error) {
console.error("Error generating the hash:", error);
}
}
async function verifyHash(hash, password) {
try {
// Verifica se o hash tem o formato básico de um hash Bcrypt
if (!hash.startsWith("$2b$") && !hash.startsWith("$2a$") && !hash.startsWith("$2y$")) {
console.error("Invalid hash format. Please make sure the hash is correct.");
return false;
}
return await bcrypt.compare(password, hash);
} catch (error) {
console.error("Error verifying the hash:", error);
return false;
}
}
// Interactive mode function
function runInteractiveMode(only = false) {
rl.question('Enter the password to generate the hash: ', (password) => {
rl.question('Enter the number of salt rounds (or press Enter for default 10): ', (saltInput) => {
const saltRounds = parseInt(saltInput, 10) || 10;
generateHash(password, saltRounds).then(hash => {
if (hash) {
if (only) {
console.log(hash);
} else {
console.log("Generated hash:", hash);
console.log("Tip: use -h to see help.");
}
}
rl.close();
}).catch(error => {
console.error("Error:", error);
rl.close();
});
});
});
}
// Interactive verification mode function
function runInteractiveVerifyMode() {
rl.question('Enter the bcrypt hash to verify: ', (hash) => {
rl.question('Enter the password to verify: ', (password) => {
verifyHash(hash, password).then(isMatch => {
if (isMatch) {
console.log(" ✅ Success - Password matches the hash.");
} else {
console.error("❌ Error - Password does not match the hash.");
}
rl.close();
}).catch(error => {
console.error("Error:", error);
rl.close();
});
});
});
}
// Only execute CLI when run directly
if (require.main === module) {
// Configure yargs
const rawArgs = process.argv.slice(2);
const argv = yargs
.usage('Usage: $0 [options]')
.version('1.1.1')
.option('h', {
alias: 'help',
describe: 'Show this help message',
type: 'boolean'
})
.option('i', {
alias: 'interactive',
describe: 'Interactive mode with questions for password and rounds',
type: 'boolean'
})
.option('v', {
alias: 'verify',
describe: 'Verify if the password matches the given hash',
type: 'boolean'
})
.option('interactive-verify', {
alias: 'iv',
describe: 'Interactive mode with questions for hash and password verification',
type: 'boolean'
})
.option('c', {
alias: 'custom',
describe: 'Generate hash for the given password with custom saltRounds',
type: 'boolean'
})
.option('p', {
alias: 'password',
describe: 'Generate hash for the given password with default saltRounds (10)',
type: 'boolean'
})
.option('hash', {
describe: 'Hash to verify (used with -v)',
type: 'string'
})
.option('pwd', {
describe: 'Password to hash or verify',
type: 'string'
})
.option('rounds', {
describe: 'Number of salt rounds (used with -c)',
type: 'number'
})
.option('o', {
alias: 'only',
describe: 'Print only the generated hash (no label/tips)',
type: 'boolean'
})
.example('$0 -i', 'Run in interactive mode')
.example('$0 -iv', 'Run in interactive verification mode')
.example('$0 -v --hash \'$2b$10$...\' --pwd "mypassword"', 'Verify if password matches hash')
.example('$0 -c --pwd "mypassword" --rounds 12', 'Generate hash with custom salt rounds')
.example('$0 -p --pwd "mypassword" -o', 'Generate hash with default rounds and print only the hash')
.epilogue('Use single quotes around bcrypt hashes in shell commands.')
.help('h')
.argv;
// Process commands based on yargs arguments
if (argv.interactiveVerify || rawArgs.includes('-iv')) {
// Interactive verify mode
runInteractiveVerifyMode();
} else if (argv.v) {
// Verify mode
const hash = argv.hash;
const password = argv.pwd;
if (!hash || !password) {
console.error("Error: You must provide a hash and a password with the -v option.");
console.log("Use -h for help.");
rl.close();
} else {
verifyHash(hash, password).then(isMatch => {
if (isMatch) {
console.log(" ✅ Success - Password matches the hash.");
} else {
console.error("❌ Error - Password does not match the hash.");
}
rl.close();
}).catch(error => {
console.error("Error:", error);
rl.close();
});
}
} else if (argv.c) {
// Custom salt rounds mode
const password = argv.pwd;
const saltRounds = argv.rounds;
if (!password || isNaN(saltRounds)) {
console.error("Error: You must provide a password and valid saltRounds with the -c option.");
console.log("Use -h for help.");
rl.close();
} else {
generateHash(password, saltRounds).then(hash => {
if (hash) {
if (argv.only) {
console.log(hash);
} else {
console.log("Generated hash:", hash);
console.log("Tip: use -h to see help.");
}
}
rl.close();
}).catch(error => {
console.error("Error:", error);
rl.close();
});
}
} else if (argv.p) {
// Default salt rounds mode
const password = argv.pwd;
if (!password) {
console.error("Error: You must provide a password with the -p option.");
console.log("Use -h for help.");
rl.close();
} else {
generateHash(password).then(hash => {
if (hash) {
if (argv.only) {
console.log(hash);
} else {
console.log("Generated hash:", hash);
console.log("Tip: use -h to see help.");
}
}
rl.close();
}).catch(error => {
console.error("Error:", error);
rl.close();
});
}
} else if (argv.i || Object.keys(argv).length <= 2) {
// Interactive mode (either explicitly requested or default behavior)
runInteractiveMode(argv.only);
}
}
module.exports = { generateHash, verifyHash };