UNPKG

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