Skip to content

Commit

Permalink
Merge pull request #2 from mangelsnc/feature/configuration
Browse files Browse the repository at this point in the history
Add configuration file
  • Loading branch information
mangelsnc committed Dec 6, 2022
2 parents 265adb2 + aef649c commit 6b7eda9
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 23 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
*.crt
*.csr
*.rsa
.env
.env.enc
undisclosed.conf.json
secrets

node_modules

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Simple CLI tool to handle encrypted secrets, heavily inspired in [Symfony Secret

With `undisclosed` you can set and store your credentials encrypted, and dump it in plain whenever you want.

## init
Execute `undisclosed init` to create a default config file template and the folder to store the keys.

## generate-keypair
With `undisclosed generate-keypair` you will generate your keypair. It will be used to encrypt all your data.

Expand Down
8 changes: 8 additions & 0 deletions config/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"keypair": {
"path": "/secrets",
"privateKeyName": "private",
"publicKeyName": "public"
},
"defaultEnvironment": "dev"
}
84 changes: 62 additions & 22 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ const fs = require('fs');
const crypto = require('crypto');

const args = process.argv;
const privateKeyPath = process.env.PWD + '/private.pem';
const publicKeyPath = process.env.PWD + '/public.pem';
const encryptedDataPath = process.env.PWD + '/.env.enc';
const decryptedDataPath = process.env.PWD + '/.env';
const config = loadConfig();

const subcommand = args[2];

