@naturalcycles/nodejs-lib
Version:
Standard library for Node.js
101 lines • 3.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs-extra");
const __1 = require("..");
let loaded = false;
// it's wrapped to be able to pipe console.* to Stackdriver
const getLog = () => __1.Debug('nc:nodejs-lib:secret');
const secretMap = {};
/**
* Loads plaintext secrets from process.env, removes them, stores locally.
* Make sure to call this function early on server startup, so secrets are removed from process.env
*
* Does NOT delete previous secrets from secretMap.
*/
function loadSecretsFromEnv() {
require('dotenv').config(); // ensure .env is loaded
const secrets = {};
Object.keys(process.env)
.filter(k => k.toUpperCase().startsWith('SECRET_'))
.forEach(k => {
secrets[k.toUpperCase()] = process.env[k];
secretMap[k.toUpperCase()] = process.env[k];
delete process.env[k];
});
loaded = true;
getLog()(`${Object.keys(secrets).length} secret(s) loaded from process.env: ${Object.keys(secrets).join(', ')}`);
}
exports.loadSecretsFromEnv = loadSecretsFromEnv;
/**
* Removes process.env.SECRET_*
*/
function removeSecretsFromEnv() {
Object.keys(process.env)
.filter(k => k.toUpperCase().startsWith('SECRET_'))
.forEach(k => delete process.env[k]);
}
exports.removeSecretsFromEnv = removeSecretsFromEnv;
/**
* Does NOT delete previous secrets from secretMap.
*
* If SECRET_ENCRYPTION_KEY argument is passed - will decrypt the contents of the file first, before parsing it as JSON.
*/
function loadSecretsFromJsonFile(filePath, SECRET_ENCRYPTION_KEY) {
if (!fs.existsSync(filePath)) {
throw new Error(`loadSecretsFromPlainJsonFile() cannot load from path: ${filePath}`);
}
let secrets;
if (SECRET_ENCRYPTION_KEY) {
const buf = fs.readFileSync(filePath);
const plain = __1.decryptRandomIVBuffer(buf, SECRET_ENCRYPTION_KEY).toString('utf8');
secrets = JSON.parse(plain);
}
else {
secrets = fs.readJsonSync(filePath);
}
Object.entries(secrets).forEach(([k, v]) => (secretMap[k.toUpperCase()] = v));
loaded = true;
getLog()(`${Object.keys(secrets).length} secret(s) loaded from ${filePath}: ${Object.keys(secrets)
.map(s => s.toUpperCase())
.join(', ')}`);
}
exports.loadSecretsFromJsonFile = loadSecretsFromJsonFile;
/**
* json secrets are always base64'd
*/
function secret(k, json = false) {
const v = secretOptional(k, json);
if (!v) {
throw new Error(`secret(${k.toUpperCase()}) not found!`);
}
return v;
}
exports.secret = secret;
function secretOptional(k, json = false) {
requireLoaded();
const v = secretMap[k.toUpperCase()];
return v && json ? JSON.parse(__1.base64ToString(v)) : v;
}
exports.secretOptional = secretOptional;
function getSecretMap() {
requireLoaded();
return secretMap;
}
exports.getSecretMap = getSecretMap;
/**
* REPLACES secretMap with new map.
*/
function setSecretMap(map) {
Object.keys(secretMap).forEach(k => delete secretMap[k]);
Object.entries(map).forEach(([k, v]) => (secretMap[k.toUpperCase()] = v));
getLog()(`setSecretMap set ${Object.keys(secretMap).length} secret(s): ${Object.keys(map)
.map(s => s.toUpperCase())
.join(', ')}`);
}
exports.setSecretMap = setSecretMap;
function requireLoaded() {
if (!loaded) {
throw new Error(`Secrets were not loaded! Call loadSecrets() before accessing secrets.`);
}
}
//# sourceMappingURL=secret.util.js.map