Last active
May 4, 2020 16:35
-
-
Save ScreamZ/6d9ed1c3661554ca0ae6b020ef1b3894 to your computer and use it in GitHub Desktop.
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
import crypto from "crypto"; | |
import merge from "lodash/merge"; | |
import { AppConfig, PrivateConfig, PublicConfig } from "./types"; | |
/** | |
* Factory function that takes a public config and a HEX encrypted configuration. | |
* On call, this function will decipher, both configuration will be merged together to provide a single JSON object representating the configuration. | |
* | |
* @param {PublicConfig} publicConfig | |
* @param {string} hexEncodedPrivateConfig | |
* @returns {() => AppConfig} | |
*/ | |
function buildConfig(publicConfig: PublicConfig, hexEncodedPrivateConfig: string): () => AppConfig { | |
return () => { | |
try { | |
// Isolate the IV from the encrypted string. | |
const [ivHex, encoded] = hexEncodedPrivateConfig.split(":"); | |
// Initiate a deciper instance using the encryption key and the IV. | |
const decipher = crypto.createDecipheriv( | |
"aes-256-cbc", | |
Buffer.from(process.env.ENCRYPTION_KEY), | |
Buffer.from(ivHex, "hex"), | |
); | |
// Decrypt private configuration. | |
let decryptedString = decipher.update(Buffer.from(encoded, "hex")); | |
decryptedString = Buffer.concat([decryptedString, decipher.final()]); | |
// Parse decrypted configuration string into JSON object for usage. | |
const decryptedPrivateConfig: PrivateConfig = JSON.parse(decryptedString.toString("utf8")); | |
// Merge private with public config and freeze it to prevent alteration within program executation. | |
return Object.freeze(merge(publicConfig, decryptedPrivateConfig)); | |
} catch (e) { | |
throw new Error("Error while decrypting server configuration. Probably bad decryption key…"); | |
} | |
}; | |
} | |
// Initiate factory for staging config | |
const getStagingConfig = buildConfig( | |
{ | |
authentication: { | |
session_duration_seconds: 604800 | |
}, | |
database: { | |
db_name: "some_name", | |
}, | |
mailing: { | |
templates_id: { | |
password_reset: 41, | |
}, | |
}, | |
}, | |
"1e53e959b66e8e5e778cda7aedf5f400:7ertt…ytfh99", // HERE paste encrypted config string | |
); | |
// Initiate factory for production config | |
const getProdConfig = buildConfig( | |
{ | |
authentication: { | |
session_duration_seconds: 604800 | |
}, | |
database: { | |
db_name: "some_prod_name", | |
}, | |
mailing: { | |
templates_id: { | |
password_reset: 25, | |
}, | |
}, | |
}, | |
"1e53e959b66e8e5e778cda7aedf5f400:7ertt…ytfh99", // HERE paste encrypted config string | |
); | |
export const APP_CONFIG = process.env.NODE_ENV === "production" ? getProdConfig() : getStagingConfig(); |
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 script is made for encrypting a JSON file named config.json that lives in the same directory of that script. | |
* This config.json should never be committed in a version control system like Git. | |
* | |
* Usage: | |
* - node encrypt.js <encryption_key> | |
*/ | |
const crypto = require("crypto"); | |
// Config | |
let contentToEncrypt; | |
const IV_LENGTH = 16; | |
const KEY = process.argv.slice(2)[0]; | |
// First, try to get the configuration file. | |
try { | |
contentToEncrypt = require("./config.json"); | |
} catch (e) {} | |
// Ensure that an encryption key has been provided as first arg and that there is a JSON configuration to encrypt. | |
if (!KEY || !contentToEncrypt) { | |
console.error( | |
"Please ensure that an encryption key is provided as argument and that there is config file to encrypt.", | |
); | |
process.exit(1); | |
} | |
// Generate Random IV | |
const iv = crypto.randomBytes(IV_LENGTH); | |
const cipher = crypto.createCipheriv("aes-256-cbc", KEY, iv); | |
// Encrypt a stringified version of our JSON configuration. | |
let encrypted = cipher.update(JSON.stringify(contentToEncrypt)); | |
encrypted = Buffer.concat([encrypted, cipher.final()]); | |
// Display the encrypted version that should be versionned. | |
console.log("Please store the following content in your configuration."); | |
console.log("---------------------------------------------------------"); | |
console.log(iv.toString("hex") + ":" + encrypted.toString("hex")); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
True, you can indeed roll your own crypto like this, but may I suggest using SOPS from Mozilla instead? https://github.com/mozilla/sops/blob/master/README.rst