vault-nacl
Version:
A symmetric encrypted vault using nacl elliptic curves
195 lines (177 loc) • 5.25 kB
JavaScript
#!/usr/bin/env node
/* eslint-disable no-console */
const fs = require('fs')
const path = require('path')
const { prompt } = require('enquirer')
const { EncDecSync, Vault, readPwdFileSync } = require('..')
const MSG_PASSWORD = 'Vault password'
const MSG_PASSWORD_CONFIRM = 'Confirm Vault password'
const MSG_NEW_PASSWORD = 'New Vault password'
const MSG_NEW_PASSWORD_CONFIRM = 'Confirm new Vault password'
const ERROR_PASSWORD_MATCH = 'Error: Passwords need to match!'
const ERROR_COMMAND = 'Missing action!'
const ERROR_PASSWORD = 'Empty password!'
const ERROR_ITERATIONS = 'iterations is not a Number!'
async function promtPassword (message, password1) {
const { password } = await prompt({
type: 'password',
name: 'password',
message,
validate: (inp) => !password1 || password1 === inp || ERROR_PASSWORD_MATCH
})
return password
}
function argv () {
const argv = process.argv.slice(2)
const cmd = { files: [] }
while (argv.length) {
const arg = argv.shift()
switch (arg) {
case '-h':
case '--help':
cmd.help = true
break
case '--version':
cmd.version = true
break
case 'encrypt':
case 'decrypt':
case 'rekey':
cmd.action = arg
break
case '-p':
case '--password':
cmd.password = argv.shift()
break
case '-n':
case '--new-password':
cmd.newPassword = argv.shift()
break
case '--password-file':
cmd.passwordFile = argv.shift()
break
case '--new-password-file':
cmd.newPasswordFile = argv.shift()
break
case '--digest':
cmd.digest = argv.shift()
break
case '--iterations':
cmd.iterations = Number(argv.shift())
if (isNaN(cmd.iterations)) {
throw new Error(ERROR_ITERATIONS)
}
break
case '-o':
case '--output':
cmd.output = path.resolve(process.cwd(), argv.shift())
break
default:
cmd.files.push(path.resolve(process.cwd(), arg))
break
}
}
return cmd
}
async function ask (cmd) {
if (!cmd.password && !cmd.passwordFile) {
const password1 = await promtPassword(MSG_PASSWORD)
if (cmd.action === 'encrypt') {
await promtPassword(MSG_PASSWORD_CONFIRM, password1)
}
cmd.password = password1
}
if (cmd.action === 'rekey' && !cmd.newPasswordFile && !cmd.newPassword) {
const { password1 } = await prompt({
type: 'password',
name: 'password1',
message: MSG_NEW_PASSWORD
})
await prompt({
type: 'password',
name: 'password2',
message: MSG_NEW_PASSWORD_CONFIRM,
validate: (inp) => password1 === inp || ERROR_PASSWORD_MATCH
})
cmd.newPassword = password1
}
}
const readFile = (filename) => fs.readFileSync(filename, 'utf8')
const writeFile = (filename, data) => fs.writeFileSync(filename, data, 'utf8')
function version () {
console.log('v' + require('../package.json').version)
}
function help () {
console.log(fs.readFileSync(path.resolve(__dirname, '..', 'man', 'vault-nacl.txt'), 'utf8'))
}
async function main () {
const cmd = argv()
if (cmd.help) {
help()
} else if (cmd.version) {
version()
} else if (!cmd.action) {
throw new Error(ERROR_COMMAND)
} else {
await ask(cmd)
let newVault
if (!cmd.password && cmd.passwordFile) {
cmd.password = readPwdFileSync(cmd.passwordFile)
if (!cmd.password) throw new Error(ERROR_PASSWORD)
}
if (!cmd.newPassword && cmd.newPasswordFile) {
cmd.newPassword = readPwdFileSync(cmd.newPasswordFile)
}
const { digest, iterations } = cmd
const encdec = new EncDecSync(cmd.password, { digest, iterations })
if (!cmd.files.length) {
if (cmd.action === 'encrypt') {
const data = await promtPassword('Secret')
const _data = encdec.encryptString(data)
console.log(_data)
return
} else if (cmd.action === 'decrypt') {
const { data } = await prompt({
type: 'input',
name: 'data',
message: 'Vault'
})
const _data = encdec.decrypt(data)
console.log(_data)
return
}
}
cmd.files.forEach(filename => {
const data = readFile(filename)
switch (cmd.action) {
case 'decrypt': {
const _data = encdec.decrypt(data)
if (cmd.output && cmd.files.length === 1) {
fs.writeFileSync(cmd.output, _data, 'utf8')
} else {
console.log(_data) // print decrypted data to stdout
}
break
}
case 'encrypt': {
const _data = encdec.check(data)
? encdec.encrypt(data)
: encdec.encryptString(data)
writeFile(cmd.output || filename, _data)
break
}
case 'rekey': {
const { digest, iterations } = cmd
newVault = new Vault(cmd.newPassword, { digest, iterations })
const _data = encdec.rekey(data, newVault)
writeFile(cmd.output || filename, _data)
break
}
}
})
}
}
main().catch(err => {
console.error('Error: ' + err.message)
process.exit(1)
})