UNPKG

3.76 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.setSecretMap = exports.getSecretMap = exports.secretOptional = exports.secret = exports.loadSecretsFromJsonFile = exports.removeSecretsFromEnv = exports.loadSecretsFromEnv = void 0;
4const fs = require("fs");
5const __1 = require("..");
6const crypto_util_1 = require("./crypto.util");
7let loaded = false;
8// it's wrapped to be able to pipe console.* to Stackdriver
9const getLog = () => (0, __1.Debug)('nc:nodejs-lib:secret');
10const secretMap = {};
11/**
12 * Loads plaintext secrets from process.env, removes them, stores locally.
13 * Make sure to call this function early on server startup, so secrets are removed from process.env
14 *
15 * Does NOT delete previous secrets from secretMap.
16 */
17function loadSecretsFromEnv() {
18 require('dotenv').config(); // ensure .env is loaded
19 const secrets = {};
20 Object.keys(process.env)
21 .filter(k => k.toUpperCase().startsWith('SECRET_'))
22 .forEach(k => {
23 secrets[k.toUpperCase()] = process.env[k];
24 secretMap[k.toUpperCase()] = process.env[k];
25 delete process.env[k];
26 });
27 loaded = true;
28 getLog()(`${Object.keys(secrets).length} secret(s) loaded from process.env: ${Object.keys(secrets).join(', ')}`);
29}
30exports.loadSecretsFromEnv = loadSecretsFromEnv;
31/**
32 * Removes process.env.SECRET_*
33 */
34function removeSecretsFromEnv() {
35 Object.keys(process.env)
36 .filter(k => k.toUpperCase().startsWith('SECRET_'))
37 .forEach(k => delete process.env[k]);
38}
39exports.removeSecretsFromEnv = removeSecretsFromEnv;
40/**
41 * Does NOT delete previous secrets from secretMap.
42 *
43 * If SECRET_ENCRYPTION_KEY argument is passed - will decrypt the contents of the file first, before parsing it as JSON.
44 */
45function loadSecretsFromJsonFile(filePath, SECRET_ENCRYPTION_KEY) {
46 if (!fs.existsSync(filePath)) {
47 throw new Error(`loadSecretsFromPlainJsonFile() cannot load from path: ${filePath}`);
48 }
49 let secrets;
50 if (SECRET_ENCRYPTION_KEY) {
51 const buf = fs.readFileSync(filePath);
52 const plain = (0, crypto_util_1.decryptRandomIVBuffer)(buf, SECRET_ENCRYPTION_KEY).toString('utf8');
53 secrets = JSON.parse(plain);
54 }
55 else {
56 secrets = JSON.parse(fs.readFileSync(filePath, 'utf8'));
57 }
58 Object.entries(secrets).forEach(([k, v]) => (secretMap[k.toUpperCase()] = v));
59 loaded = true;
60 getLog()(`${Object.keys(secrets).length} secret(s) loaded from ${filePath}: ${Object.keys(secrets)
61 .map(s => s.toUpperCase())
62 .join(', ')}`);
63}
64exports.loadSecretsFromJsonFile = loadSecretsFromJsonFile;
65/**
66 * json secrets are always base64'd
67 */
68function secret(k, json = false) {
69 const v = secretOptional(k, json);
70 if (!v) {
71 throw new Error(`secret(${k.toUpperCase()}) not found!`);
72 }
73 return v;
74}
75exports.secret = secret;
76function secretOptional(k, json = false) {
77 requireLoaded();
78 const v = secretMap[k.toUpperCase()];
79 return v && json ? JSON.parse((0, __1.base64ToString)(v)) : v;
80}
81exports.secretOptional = secretOptional;
82function getSecretMap() {
83 requireLoaded();
84 return secretMap;
85}
86exports.getSecretMap = getSecretMap;
87/**
88 * REPLACES secretMap with new map.
89 */
90function setSecretMap(map) {
91 Object.keys(secretMap).forEach(k => delete secretMap[k]);
92 Object.entries(map).forEach(([k, v]) => (secretMap[k.toUpperCase()] = v));
93 getLog()(`setSecretMap set ${Object.keys(secretMap).length} secret(s): ${Object.keys(map)
94 .map(s => s.toUpperCase())
95 .join(', ')}`);
96}
97exports.setSecretMap = setSecretMap;
98function requireLoaded() {
99 if (!loaded) {
100 throw new Error(`Secrets were not loaded! Call loadSecrets() before accessing secrets.`);
101 }
102}