const commandHandler = {
'init': handleInit,
'generate-keypair': handleGenereateKeyPair,
'list': handleList,
'set': handleSet,
Expand All @@ -22,34 +20,34 @@ const commandHandler = {
if (commandHandler.hasOwnProperty(subcommand)) {
commandHandler[subcommand]();
} else {
console.log("Usage: undisclosed [generate-keypair|list|set|get|dump]\n")
console.log("Usage: undisclosed [init|generate-keypair|list|set|get|dump]\n")
}

process.exit(0);

function encrypt(toEncrypt, publicKey) {
const buffer = Buffer.from(toEncrypt,'utf8');
const buffer = Buffer.from(toEncrypt, 'utf8');
const encrypted = crypto.publicEncrypt(publicKey, buffer);

return encrypted.toString('base64');
}

function decrypt(toDecrypt, privateKey) {
const buffer = Buffer.from(toDecrypt,'base64');
const buffer = Buffer.from(toDecrypt, 'base64');
const decrypted = crypto.privateDecrypt(privateKey, buffer);

return decrypted.toString('utf8');
}

function keysExists() {
return fs.existsSync(privateKeyPath) || fs.existsSync(publicKeyPath);
return fs.existsSync(config.keypair.privateKeyPath) || fs.existsSync(config.keypair.publicKeyPath);
}

function encryptedFileExists() {
return fs.existsSync(encryptedDataPath);
return fs.existsSync(config.encryptedDataPath);
}

function generateKeyPair(privateKeyPath, publicKeyPath) {
function generateKeyPair(publicKeyPath, privateKeyPath) {
const keyPair = crypto.generateKeyPairSync('rsa', {
modulusLength: 4096
});
Expand All @@ -65,7 +63,6 @@ function generateKeyPair(privateKeyPath, publicKeyPath) {
});

fs.writeFileSync(publicKeyPath, publicKey);

fs.writeFileSync(privateKeyPath, privateKey);

const dataToShow = [
Expand All @@ -85,7 +82,7 @@ function truncate(string, limit = 20) {
}

function loadSecrets(truncateValue = false) {
let data = fs.readFileSync(encryptedDataPath);
let data = fs.readFileSync(config.encryptedDataPath);
data = data.toString().split("\n");
const dataArray = [];

Expand All @@ -103,14 +100,28 @@ function loadSecrets(truncateValue = false) {
return dataArray;
}

function handleInit() {
if (!fs.existsSync(process.env.PWD + '/undisclosed.conf.json')) {
fs.copyFileSync(__dirname + '/config/default.json', process.env.PWD + '/undisclosed.conf.json');
}

const config = loadConfig();

if (!fs.existsSync(config.keypair.path)) {
fs.mkdirSync(config.keypair.path);
}

console.log("Undisclosed initialized.\n");
}

function handleGenereateKeyPair() {
if (keysExists()) {
console.error("Keypair already exists. Remove it before generate new keypair.\n");

process.exit(1);
}

generateKeyPair(privateKeyPath, publicKeyPath);
generateKeyPair(config.keypair.publicKeyPath, config.keypair.privateKeyPath);
}

function handleList() {
Expand All @@ -125,15 +136,15 @@ function handleList() {

function handleSet() {
if (!keysExists()) {
console.log("Keypair not found, run before:\n\tsecrets generate-keypair");
console.log("Keypair not found, run before:\n\tundisclosed generate-keypair");
process.exit(1);
}

const publicKey = fs.readFileSync(publicKeyPath, 'utf8').toString();
const publicKey = fs.readFileSync(config.keypair.publicKeyPath, 'utf8').toString();
const key = args[3];
const value = args[4];
const encryptedValue = encrypt(value, publicKey);
fs.appendFileSync(encryptedDataPath, key.toUpperCase() + '=' + encryptedValue + "\n");
fs.appendFileSync(config.encryptedDataPath, key.toUpperCase() + '=' + encryptedValue + "\n");

console.table([
{ key: key.toUpperCase(), value: truncate(encryptedValue) }
Expand All @@ -147,12 +158,12 @@ function handleGet() {
}

if (!keysExists()) {
console.log("Keypair not found, run before:\n\tsecrets generate-keypair");
console.log("Keypair not found, run before:\n\tundisclosed generate-keypair");
process.exit(1);
}

const keyToFind = args[3].toUpperCase();
const privateKey = fs.readFileSync(privateKeyPath, 'utf8').toString();
const privateKey = fs.readFileSync(config.keypair.privateKeyPath, 'utf8').toString();
loadSecrets().forEach(secret => {
if (secret.key === keyToFind) {
secret.value = decrypt(secret.value, privateKey);
Expand All @@ -172,18 +183,47 @@ function handleDump() {
}

if (!keysExists()) {
console.log("Keypair not found, run before:\n\tsecrets generate-keypair");
console.log("Keypair not found, run before:\n\tundisclosed generate-keypair");
process.exit(1);
}

const privateKey = fs.readFileSync(privateKeyPath, 'utf8').toString();
const privateKey = fs.readFileSync(config.keypair.privateKeyPath, 'utf8').toString();
const dumpedContent = []
loadSecrets().forEach(secret => {
secret.value = decrypt(secret.value, privateKey);
dumpedContent.push(secret.key + '=' + secret.value);
});

fs.writeFileSync(decryptedDataPath, dumpedContent.join("\n"));
fs.writeFileSync(config.decryptedDataPath, dumpedContent.join("\n"));

console.log('Secrets dumped to: ' + decryptedDataPath + "\n");
console.log('Secrets dumped to: ' + config.decryptedDataPath + "\n");
}

function loadConfig() {
const defaultConfig = {
keypair: {
path: process.env.PWD + '/secrets',
privateKeyName: 'private',
publicKeyName: 'public'
},
defaultEnvironment: 'dev',
encryptedDataPath: process.env.PWD + '/.env.enc',
decryptedDataPath: process.env.PWD + '/.env',
};

if (!fs.existsSync(process.env.PWD + '/undisclosed.conf.json')) {
defaultConfig.keypair.privateKeyPath = defaultConfig.keypair.path + '/' + defaultConfig.keypair.privateKeyName + '.pem';
defaultConfig.keypair.publicKeyPath = defaultConfig.keypair.path + '/' + defaultConfig.keypair.publicKeyName + '.pem';

return defaultConfig;
}

const userConfig = JSON.parse(fs.readFileSync(process.env.PWD + '/undisclosed.conf.json'));
const keyPairPath = process.env.PWD + userConfig.keypair.path;
userConfig.keypair.path = keyPairPath;
const config = { ...defaultConfig, ...userConfig }
config.keypair.privateKeyPath = config.keypair.path + '/' + config.keypair.privateKeyName + '.pem';
config.keypair.publicKeyPath = config.keypair.path + '/' + config.keypair.publicKeyName + '.pem';

return config;
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "undisclosed",
"version": "1.0.0",
"version": "1.1.0",
"description": "Command line tool to handle encrypted secrets",
"main": "index.js",
"scripts": {
Expand Down

0 comments on commit 6b7eda9

Please sign in to comment.