@naturalcycles/nodejs-lib 12.104.0 → 13.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/secrets-decrypt.js +5 -4
- package/dist/bin/secrets-encrypt.js +6 -5
- package/dist/fs/fs.util.js +8 -4
- package/dist/secret/secrets-decrypt.util.d.ts +3 -2
- package/dist/secret/secrets-decrypt.util.js +6 -4
- package/dist/secret/secrets-encrypt.util.d.ts +3 -2
- package/dist/secret/secrets-encrypt.util.js +3 -3
- package/dist/security/crypto.util.d.ts +22 -12
- package/dist/security/crypto.util.js +33 -23
- package/dist/security/secret.util.js +4 -2
- package/package.json +1 -1
- package/readme.md +1 -1
- package/src/bin/secrets-decrypt.ts +6 -4
- package/src/bin/secrets-encrypt.ts +7 -5
- package/src/fs/fs.util.ts +9 -4
- package/src/secret/secrets-decrypt.util.ts +8 -5
- package/src/secret/secrets-encrypt.util.ts +4 -4
- package/src/security/crypto.util.ts +34 -24
- package/src/security/secret.util.ts +4 -2
|
@@ -6,8 +6,8 @@ const colors_1 = require("../colors/colors");
|
|
|
6
6
|
const runScript_1 = require("../script/runScript");
|
|
7
7
|
const secrets_decrypt_util_1 = require("../secret/secrets-decrypt.util");
|
|
8
8
|
(0, runScript_1.runScript)(() => {
|
|
9
|
-
const { dir, file,
|
|
10
|
-
(0, secrets_decrypt_util_1.secretsDecrypt)(dir, file,
|
|
9
|
+
const { dir, file, encKeyBuffer, del, jsonMode } = getDecryptCLIOptions();
|
|
10
|
+
(0, secrets_decrypt_util_1.secretsDecrypt)(dir, file, encKeyBuffer, del, jsonMode);
|
|
11
11
|
});
|
|
12
12
|
function getDecryptCLIOptions() {
|
|
13
13
|
require('dotenv').config();
|
|
@@ -24,7 +24,7 @@ function getDecryptCLIOptions() {
|
|
|
24
24
|
},
|
|
25
25
|
encKey: {
|
|
26
26
|
type: 'string',
|
|
27
|
-
desc: 'Encryption key',
|
|
27
|
+
desc: 'Encryption key as base64 encoded string',
|
|
28
28
|
// demandOption: true,
|
|
29
29
|
// default: process.env.SECRET_ENCRYPTION_KEY!,
|
|
30
30
|
},
|
|
@@ -56,6 +56,7 @@ function getDecryptCLIOptions() {
|
|
|
56
56
|
throw new Error(`encKey is required. Can be provided as --encKey or env.SECRET_ENCRYPTION_KEY (see readme.md)`);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
const encKeyBuffer = Buffer.from(encKey, 'base64');
|
|
59
60
|
// `as any` because @types/yargs can't handle string[] type properly
|
|
60
|
-
return { dir: dir, file,
|
|
61
|
+
return { dir: dir, file, encKeyBuffer, del, jsonMode };
|
|
61
62
|
}
|
|
@@ -6,8 +6,8 @@ const colors_1 = require("../colors/colors");
|
|
|
6
6
|
const runScript_1 = require("../script/runScript");
|
|
7
7
|
const secrets_encrypt_util_1 = require("../secret/secrets-encrypt.util");
|
|
8
8
|
(0, runScript_1.runScript)(() => {
|
|
9
|
-
const { pattern, file,
|
|
10
|
-
(0, secrets_encrypt_util_1.secretsEncrypt)(pattern, file,
|
|
9
|
+
const { pattern, file, encKeyBuffer, del, jsonMode } = getEncryptCLIOptions();
|
|
10
|
+
(0, secrets_encrypt_util_1.secretsEncrypt)(pattern, file, encKeyBuffer, del, jsonMode);
|
|
11
11
|
});
|
|
12
12
|
function getEncryptCLIOptions() {
|
|
13
13
|
require('dotenv').config();
|
|
@@ -15,7 +15,7 @@ function getEncryptCLIOptions() {
|
|
|
15
15
|
pattern: {
|
|
16
16
|
type: 'string',
|
|
17
17
|
array: true,
|
|
18
|
-
desc: 'Globby pattern for secrets. Can be
|
|
18
|
+
desc: 'Globby pattern for secrets. Can be multiple.',
|
|
19
19
|
// demandOption: true,
|
|
20
20
|
default: './secret/**',
|
|
21
21
|
},
|
|
@@ -25,7 +25,7 @@ function getEncryptCLIOptions() {
|
|
|
25
25
|
},
|
|
26
26
|
encKey: {
|
|
27
27
|
type: 'string',
|
|
28
|
-
desc: 'Encryption key',
|
|
28
|
+
desc: 'Encryption key as base64 encoded string',
|
|
29
29
|
// demandOption: true,
|
|
30
30
|
// default: process.env.SECRET_ENCRYPTION_KEY!,
|
|
31
31
|
},
|
|
@@ -58,6 +58,7 @@ function getEncryptCLIOptions() {
|
|
|
58
58
|
throw new Error(`encKey is required. Can be provided as --encKey or env.SECRET_ENCRYPTION_KEY (see readme.md)`);
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
const encKeyBuffer = Buffer.from(encKey, 'base64');
|
|
61
62
|
// `as any` because @types/yargs can't handle string[] type properly
|
|
62
|
-
return { pattern: pattern, file,
|
|
63
|
+
return { pattern: pattern, file, encKeyBuffer, del, jsonMode };
|
|
63
64
|
}
|
package/dist/fs/fs.util.js
CHANGED
|
@@ -120,23 +120,27 @@ function _outputFileSync(filePath, data) {
|
|
|
120
120
|
fs.writeFileSync(filePath, data);
|
|
121
121
|
}
|
|
122
122
|
exports._outputFileSync = _outputFileSync;
|
|
123
|
+
function stringify(data, opt) {
|
|
124
|
+
// If pretty-printing is enabled (spaces) - also add a newline at the end (to match our prettier config)
|
|
125
|
+
return JSON.stringify(data, null, opt?.spaces) + (opt?.spaces ? '\n' : '');
|
|
126
|
+
}
|
|
123
127
|
async function _writeJson(filePath, data, opt) {
|
|
124
|
-
const str =
|
|
128
|
+
const str = stringify(data, opt);
|
|
125
129
|
await fsp.writeFile(filePath, str);
|
|
126
130
|
}
|
|
127
131
|
exports._writeJson = _writeJson;
|
|
128
132
|
function _writeJsonSync(filePath, data, opt) {
|
|
129
|
-
const str =
|
|
133
|
+
const str = stringify(data, opt);
|
|
130
134
|
fs.writeFileSync(filePath, str);
|
|
131
135
|
}
|
|
132
136
|
exports._writeJsonSync = _writeJsonSync;
|
|
133
137
|
async function _outputJson(filePath, data, opt) {
|
|
134
|
-
const str =
|
|
138
|
+
const str = stringify(data, opt);
|
|
135
139
|
await _outputFile(filePath, str);
|
|
136
140
|
}
|
|
137
141
|
exports._outputJson = _outputJson;
|
|
138
142
|
function _outputJsonSync(filePath, data, opt) {
|
|
139
|
-
const str =
|
|
143
|
+
const str = stringify(data, opt);
|
|
140
144
|
_outputFileSync(filePath, str);
|
|
141
145
|
}
|
|
142
146
|
exports._outputJsonSync = _outputJsonSync;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
export interface DecryptCLIOptions {
|
|
2
3
|
dir: string[];
|
|
3
4
|
file?: string;
|
|
4
|
-
|
|
5
|
+
encKeyBuffer: Buffer;
|
|
5
6
|
del?: boolean;
|
|
6
7
|
jsonMode?: boolean;
|
|
7
8
|
}
|
|
@@ -9,4 +10,4 @@ export interface DecryptCLIOptions {
|
|
|
9
10
|
* Decrypts all files in given directory (*.enc), saves decrypted versions without ending `.enc`.
|
|
10
11
|
* Using provided encKey.
|
|
11
12
|
*/
|
|
12
|
-
export declare function secretsDecrypt(dir: string[], file: string | undefined,
|
|
13
|
+
export declare function secretsDecrypt(dir: string[], file: string | undefined, encKeyBuffer: Buffer, del?: boolean, jsonMode?: boolean): void;
|
|
@@ -8,13 +8,15 @@ const colors_1 = require("../colors/colors");
|
|
|
8
8
|
const index_1 = require("../index");
|
|
9
9
|
const crypto_util_1 = require("../security/crypto.util");
|
|
10
10
|
// Debug it like this:
|
|
11
|
-
// yarn tsn ./src/bin/secrets-decrypt.ts --file ./src/test/secrets2.json --jsonMode --encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
12
11
|
// yarn tsn ./src/bin/secrets-encrypt.ts --file ./src/test/secrets2.plain.json --jsonMode --encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
12
|
+
// yarn tsn ./src/bin/secrets-decrypt.ts --file ./src/test/secrets2.json --jsonMode --encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
13
|
+
// yarn tsn ./src/bin/secrets-encrypt.ts --file ./src/test/secrets.json -encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
14
|
+
// yarn tsn ./src/bin/secrets-decrypt.ts --file ./src/test/secrets.json.enc -encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
13
15
|
/**
|
|
14
16
|
* Decrypts all files in given directory (*.enc), saves decrypted versions without ending `.enc`.
|
|
15
17
|
* Using provided encKey.
|
|
16
18
|
*/
|
|
17
|
-
function secretsDecrypt(dir, file,
|
|
19
|
+
function secretsDecrypt(dir, file, encKeyBuffer, del = false, jsonMode = false) {
|
|
18
20
|
// If `file` is provided - only this one file is used
|
|
19
21
|
const patterns = file ? [file] : dir.map(d => `${d}/**/*.enc`);
|
|
20
22
|
const filenames = index_1.fastGlob.sync(patterns);
|
|
@@ -24,12 +26,12 @@ function secretsDecrypt(dir, file, encKey, del = false, jsonMode = false) {
|
|
|
24
26
|
(0, js_lib_1._assert)(filename.endsWith('.json'), `${path.basename(filename)} MUST end with '.json'`);
|
|
25
27
|
(0, js_lib_1._assert)(!filename.endsWith('.plain.json'), `${path.basename(filename)} MUST NOT end with '.plain.json'`);
|
|
26
28
|
plainFilename = filename.replace('.json', '.plain.json');
|
|
27
|
-
const json = (0, crypto_util_1.decryptObject)((0, index_1._readJsonSync)(filename),
|
|
29
|
+
const json = (0, crypto_util_1.decryptObject)((0, index_1._readJsonSync)(filename), encKeyBuffer);
|
|
28
30
|
(0, index_1._writeJsonSync)(plainFilename, json, { spaces: 2 });
|
|
29
31
|
}
|
|
30
32
|
else {
|
|
31
33
|
const enc = fs.readFileSync(filename);
|
|
32
|
-
const plain = (0, crypto_util_1.decryptRandomIVBuffer)(enc,
|
|
34
|
+
const plain = (0, crypto_util_1.decryptRandomIVBuffer)(enc, encKeyBuffer);
|
|
33
35
|
plainFilename = filename.slice(0, filename.length - '.enc'.length);
|
|
34
36
|
fs.writeFileSync(plainFilename, plain);
|
|
35
37
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
export interface EncryptCLIOptions {
|
|
2
3
|
pattern: string[];
|
|
3
4
|
file?: string;
|
|
4
|
-
|
|
5
|
+
encKeyBuffer: Buffer;
|
|
5
6
|
del?: boolean;
|
|
6
7
|
jsonMode?: boolean;
|
|
7
8
|
}
|
|
@@ -9,4 +10,4 @@ export interface EncryptCLIOptions {
|
|
|
9
10
|
* Encrypts all files in given directory (except *.enc), saves encrypted versions as filename.ext.enc.
|
|
10
11
|
* Using provided encKey.
|
|
11
12
|
*/
|
|
12
|
-
export declare function secretsEncrypt(pattern: string[], file: string | undefined,
|
|
13
|
+
export declare function secretsEncrypt(pattern: string[], file: string | undefined, encKeyBuffer: Buffer, del?: boolean, jsonMode?: boolean): void;
|
|
@@ -11,7 +11,7 @@ const crypto_util_1 = require("../security/crypto.util");
|
|
|
11
11
|
* Encrypts all files in given directory (except *.enc), saves encrypted versions as filename.ext.enc.
|
|
12
12
|
* Using provided encKey.
|
|
13
13
|
*/
|
|
14
|
-
function secretsEncrypt(pattern, file,
|
|
14
|
+
function secretsEncrypt(pattern, file, encKeyBuffer, del = false, jsonMode = false) {
|
|
15
15
|
const patterns = file
|
|
16
16
|
? [file]
|
|
17
17
|
: [
|
|
@@ -24,12 +24,12 @@ function secretsEncrypt(pattern, file, encKey, del = false, jsonMode = false) {
|
|
|
24
24
|
if (jsonMode) {
|
|
25
25
|
(0, js_lib_1._assert)(filename.endsWith('.plain.json'), `${path.basename(filename)} MUST end with '.plain.json'`);
|
|
26
26
|
encFilename = filename.replace('.plain', '');
|
|
27
|
-
const json = (0, crypto_util_1.encryptObject)((0, index_1._readJsonSync)(filename),
|
|
27
|
+
const json = (0, crypto_util_1.encryptObject)((0, index_1._readJsonSync)(filename), encKeyBuffer);
|
|
28
28
|
(0, index_1._writeJsonSync)(encFilename, json, { spaces: 2 });
|
|
29
29
|
}
|
|
30
30
|
else {
|
|
31
31
|
const plain = fs.readFileSync(filename);
|
|
32
|
-
const enc = (0, crypto_util_1.encryptRandomIVBuffer)(plain,
|
|
32
|
+
const enc = (0, crypto_util_1.encryptRandomIVBuffer)(plain, encKeyBuffer);
|
|
33
33
|
encFilename = `${filename}.enc`;
|
|
34
34
|
fs.writeFileSync(encFilename, enc);
|
|
35
35
|
}
|
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Base64String, StringMap } from '@naturalcycles/js-lib';
|
|
3
3
|
/**
|
|
4
|
-
* Using aes-256-cbc
|
|
4
|
+
* Using aes-256-cbc.
|
|
5
5
|
*/
|
|
6
|
-
export declare function encryptRandomIVBuffer(input: Buffer,
|
|
6
|
+
export declare function encryptRandomIVBuffer(input: Buffer, secretKeyBuffer: Buffer): Buffer;
|
|
7
7
|
/**
|
|
8
|
-
* Using aes-256-cbc
|
|
8
|
+
* Using aes-256-cbc.
|
|
9
9
|
*/
|
|
10
|
-
export declare function decryptRandomIVBuffer(input: Buffer,
|
|
10
|
+
export declare function decryptRandomIVBuffer(input: Buffer, secretKeyBuffer: Buffer): Buffer;
|
|
11
11
|
/**
|
|
12
|
-
* Decrypts all object values.
|
|
13
|
-
* Returns object with decrypted values.
|
|
12
|
+
* Decrypts all object values (base64 strings).
|
|
13
|
+
* Returns object with decrypted values (utf8 strings).
|
|
14
14
|
*/
|
|
15
|
-
export declare function decryptObject(obj: StringMap<Base64String>,
|
|
16
|
-
export declare function encryptObject(obj: StringMap, secretKey: string): StringMap<Base64String>;
|
|
15
|
+
export declare function decryptObject(obj: StringMap<Base64String>, secretKeyBuffer: Buffer): StringMap;
|
|
17
16
|
/**
|
|
18
|
-
*
|
|
17
|
+
* Encrypts all object values (utf8 strings).
|
|
18
|
+
* Returns object with encrypted values (base64 strings).
|
|
19
19
|
*/
|
|
20
|
-
export declare function
|
|
20
|
+
export declare function encryptObject(obj: StringMap, secretKeyBuffer: Buffer): StringMap<Base64String>;
|
|
21
21
|
/**
|
|
22
|
-
* Using aes-256-cbc
|
|
22
|
+
* Using aes-256-cbc.
|
|
23
|
+
*
|
|
24
|
+
* Input is base64 string.
|
|
25
|
+
* Output is utf8 string.
|
|
23
26
|
*/
|
|
24
|
-
export declare function
|
|
27
|
+
export declare function decryptString(str: Base64String, secretKeyBuffer: Buffer): string;
|
|
28
|
+
/**
|
|
29
|
+
* Using aes-256-cbc.
|
|
30
|
+
*
|
|
31
|
+
* Input is utf8 string.
|
|
32
|
+
* Output is base64 string.
|
|
33
|
+
*/
|
|
34
|
+
export declare function encryptString(str: string, secretKeyBuffer: Buffer): Base64String;
|
|
@@ -6,11 +6,11 @@ const js_lib_1 = require("@naturalcycles/js-lib");
|
|
|
6
6
|
const hash_util_1 = require("./hash.util");
|
|
7
7
|
const algorithm = 'aes-256-cbc';
|
|
8
8
|
/**
|
|
9
|
-
* Using aes-256-cbc
|
|
9
|
+
* Using aes-256-cbc.
|
|
10
10
|
*/
|
|
11
|
-
function encryptRandomIVBuffer(input,
|
|
12
|
-
//
|
|
13
|
-
const key = (0, hash_util_1.
|
|
11
|
+
function encryptRandomIVBuffer(input, secretKeyBuffer) {
|
|
12
|
+
// sha256 to match aes-256 key length
|
|
13
|
+
const key = (0, hash_util_1.sha256AsBuffer)(secretKeyBuffer);
|
|
14
14
|
// Random iv to achieve non-deterministic encryption (but deterministic decryption)
|
|
15
15
|
const iv = crypto.randomBytes(16);
|
|
16
16
|
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
|
@@ -18,11 +18,11 @@ function encryptRandomIVBuffer(input, secretKeyBase64) {
|
|
|
18
18
|
}
|
|
19
19
|
exports.encryptRandomIVBuffer = encryptRandomIVBuffer;
|
|
20
20
|
/**
|
|
21
|
-
* Using aes-256-cbc
|
|
21
|
+
* Using aes-256-cbc.
|
|
22
22
|
*/
|
|
23
|
-
function decryptRandomIVBuffer(input,
|
|
24
|
-
//
|
|
25
|
-
const key = (0, hash_util_1.
|
|
23
|
+
function decryptRandomIVBuffer(input, secretKeyBuffer) {
|
|
24
|
+
// sha256 to match aes-256 key length
|
|
25
|
+
const key = (0, hash_util_1.sha256AsBuffer)(secretKeyBuffer);
|
|
26
26
|
// iv is first 16 bytes of encrypted buffer, the rest is payload
|
|
27
27
|
const iv = input.subarray(0, 16);
|
|
28
28
|
const payload = input.subarray(16);
|
|
@@ -31,11 +31,11 @@ function decryptRandomIVBuffer(input, secretKeyBase64) {
|
|
|
31
31
|
}
|
|
32
32
|
exports.decryptRandomIVBuffer = decryptRandomIVBuffer;
|
|
33
33
|
/**
|
|
34
|
-
* Decrypts all object values.
|
|
35
|
-
* Returns object with decrypted values.
|
|
34
|
+
* Decrypts all object values (base64 strings).
|
|
35
|
+
* Returns object with decrypted values (utf8 strings).
|
|
36
36
|
*/
|
|
37
|
-
function decryptObject(obj,
|
|
38
|
-
const { key, iv } = getCryptoParams(
|
|
37
|
+
function decryptObject(obj, secretKeyBuffer) {
|
|
38
|
+
const { key, iv } = getCryptoParams(secretKeyBuffer);
|
|
39
39
|
const r = {};
|
|
40
40
|
(0, js_lib_1._stringMapEntries)(obj).forEach(([k, v]) => {
|
|
41
41
|
const decipher = crypto.createDecipheriv(algorithm, key, iv);
|
|
@@ -44,8 +44,12 @@ function decryptObject(obj, secretKey) {
|
|
|
44
44
|
return r;
|
|
45
45
|
}
|
|
46
46
|
exports.decryptObject = decryptObject;
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Encrypts all object values (utf8 strings).
|
|
49
|
+
* Returns object with encrypted values (base64 strings).
|
|
50
|
+
*/
|
|
51
|
+
function encryptObject(obj, secretKeyBuffer) {
|
|
52
|
+
const { key, iv } = getCryptoParams(secretKeyBuffer);
|
|
49
53
|
const r = {};
|
|
50
54
|
(0, js_lib_1._stringMapEntries)(obj).forEach(([k, v]) => {
|
|
51
55
|
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
|
@@ -55,25 +59,31 @@ function encryptObject(obj, secretKey) {
|
|
|
55
59
|
}
|
|
56
60
|
exports.encryptObject = encryptObject;
|
|
57
61
|
/**
|
|
58
|
-
* Using aes-256-cbc
|
|
62
|
+
* Using aes-256-cbc.
|
|
63
|
+
*
|
|
64
|
+
* Input is base64 string.
|
|
65
|
+
* Output is utf8 string.
|
|
59
66
|
*/
|
|
60
|
-
function decryptString(str,
|
|
61
|
-
const { key, iv } = getCryptoParams(
|
|
67
|
+
function decryptString(str, secretKeyBuffer) {
|
|
68
|
+
const { key, iv } = getCryptoParams(secretKeyBuffer);
|
|
62
69
|
const decipher = crypto.createDecipheriv(algorithm, key, iv);
|
|
63
70
|
return decipher.update(str, 'base64', 'utf8') + decipher.final('utf8');
|
|
64
71
|
}
|
|
65
72
|
exports.decryptString = decryptString;
|
|
66
73
|
/**
|
|
67
|
-
* Using aes-256-cbc
|
|
74
|
+
* Using aes-256-cbc.
|
|
75
|
+
*
|
|
76
|
+
* Input is utf8 string.
|
|
77
|
+
* Output is base64 string.
|
|
68
78
|
*/
|
|
69
|
-
function encryptString(str,
|
|
70
|
-
const { key, iv } = getCryptoParams(
|
|
79
|
+
function encryptString(str, secretKeyBuffer) {
|
|
80
|
+
const { key, iv } = getCryptoParams(secretKeyBuffer);
|
|
71
81
|
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
|
72
82
|
return cipher.update(str, 'utf8', 'base64') + cipher.final('base64');
|
|
73
83
|
}
|
|
74
84
|
exports.encryptString = encryptString;
|
|
75
|
-
function getCryptoParams(
|
|
76
|
-
const key = (0, hash_util_1.
|
|
77
|
-
const iv = (0, hash_util_1.
|
|
85
|
+
function getCryptoParams(secretKeyBuffer) {
|
|
86
|
+
const key = (0, hash_util_1.sha256AsBuffer)(secretKeyBuffer);
|
|
87
|
+
const iv = (0, hash_util_1.md5AsBuffer)(Buffer.concat([secretKeyBuffer, key]));
|
|
78
88
|
return { key, iv };
|
|
79
89
|
}
|
|
@@ -48,7 +48,8 @@ function loadSecretsFromEncryptedJsonFile(filePath, secretEncryptionKey) {
|
|
|
48
48
|
let secrets;
|
|
49
49
|
if (secretEncryptionKey) {
|
|
50
50
|
const buf = fs.readFileSync(filePath);
|
|
51
|
-
const
|
|
51
|
+
const encKeyBuffer = Buffer.from(secretEncryptionKey, 'base64');
|
|
52
|
+
const plain = (0, crypto_util_1.decryptRandomIVBuffer)(buf, encKeyBuffer).toString('utf8');
|
|
52
53
|
secrets = JSON.parse(plain);
|
|
53
54
|
}
|
|
54
55
|
else {
|
|
@@ -69,7 +70,8 @@ function loadSecretsFromEncryptedJsonFileValues(filePath, secretEncryptionKey) {
|
|
|
69
70
|
(0, js_lib_1._assert)(fs.existsSync(filePath), `loadSecretsFromEncryptedJsonFileValues() cannot load from path: ${filePath}`);
|
|
70
71
|
let secrets = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
71
72
|
if (secretEncryptionKey) {
|
|
72
|
-
|
|
73
|
+
const encKeyBuffer = Buffer.from(secretEncryptionKey, 'base64');
|
|
74
|
+
secrets = (0, crypto_util_1.decryptObject)(secrets, encKeyBuffer);
|
|
73
75
|
}
|
|
74
76
|
Object.entries(secrets).forEach(([k, v]) => (secretMap[k.toUpperCase()] = v));
|
|
75
77
|
loaded = true;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
[](https://codeclimate.com/github/NaturalCycles/nodejs-lib/maintainability)
|
|
9
9
|
[](https://codeclimate.com/github/NaturalCycles/nodejs-lib/test_coverage)
|
|
10
10
|
[](https://github.com/prettier/prettier)
|
|
11
|
-
[](https://github.com/NaturalCycles/nodejs-lib/actions)
|
|
12
12
|
|
|
13
13
|
# [Documentation](https://naturalcycles.github.io/nodejs-lib/)
|
|
14
14
|
|
|
@@ -6,9 +6,9 @@ import { runScript } from '../script/runScript'
|
|
|
6
6
|
import { DecryptCLIOptions, secretsDecrypt } from '../secret/secrets-decrypt.util'
|
|
7
7
|
|
|
8
8
|
runScript(() => {
|
|
9
|
-
const { dir, file,
|
|
9
|
+
const { dir, file, encKeyBuffer, del, jsonMode } = getDecryptCLIOptions()
|
|
10
10
|
|
|
11
|
-
secretsDecrypt(dir, file,
|
|
11
|
+
secretsDecrypt(dir, file, encKeyBuffer, del, jsonMode)
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
function getDecryptCLIOptions(): DecryptCLIOptions {
|
|
@@ -27,7 +27,7 @@ function getDecryptCLIOptions(): DecryptCLIOptions {
|
|
|
27
27
|
},
|
|
28
28
|
encKey: {
|
|
29
29
|
type: 'string',
|
|
30
|
-
desc: 'Encryption key',
|
|
30
|
+
desc: 'Encryption key as base64 encoded string',
|
|
31
31
|
// demandOption: true,
|
|
32
32
|
// default: process.env.SECRET_ENCRYPTION_KEY!,
|
|
33
33
|
},
|
|
@@ -63,6 +63,8 @@ function getDecryptCLIOptions(): DecryptCLIOptions {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
const encKeyBuffer = Buffer.from(encKey, 'base64')
|
|
67
|
+
|
|
66
68
|
// `as any` because @types/yargs can't handle string[] type properly
|
|
67
|
-
return { dir: dir as any, file,
|
|
69
|
+
return { dir: dir as any, file, encKeyBuffer, del, jsonMode }
|
|
68
70
|
}
|
|
@@ -6,9 +6,9 @@ import { runScript } from '../script/runScript'
|
|
|
6
6
|
import { EncryptCLIOptions, secretsEncrypt } from '../secret/secrets-encrypt.util'
|
|
7
7
|
|
|
8
8
|
runScript(() => {
|
|
9
|
-
const { pattern, file,
|
|
9
|
+
const { pattern, file, encKeyBuffer, del, jsonMode } = getEncryptCLIOptions()
|
|
10
10
|
|
|
11
|
-
secretsEncrypt(pattern, file,
|
|
11
|
+
secretsEncrypt(pattern, file, encKeyBuffer, del, jsonMode)
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
function getEncryptCLIOptions(): EncryptCLIOptions {
|
|
@@ -18,7 +18,7 @@ function getEncryptCLIOptions(): EncryptCLIOptions {
|
|
|
18
18
|
pattern: {
|
|
19
19
|
type: 'string',
|
|
20
20
|
array: true,
|
|
21
|
-
desc: 'Globby pattern for secrets. Can be
|
|
21
|
+
desc: 'Globby pattern for secrets. Can be multiple.',
|
|
22
22
|
// demandOption: true,
|
|
23
23
|
default: './secret/**',
|
|
24
24
|
},
|
|
@@ -28,7 +28,7 @@ function getEncryptCLIOptions(): EncryptCLIOptions {
|
|
|
28
28
|
},
|
|
29
29
|
encKey: {
|
|
30
30
|
type: 'string',
|
|
31
|
-
desc: 'Encryption key',
|
|
31
|
+
desc: 'Encryption key as base64 encoded string',
|
|
32
32
|
// demandOption: true,
|
|
33
33
|
// default: process.env.SECRET_ENCRYPTION_KEY!,
|
|
34
34
|
},
|
|
@@ -65,6 +65,8 @@ function getEncryptCLIOptions(): EncryptCLIOptions {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
const encKeyBuffer = Buffer.from(encKey, 'base64')
|
|
69
|
+
|
|
68
70
|
// `as any` because @types/yargs can't handle string[] type properly
|
|
69
|
-
return { pattern: pattern as any, file,
|
|
71
|
+
return { pattern: pattern as any, file, encKeyBuffer, del, jsonMode }
|
|
70
72
|
}
|
package/src/fs/fs.util.ts
CHANGED
|
@@ -126,23 +126,28 @@ export function _outputFileSync(filePath: string, data: string | Buffer): void {
|
|
|
126
126
|
fs.writeFileSync(filePath, data)
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
function stringify(data: any, opt?: JsonOptions): string {
|
|
130
|
+
// If pretty-printing is enabled (spaces) - also add a newline at the end (to match our prettier config)
|
|
131
|
+
return JSON.stringify(data, null, opt?.spaces) + (opt?.spaces ? '\n' : '')
|
|
132
|
+
}
|
|
133
|
+
|
|
129
134
|
export async function _writeJson(filePath: string, data: any, opt?: JsonOptions): Promise<void> {
|
|
130
|
-
const str =
|
|
135
|
+
const str = stringify(data, opt)
|
|
131
136
|
await fsp.writeFile(filePath, str)
|
|
132
137
|
}
|
|
133
138
|
|
|
134
139
|
export function _writeJsonSync(filePath: string, data: any, opt?: JsonOptions): void {
|
|
135
|
-
const str =
|
|
140
|
+
const str = stringify(data, opt)
|
|
136
141
|
fs.writeFileSync(filePath, str)
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
export async function _outputJson(filePath: string, data: any, opt?: JsonOptions): Promise<void> {
|
|
140
|
-
const str =
|
|
145
|
+
const str = stringify(data, opt)
|
|
141
146
|
await _outputFile(filePath, str)
|
|
142
147
|
}
|
|
143
148
|
|
|
144
149
|
export function _outputJsonSync(filePath: string, data: any, opt?: JsonOptions): void {
|
|
145
|
-
const str =
|
|
150
|
+
const str = stringify(data, opt)
|
|
146
151
|
_outputFileSync(filePath, str)
|
|
147
152
|
}
|
|
148
153
|
|
|
@@ -8,14 +8,17 @@ import { decryptObject, decryptRandomIVBuffer } from '../security/crypto.util'
|
|
|
8
8
|
export interface DecryptCLIOptions {
|
|
9
9
|
dir: string[]
|
|
10
10
|
file?: string
|
|
11
|
-
|
|
11
|
+
encKeyBuffer: Buffer
|
|
12
12
|
del?: boolean
|
|
13
13
|
jsonMode?: boolean
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// Debug it like this:
|
|
17
|
-
// yarn tsn ./src/bin/secrets-decrypt.ts --file ./src/test/secrets2.json --jsonMode --encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
18
17
|
// yarn tsn ./src/bin/secrets-encrypt.ts --file ./src/test/secrets2.plain.json --jsonMode --encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
18
|
+
// yarn tsn ./src/bin/secrets-decrypt.ts --file ./src/test/secrets2.json --jsonMode --encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
19
|
+
|
|
20
|
+
// yarn tsn ./src/bin/secrets-encrypt.ts --file ./src/test/secrets.json -encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
21
|
+
// yarn tsn ./src/bin/secrets-decrypt.ts --file ./src/test/secrets.json.enc -encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* Decrypts all files in given directory (*.enc), saves decrypted versions without ending `.enc`.
|
|
@@ -24,7 +27,7 @@ export interface DecryptCLIOptions {
|
|
|
24
27
|
export function secretsDecrypt(
|
|
25
28
|
dir: string[],
|
|
26
29
|
file: string | undefined,
|
|
27
|
-
|
|
30
|
+
encKeyBuffer: Buffer,
|
|
28
31
|
del = false,
|
|
29
32
|
jsonMode = false,
|
|
30
33
|
): void {
|
|
@@ -44,12 +47,12 @@ export function secretsDecrypt(
|
|
|
44
47
|
)
|
|
45
48
|
plainFilename = filename.replace('.json', '.plain.json')
|
|
46
49
|
|
|
47
|
-
const json = decryptObject(_readJsonSync(filename),
|
|
50
|
+
const json = decryptObject(_readJsonSync(filename), encKeyBuffer)
|
|
48
51
|
|
|
49
52
|
_writeJsonSync(plainFilename, json, { spaces: 2 })
|
|
50
53
|
} else {
|
|
51
54
|
const enc = fs.readFileSync(filename)
|
|
52
|
-
const plain = decryptRandomIVBuffer(enc,
|
|
55
|
+
const plain = decryptRandomIVBuffer(enc, encKeyBuffer)
|
|
53
56
|
plainFilename = filename.slice(0, filename.length - '.enc'.length)
|
|
54
57
|
fs.writeFileSync(plainFilename, plain)
|
|
55
58
|
}
|
|
@@ -8,7 +8,7 @@ import { encryptObject, encryptRandomIVBuffer } from '../security/crypto.util'
|
|
|
8
8
|
export interface EncryptCLIOptions {
|
|
9
9
|
pattern: string[]
|
|
10
10
|
file?: string
|
|
11
|
-
|
|
11
|
+
encKeyBuffer: Buffer
|
|
12
12
|
del?: boolean
|
|
13
13
|
jsonMode?: boolean
|
|
14
14
|
}
|
|
@@ -20,7 +20,7 @@ export interface EncryptCLIOptions {
|
|
|
20
20
|
export function secretsEncrypt(
|
|
21
21
|
pattern: string[],
|
|
22
22
|
file: string | undefined,
|
|
23
|
-
|
|
23
|
+
encKeyBuffer: Buffer,
|
|
24
24
|
del = false,
|
|
25
25
|
jsonMode = false,
|
|
26
26
|
): void {
|
|
@@ -41,12 +41,12 @@ export function secretsEncrypt(
|
|
|
41
41
|
)
|
|
42
42
|
encFilename = filename.replace('.plain', '')
|
|
43
43
|
|
|
44
|
-
const json = encryptObject(_readJsonSync(filename),
|
|
44
|
+
const json = encryptObject(_readJsonSync(filename), encKeyBuffer)
|
|
45
45
|
|
|
46
46
|
_writeJsonSync(encFilename, json, { spaces: 2 })
|
|
47
47
|
} else {
|
|
48
48
|
const plain = fs.readFileSync(filename)
|
|
49
|
-
const enc = encryptRandomIVBuffer(plain,
|
|
49
|
+
const enc = encryptRandomIVBuffer(plain, encKeyBuffer)
|
|
50
50
|
encFilename = `${filename}.enc`
|
|
51
51
|
fs.writeFileSync(encFilename, enc)
|
|
52
52
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as crypto from 'node:crypto'
|
|
2
2
|
import { _stringMapEntries, Base64String, StringMap } from '@naturalcycles/js-lib'
|
|
3
|
-
import {
|
|
3
|
+
import { md5AsBuffer, sha256AsBuffer } from './hash.util'
|
|
4
4
|
|
|
5
5
|
const algorithm = 'aes-256-cbc'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Using aes-256-cbc
|
|
8
|
+
* Using aes-256-cbc.
|
|
9
9
|
*/
|
|
10
|
-
export function encryptRandomIVBuffer(input: Buffer,
|
|
11
|
-
//
|
|
12
|
-
const key =
|
|
10
|
+
export function encryptRandomIVBuffer(input: Buffer, secretKeyBuffer: Buffer): Buffer {
|
|
11
|
+
// sha256 to match aes-256 key length
|
|
12
|
+
const key = sha256AsBuffer(secretKeyBuffer)
|
|
13
13
|
|
|
14
14
|
// Random iv to achieve non-deterministic encryption (but deterministic decryption)
|
|
15
15
|
const iv = crypto.randomBytes(16)
|
|
@@ -19,11 +19,11 @@ export function encryptRandomIVBuffer(input: Buffer, secretKeyBase64: Base64Stri
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Using aes-256-cbc
|
|
22
|
+
* Using aes-256-cbc.
|
|
23
23
|
*/
|
|
24
|
-
export function decryptRandomIVBuffer(input: Buffer,
|
|
25
|
-
//
|
|
26
|
-
const key =
|
|
24
|
+
export function decryptRandomIVBuffer(input: Buffer, secretKeyBuffer: Buffer): Buffer {
|
|
25
|
+
// sha256 to match aes-256 key length
|
|
26
|
+
const key = sha256AsBuffer(secretKeyBuffer)
|
|
27
27
|
|
|
28
28
|
// iv is first 16 bytes of encrypted buffer, the rest is payload
|
|
29
29
|
const iv = input.subarray(0, 16)
|
|
@@ -35,11 +35,11 @@ export function decryptRandomIVBuffer(input: Buffer, secretKeyBase64: Base64Stri
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Decrypts all object values.
|
|
39
|
-
* Returns object with decrypted values.
|
|
38
|
+
* Decrypts all object values (base64 strings).
|
|
39
|
+
* Returns object with decrypted values (utf8 strings).
|
|
40
40
|
*/
|
|
41
|
-
export function decryptObject(obj: StringMap<Base64String>,
|
|
42
|
-
const { key, iv } = getCryptoParams(
|
|
41
|
+
export function decryptObject(obj: StringMap<Base64String>, secretKeyBuffer: Buffer): StringMap {
|
|
42
|
+
const { key, iv } = getCryptoParams(secretKeyBuffer)
|
|
43
43
|
|
|
44
44
|
const r: StringMap = {}
|
|
45
45
|
_stringMapEntries(obj).forEach(([k, v]) => {
|
|
@@ -49,8 +49,12 @@ export function decryptObject(obj: StringMap<Base64String>, secretKey: string):
|
|
|
49
49
|
return r
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Encrypts all object values (utf8 strings).
|
|
54
|
+
* Returns object with encrypted values (base64 strings).
|
|
55
|
+
*/
|
|
56
|
+
export function encryptObject(obj: StringMap, secretKeyBuffer: Buffer): StringMap<Base64String> {
|
|
57
|
+
const { key, iv } = getCryptoParams(secretKeyBuffer)
|
|
54
58
|
|
|
55
59
|
const r: StringMap = {}
|
|
56
60
|
_stringMapEntries(obj).forEach(([k, v]) => {
|
|
@@ -61,25 +65,31 @@ export function encryptObject(obj: StringMap, secretKey: string): StringMap<Base
|
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
/**
|
|
64
|
-
* Using aes-256-cbc
|
|
68
|
+
* Using aes-256-cbc.
|
|
69
|
+
*
|
|
70
|
+
* Input is base64 string.
|
|
71
|
+
* Output is utf8 string.
|
|
65
72
|
*/
|
|
66
|
-
export function decryptString(str: Base64String,
|
|
67
|
-
const { key, iv } = getCryptoParams(
|
|
73
|
+
export function decryptString(str: Base64String, secretKeyBuffer: Buffer): string {
|
|
74
|
+
const { key, iv } = getCryptoParams(secretKeyBuffer)
|
|
68
75
|
const decipher = crypto.createDecipheriv(algorithm, key, iv)
|
|
69
76
|
return decipher.update(str, 'base64', 'utf8') + decipher.final('utf8')
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
/**
|
|
73
|
-
* Using aes-256-cbc
|
|
80
|
+
* Using aes-256-cbc.
|
|
81
|
+
*
|
|
82
|
+
* Input is utf8 string.
|
|
83
|
+
* Output is base64 string.
|
|
74
84
|
*/
|
|
75
|
-
export function encryptString(str: string,
|
|
76
|
-
const { key, iv } = getCryptoParams(
|
|
85
|
+
export function encryptString(str: string, secretKeyBuffer: Buffer): Base64String {
|
|
86
|
+
const { key, iv } = getCryptoParams(secretKeyBuffer)
|
|
77
87
|
const cipher = crypto.createCipheriv(algorithm, key, iv)
|
|
78
88
|
return cipher.update(str, 'utf8', 'base64') + cipher.final('base64')
|
|
79
89
|
}
|
|
80
90
|
|
|
81
|
-
function getCryptoParams(
|
|
82
|
-
const key =
|
|
83
|
-
const iv =
|
|
91
|
+
function getCryptoParams(secretKeyBuffer: Buffer): { key: Buffer; iv: Buffer } {
|
|
92
|
+
const key = sha256AsBuffer(secretKeyBuffer)
|
|
93
|
+
const iv = md5AsBuffer(Buffer.concat([secretKeyBuffer, key]))
|
|
84
94
|
return { key, iv }
|
|
85
95
|
}
|
|
@@ -62,7 +62,8 @@ export function loadSecretsFromEncryptedJsonFile(
|
|
|
62
62
|
|
|
63
63
|
if (secretEncryptionKey) {
|
|
64
64
|
const buf = fs.readFileSync(filePath)
|
|
65
|
-
const
|
|
65
|
+
const encKeyBuffer = Buffer.from(secretEncryptionKey, 'base64')
|
|
66
|
+
const plain = decryptRandomIVBuffer(buf, encKeyBuffer).toString('utf8')
|
|
66
67
|
secrets = JSON.parse(plain)
|
|
67
68
|
} else {
|
|
68
69
|
secrets = JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
@@ -94,7 +95,8 @@ export function loadSecretsFromEncryptedJsonFileValues(
|
|
|
94
95
|
let secrets: StringMap = JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
95
96
|
|
|
96
97
|
if (secretEncryptionKey) {
|
|
97
|
-
|
|
98
|
+
const encKeyBuffer = Buffer.from(secretEncryptionKey, 'base64')
|
|
99
|
+
secrets = decryptObject(secrets, encKeyBuffer)
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
Object.entries(secrets).forEach(([k, v]) => (secretMap[k.toUpperCase()] = v))
|