-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
82278ec
commit 235f144
Showing
5 changed files
with
325 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
const Bakelet = require('../bakelet'); | ||
const path = require('path'); | ||
|
||
const { privateKey } = require('../../../global-vars'); | ||
const conf = require('../../modules/configstore') | ||
|
||
const Ansible = require('../../modules/configuration/ansible'); | ||
const VaultLib = require('../../modules/vault'); | ||
const Ssh = require('../../modules/ssh'); | ||
|
||
class Vault extends Bakelet { | ||
|
||
constructor(name,ansibleSSHConfig, version) { | ||
super(ansibleSSHConfig); | ||
|
||
this.name = name; | ||
this.version = version; | ||
} | ||
|
||
|
||
async promptPass() | ||
{ | ||
return new Promise(function(resolve,reject) | ||
{ | ||
var properties = [ | ||
{ | ||
name: 'password', | ||
hidden: true | ||
} | ||
]; | ||
|
||
prompt.start(); | ||
|
||
prompt.get(properties, function (err, result) { | ||
if (err) { reject(err); } | ||
else | ||
{ | ||
resolve(result.password) | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
|
||
async load(obj, variables) | ||
{ | ||
|
||
let passphraseKey = `vault:${process.cwd()}`; | ||
let passphrase = ''; | ||
if (conf.has(passphraseKey)) | ||
{ | ||
passphrase = conf.get(passphraseKey); | ||
} | ||
else | ||
{ | ||
passphrase = promptPass(); | ||
} | ||
let vault = new VaultLib(); | ||
|
||
if( Array.isArray(obj.vault) ) | ||
{ | ||
this.vault = obj.vault; | ||
this.variables = variables || {}; | ||
|
||
for (let entry of obj.vault) | ||
{ | ||
let file = path.join(this.bakePath, entry.file); | ||
let content = vault.retrieve(file, passphrase); | ||
|
||
await Ssh.writeContentToDest(content, | ||
`/home/vagrant/baker/${this.name}/templates/${entry.file}`, | ||
this.ansibleSSHConfig, | ||
false | ||
); | ||
} | ||
} | ||
} | ||
|
||
async install() | ||
{ | ||
if( this.vault ) | ||
{ | ||
for (let entry of this.vault) | ||
{ | ||
await Ansible.runAnsibleTemplateCmd( | ||
{name: this.name}, `/home/vagrant/baker/${this.name}/templates/${entry.file}`, | ||
entry.dest, this.variables, this.ansibleSSHConfig, this.verbose); | ||
} | ||
} | ||
} | ||
|
||
|
||
} | ||
|
||
module.exports = Vault; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
|
||
const Baker = require('../modules/baker'); | ||
const conf = require('../../lib/modules/configstore') | ||
const Print = require('../modules/print'); | ||
const Spinner = require('../modules/spinner'); | ||
|
||
const fs = require('fs'); | ||
const prompt = require('prompt'); | ||
|
||
const VaultLib = require('../modules/vault'); | ||
|
||
const spinnerDot = conf.get('spinnerDot'); | ||
|
||
exports.command = 'vault <file>'; | ||
exports.desc = `encrypt a file`; | ||
|
||
exports.builder = (yargs) => { | ||
yargs | ||
.example(`$0 vault secret.json`, `Encrypt the secret.json file with a passphrase`) | ||
.example(`$0 vault -v secret.json`, `View unencrypted content with passphrase`) | ||
.example(`$0 vault -u secret.json`, `Unencrypt content with passphrase`) | ||
|
||
yargs | ||
.positional('file', { | ||
describe: 'file to encrypt', | ||
type: 'string' | ||
}); | ||
|
||
yargs.options({ | ||
view: { | ||
alias: 'v', | ||
describe: `view unencrypted content with passphrase`, | ||
demand: false, | ||
type: 'boolean' | ||
}, | ||
decrypt: { | ||
alias: 'u', | ||
describe: `Unencrypt content with passphrase`, | ||
demand: false, | ||
type: 'boolean' | ||
}, | ||
}); | ||
|
||
|
||
} | ||
|
||
|
||
async function promptPass() | ||
{ | ||
return new Promise(function(resolve,reject) | ||
{ | ||
var properties = [ | ||
{ | ||
name: 'password', | ||
hidden: true | ||
} | ||
]; | ||
|
||
prompt.start(); | ||
|
||
prompt.get(properties, function (err, result) { | ||
if (err) { reject(err); } | ||
else | ||
{ | ||
resolve(result.password) | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
|
||
exports.handler = async function(argv) { | ||
let { envName, verbose } = argv; | ||
|
||
try{ | ||
// await Spinner.spinPromise(BakerObj.start(envName, verbose), `Starting VM: ${envName}`, spinnerDot); | ||
if( !fs.existsSync(argv.file) ) | ||
{ | ||
throw new Error(`The provide file does not exist: ${argv.file}`) | ||
} | ||
|
||
let passphraseKey = `vault:${process.cwd()}`; | ||
if (!conf.has(passphraseKey)) | ||
{ | ||
let typedPassphrase = await promptPass(); | ||
conf.set(passphraseKey, typedPassphrase); | ||
} | ||
|
||
let passphrase = conf.get(passphraseKey); | ||
let vault = new VaultLib(); | ||
|
||
if( argv.decrypt) | ||
{ | ||
let content = vault.retrieve(argv.file, passphrase); | ||
console.log("Decrypting contents and writing to file.") | ||
fs.writeFileSync(argv.file, content); | ||
} | ||
else | ||
{ | ||
if ( argv.view ) | ||
{ | ||
let content = vault.retrieve(argv.file, passphrase); | ||
console.log("Viewing decrypted contents:") | ||
console.log(content); | ||
} | ||
else | ||
{ | ||
vault.vault(argv.file, passphrase); | ||
} | ||
} | ||
|
||
} catch (err){ | ||
Print.error(err); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
const crypto = require('crypto'); | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
|
||
const {version} = require('../../global-vars') | ||
|
||
class VaultLib { | ||
constructor() | ||
{ | ||
this.iv = crypto.randomBytes(16); | ||
this.algorithm = 'aes-256-ctr'; | ||
this.salt = Buffer.from('5ebe2294ecd0e0f', 'hex'); | ||
this.headerRegex = /baker-vault:\d+[.]\d+[.]\d+:[0-9A-Fa-f]{15}/g; | ||
} | ||
|
||
isEncrypted(filePath) | ||
{ | ||
let lines = fs.readFileSync(filePath).toString().split(/\r?\n/); | ||
if( lines.length > 0 ) | ||
{ | ||
let matches = lines[0].match( this.headerRegex ); | ||
return matches != null; | ||
} | ||
return false; | ||
} | ||
|
||
vault(filePath, passphrase) | ||
{ | ||
if( this.isEncrypted(filePath) ) | ||
{ | ||
throw new Error(`File is already encrypted: ${filePath}`); | ||
} | ||
|
||
let key = this.generateKeyFromPhrase(passphrase); | ||
let content = fs.readFileSync(filePath); | ||
|
||
let buffer = `baker-vault:${version}:${this.iv.toString('hex')}\n`; | ||
buffer += this.encryptWithKey(content, key, this.iv); | ||
|
||
fs.writeFileSync(filePath, buffer); | ||
|
||
return key.toString('hex'); | ||
} | ||
|
||
retrieve(filePath, passphrase) | ||
{ | ||
if( this.isEncrypted(filePath) ) | ||
{ | ||
let lines = fs.readFileSync(filePath).toString().split(/\r?\n/); | ||
let key = this.generateKeyFromPhrase(passphrase); | ||
let iv = Buffer.from(lines[0].split(':')[2],'hex'); | ||
|
||
return this.decryptWithKey(lines[1],key,iv); | ||
} | ||
throw new Error(`File is not encrypted: ${filePath}`); | ||
} | ||
|
||
encryptWithKey(text, key, iv) { | ||
let cipher = crypto.createCipheriv(this.algorithm, key, iv ) | ||
let crypted = cipher.update(text,'utf8','hex') | ||
crypted += cipher.final('hex'); | ||
return crypted; | ||
} | ||
|
||
generateKeyFromPhrase(passphrase) | ||
{ | ||
return crypto.pbkdf2Sync(passphrase, this.salt, 100000, 32, 'sha512'); | ||
} | ||
|
||
decryptWithKey(text, key, iv) | ||
{ | ||
let decipher = crypto.createDecipheriv(this.algorithm, key, iv) | ||
let dec = decipher.update(text,'hex','utf8') | ||
dec += decipher.final('utf8'); | ||
return dec; | ||
} | ||
} | ||
|
||
module.exports = VaultLib; | ||
|