@naturalcycles/nodejs-lib 12.67.0 → 12.68.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/index.d.ts CHANGED
@@ -9,6 +9,7 @@ import { GetGotOptions } from './got/got.model';
9
9
  export * from './infra/process.util';
10
10
  import { Debug, IDebug, IDebugger } from './log/debug';
11
11
  export * from './security/hash.util';
12
+ export * from './security/crypto.util';
12
13
  export * from './security/id.util';
13
14
  export * from './security/secret.util';
14
15
  export * from './colors/colors';
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ tslib_1.__exportStar(require("./infra/process.util"), exports);
16
16
  const debug_1 = require("./log/debug");
17
17
  Object.defineProperty(exports, "Debug", { enumerable: true, get: function () { return debug_1.Debug; } });
18
18
  tslib_1.__exportStar(require("./security/hash.util"), exports);
19
+ tslib_1.__exportStar(require("./security/crypto.util"), exports);
19
20
  tslib_1.__exportStar(require("./security/id.util"), exports);
20
21
  tslib_1.__exportStar(require("./security/secret.util"), exports);
21
22
  tslib_1.__exportStar(require("./colors/colors"), exports);
@@ -24,10 +24,7 @@ function secretsDecrypt(dir, file, encKey, del = false, jsonMode = false) {
24
24
  (0, js_lib_1._assert)(filename.endsWith('.json'), `${path.basename(filename)} MUST end with '.json'`);
25
25
  (0, js_lib_1._assert)(!filename.endsWith('.plain.json'), `${path.basename(filename)} MUST NOT end with '.plain.json'`);
26
26
  plainFilename = filename.replace('.json', '.plain.json');
27
- const json = JSON.parse(fs.readFileSync(filename, 'utf8'));
28
- (0, js_lib_1._stringMapEntries)(json).forEach(([k, v]) => {
29
- json[k] = (0, crypto_util_1.decryptString)(v, encKey);
30
- });
27
+ const json = (0, crypto_util_1.decryptObject)(JSON.parse(fs.readFileSync(filename, 'utf8')), encKey);
31
28
  fs.writeFileSync(plainFilename, JSON.stringify(json, null, 2));
32
29
  }
33
30
  else {
@@ -24,10 +24,7 @@ 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 = JSON.parse(fs.readFileSync(filename, 'utf8'));
28
- (0, js_lib_1._stringMapEntries)(json).forEach(([k, plain]) => {
29
- json[k] = (0, crypto_util_1.encryptString)(plain, encKey);
30
- });
27
+ const json = (0, crypto_util_1.encryptObject)(JSON.parse(fs.readFileSync(filename, 'utf8')), encKey);
31
28
  fs.writeFileSync(encFilename, JSON.stringify(json, null, 2));
32
29
  }
33
30
  else {
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ import { StringMap } from '@naturalcycles/js-lib';
2
3
  /**
3
4
  * Using aes-256-cbc
4
5
  */
@@ -7,6 +8,12 @@ export declare function encryptRandomIVBuffer(input: Buffer, secretKeyBase64: st
7
8
  * Using aes-256-cbc
8
9
  */
9
10
  export declare function decryptRandomIVBuffer(input: Buffer, secretKeyBase64: string): Buffer;
11
+ /**
12
+ * Decrypts all object values.
13
+ * Returns object with decrypted values.
14
+ */
15
+ export declare function decryptObject(obj: StringMap, secretKey: string): StringMap;
16
+ export declare function encryptObject(obj: StringMap, secretKey: string): StringMap;
10
17
  /**
11
18
  * Using aes-256-cbc
12
19
  */
@@ -1,17 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.encryptString = exports.decryptString = exports.decryptRandomIVBuffer = exports.encryptRandomIVBuffer = void 0;
3
+ exports.encryptString = exports.decryptString = exports.encryptObject = exports.decryptObject = exports.decryptRandomIVBuffer = exports.encryptRandomIVBuffer = void 0;
4
4
  const crypto = require("crypto");
5
+ const js_lib_1 = require("@naturalcycles/js-lib");
5
6
  const hash_util_1 = require("./hash.util");
6
7
  const algorithm = 'aes-256-cbc';
7
8
  /**
8
9
  * Using aes-256-cbc
9
10
  */
10
11
  function encryptRandomIVBuffer(input, secretKeyBase64) {
11
- const key = aes256Key(secretKeyBase64);
12
+ // md5 to match aes-256 key length of 32 bytes
13
+ const key = (0, hash_util_1.md5)(Buffer.from(secretKeyBase64, 'base64'));
12
14
  // Random iv to achieve non-deterministic encryption (but deterministic decryption)
13
- // const iv = await randomBytes(16)
14
- const iv = crypto.randomBytes(16); // use sync method here for speed
15
+ const iv = crypto.randomBytes(16);
15
16
  const cipher = crypto.createCipheriv(algorithm, key, iv);
16
17
  return Buffer.concat([iv, cipher.update(input), cipher.final()]);
17
18
  }
@@ -20,7 +21,8 @@ exports.encryptRandomIVBuffer = encryptRandomIVBuffer;
20
21
  * Using aes-256-cbc
21
22
  */
22
23
  function decryptRandomIVBuffer(input, secretKeyBase64) {
23
- const key = aes256Key(secretKeyBase64);
24
+ // md5 to match aes-256 key length of 32 bytes
25
+ const key = (0, hash_util_1.md5)(Buffer.from(secretKeyBase64, 'base64'));
24
26
  // iv is first 16 bytes of encrypted buffer, the rest is payload
25
27
  const iv = input.slice(0, 16);
26
28
  const payload = input.slice(16);
@@ -28,32 +30,50 @@ function decryptRandomIVBuffer(input, secretKeyBase64) {
28
30
  return Buffer.concat([decipher.update(payload), decipher.final()]);
29
31
  }
30
32
  exports.decryptRandomIVBuffer = decryptRandomIVBuffer;
33
+ /**
34
+ * Decrypts all object values.
35
+ * Returns object with decrypted values.
36
+ */
37
+ function decryptObject(obj, secretKey) {
38
+ const { key, iv } = getCryptoParams(secretKey);
39
+ const r = {};
40
+ (0, js_lib_1._stringMapEntries)(obj).forEach(([k, v]) => {
41
+ const decipher = crypto.createDecipheriv(algorithm, key, iv);
42
+ r[k] = decipher.update(v, 'base64', 'utf8') + decipher.final('utf8');
43
+ });
44
+ return r;
45
+ }
46
+ exports.decryptObject = decryptObject;
47
+ function encryptObject(obj, secretKey) {
48
+ const { key, iv } = getCryptoParams(secretKey);
49
+ const r = {};
50
+ (0, js_lib_1._stringMapEntries)(obj).forEach(([k, v]) => {
51
+ const cipher = crypto.createCipheriv(algorithm, key, iv);
52
+ r[k] = cipher.update(v, 'utf8', 'base64') + cipher.final('base64');
53
+ });
54
+ return r;
55
+ }
56
+ exports.encryptObject = encryptObject;
31
57
  /**
32
58
  * Using aes-256-cbc
33
59
  */
34
60
  function decryptString(str, secretKey) {
35
- const { algorithm, key, iv } = getCryptoParams(secretKey);
61
+ const { key, iv } = getCryptoParams(secretKey);
36
62
  const decipher = crypto.createDecipheriv(algorithm, key, iv);
37
- let decrypted = decipher.update(str, 'base64', 'utf8');
38
- return (decrypted += decipher.final('utf8'));
63
+ return decipher.update(str, 'base64', 'utf8') + decipher.final('utf8');
39
64
  }
40
65
  exports.decryptString = decryptString;
41
66
  /**
42
67
  * Using aes-256-cbc
43
68
  */
44
69
  function encryptString(str, secretKey) {
45
- const { algorithm, key, iv } = getCryptoParams(secretKey);
70
+ const { key, iv } = getCryptoParams(secretKey);
46
71
  const cipher = crypto.createCipheriv(algorithm, key, iv);
47
- let encrypted = cipher.update(str, 'utf8', 'base64');
48
- return (encrypted += cipher.final('base64'));
72
+ return cipher.update(str, 'utf8', 'base64') + cipher.final('base64');
49
73
  }
50
74
  exports.encryptString = encryptString;
51
75
  function getCryptoParams(secretKey) {
52
76
  const key = (0, hash_util_1.md5)(secretKey);
53
77
  const iv = (0, hash_util_1.md5)(secretKey + key).slice(0, 16);
54
- return { algorithm, key, iv };
55
- }
56
- function aes256Key(secretKeyBase64) {
57
- // md5 to match aes-256 key length of 32 bytes
58
- return (0, hash_util_1.md5)(Buffer.from(secretKeyBase64, 'base64'));
78
+ return { key, iv };
59
79
  }
@@ -69,11 +69,9 @@ exports.loadSecretsFromEncryptedJsonFile = loadSecretsFromEncryptedJsonFile;
69
69
  */
70
70
  function loadSecretsFromEncryptedJsonFileValues(filePath, secretEncryptionKey) {
71
71
  (0, js_lib_1._assert)(fs.existsSync(filePath), `loadSecretsFromEncryptedJsonFileValues() cannot load from path: ${filePath}`);
72
- const secrets = JSON.parse(fs.readFileSync(filePath, 'utf8'));
72
+ let secrets = JSON.parse(fs.readFileSync(filePath, 'utf8'));
73
73
  if (secretEncryptionKey) {
74
- (0, js_lib_1._stringMapEntries)(secrets).forEach(([k, enc]) => {
75
- secrets[k] = (0, crypto_util_1.decryptString)(enc, secretEncryptionKey);
76
- });
74
+ secrets = (0, crypto_util_1.decryptObject)(secrets, secretEncryptionKey);
77
75
  }
78
76
  Object.entries(secrets).forEach(([k, v]) => (secretMap[k.toUpperCase()] = v));
79
77
  loaded = true;
@@ -1,7 +1,6 @@
1
1
  import { MemoCache } from '@naturalcycles/js-lib';
2
2
  import LRUCache = require('lru-cache');
3
- export interface LRUMemoCacheOptions<KEY, VALUE> extends Partial<LRUCache.Options<KEY, VALUE>> {
4
- }
3
+ export declare type LRUMemoCacheOptions<KEY, VALUE> = Partial<LRUCache.Options<KEY, VALUE>>;
5
4
  /**
6
5
  * @example
7
6
  * Use it like this:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
- "version": "12.67.0",
3
+ "version": "12.68.1",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "docs-serve": "vuepress dev docs",
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ import { GetGotOptions } from './got/got.model'
9
9
  export * from './infra/process.util'
10
10
  import { Debug, IDebug, IDebugger } from './log/debug'
11
11
  export * from './security/hash.util'
12
+ export * from './security/crypto.util'
12
13
  export * from './security/id.util'
13
14
  export * from './security/secret.util'
14
15
  export * from './colors/colors'
@@ -1,9 +1,9 @@
1
1
  import * as path from 'path'
2
- import { _assert, _stringMapEntries, StringMap } from '@naturalcycles/js-lib'
2
+ import { _assert } from '@naturalcycles/js-lib'
3
3
  import * as fs from 'fs-extra'
4
4
  import globby = require('globby')
5
5
  import { dimGrey, yellow } from '../colors'
6
- import { decryptRandomIVBuffer, decryptString } from '../security/crypto.util'
6
+ import { decryptObject, decryptRandomIVBuffer } from '../security/crypto.util'
7
7
 
8
8
  export interface DecryptCLIOptions {
9
9
  dir: string[]
@@ -44,10 +44,7 @@ export function secretsDecrypt(
44
44
  )
45
45
  plainFilename = filename.replace('.json', '.plain.json')
46
46
 
47
- const json: StringMap = JSON.parse(fs.readFileSync(filename, 'utf8'))
48
- _stringMapEntries(json).forEach(([k, v]) => {
49
- json[k] = decryptString(v, encKey)
50
- })
47
+ const json = decryptObject(JSON.parse(fs.readFileSync(filename, 'utf8')), encKey)
51
48
 
52
49
  fs.writeFileSync(plainFilename, JSON.stringify(json, null, 2))
53
50
  } else {
@@ -1,9 +1,9 @@
1
1
  import * as path from 'path'
2
- import { _assert, _stringMapEntries, StringMap } from '@naturalcycles/js-lib'
2
+ import { _assert } from '@naturalcycles/js-lib'
3
3
  import * as fs from 'fs-extra'
4
4
  import globby = require('globby')
5
5
  import { dimGrey, yellow } from '../colors'
6
- import { encryptRandomIVBuffer, encryptString } from '../security/crypto.util'
6
+ import { encryptObject, encryptRandomIVBuffer } from '../security/crypto.util'
7
7
 
8
8
  export interface EncryptCLIOptions {
9
9
  pattern: string[]
@@ -41,11 +41,7 @@ export function secretsEncrypt(
41
41
  )
42
42
  encFilename = filename.replace('.plain', '')
43
43
 
44
- const json: StringMap = JSON.parse(fs.readFileSync(filename, 'utf8'))
45
-
46
- _stringMapEntries(json).forEach(([k, plain]) => {
47
- json[k] = encryptString(plain, encKey)
48
- })
44
+ const json = encryptObject(JSON.parse(fs.readFileSync(filename, 'utf8')), encKey)
49
45
 
50
46
  fs.writeFileSync(encFilename, JSON.stringify(json, null, 2))
51
47
  } else {
@@ -1,4 +1,5 @@
1
1
  import * as crypto from 'crypto'
2
+ import { _stringMapEntries, StringMap } from '@naturalcycles/js-lib'
2
3
  import { md5 } from './hash.util'
3
4
 
4
5
  const algorithm = 'aes-256-cbc'
@@ -7,12 +8,11 @@ const algorithm = 'aes-256-cbc'
7
8
  * Using aes-256-cbc
8
9
  */
9
10
  export function encryptRandomIVBuffer(input: Buffer, secretKeyBase64: string): Buffer {
10
- const key = aes256Key(secretKeyBase64)
11
+ // md5 to match aes-256 key length of 32 bytes
12
+ const key = md5(Buffer.from(secretKeyBase64, 'base64'))
11
13
 
12
14
  // Random iv to achieve non-deterministic encryption (but deterministic decryption)
13
- // const iv = await randomBytes(16)
14
- const iv = crypto.randomBytes(16) // use sync method here for speed
15
-
15
+ const iv = crypto.randomBytes(16)
16
16
  const cipher = crypto.createCipheriv(algorithm, key, iv)
17
17
 
18
18
  return Buffer.concat([iv, cipher.update(input), cipher.final()])
@@ -22,7 +22,8 @@ export function encryptRandomIVBuffer(input: Buffer, secretKeyBase64: string): B
22
22
  * Using aes-256-cbc
23
23
  */
24
24
  export function decryptRandomIVBuffer(input: Buffer, secretKeyBase64: string): Buffer {
25
- const key = aes256Key(secretKeyBase64)
25
+ // md5 to match aes-256 key length of 32 bytes
26
+ const key = md5(Buffer.from(secretKeyBase64, 'base64'))
26
27
 
27
28
  // iv is first 16 bytes of encrypted buffer, the rest is payload
28
29
  const iv = input.slice(0, 16)
@@ -33,33 +34,52 @@ export function decryptRandomIVBuffer(input: Buffer, secretKeyBase64: string): B
33
34
  return Buffer.concat([decipher.update(payload), decipher.final()])
34
35
  }
35
36
 
37
+ /**
38
+ * Decrypts all object values.
39
+ * Returns object with decrypted values.
40
+ */
41
+ export function decryptObject(obj: StringMap, secretKey: string): StringMap {
42
+ const { key, iv } = getCryptoParams(secretKey)
43
+
44
+ const r: StringMap = {}
45
+ _stringMapEntries(obj).forEach(([k, v]) => {
46
+ const decipher = crypto.createDecipheriv(algorithm, key, iv)
47
+ r[k] = decipher.update(v, 'base64', 'utf8') + decipher.final('utf8')
48
+ })
49
+ return r
50
+ }
51
+
52
+ export function encryptObject(obj: StringMap, secretKey: string): StringMap {
53
+ const { key, iv } = getCryptoParams(secretKey)
54
+
55
+ const r: StringMap = {}
56
+ _stringMapEntries(obj).forEach(([k, v]) => {
57
+ const cipher = crypto.createCipheriv(algorithm, key, iv)
58
+ r[k] = cipher.update(v, 'utf8', 'base64') + cipher.final('base64')
59
+ })
60
+ return r
61
+ }
62
+
36
63
  /**
37
64
  * Using aes-256-cbc
38
65
  */
39
66
  export function decryptString(str: string, secretKey: string): string {
40
- const { algorithm, key, iv } = getCryptoParams(secretKey)
67
+ const { key, iv } = getCryptoParams(secretKey)
41
68
  const decipher = crypto.createDecipheriv(algorithm, key, iv)
42
- let decrypted = decipher.update(str, 'base64', 'utf8')
43
- return (decrypted += decipher.final('utf8'))
69
+ return decipher.update(str, 'base64', 'utf8') + decipher.final('utf8')
44
70
  }
45
71
 
46
72
  /**
47
73
  * Using aes-256-cbc
48
74
  */
49
75
  export function encryptString(str: string, secretKey: string): string {
50
- const { algorithm, key, iv } = getCryptoParams(secretKey)
76
+ const { key, iv } = getCryptoParams(secretKey)
51
77
  const cipher = crypto.createCipheriv(algorithm, key, iv)
52
- let encrypted = cipher.update(str, 'utf8', 'base64')
53
- return (encrypted += cipher.final('base64'))
78
+ return cipher.update(str, 'utf8', 'base64') + cipher.final('base64')
54
79
  }
55
80
 
56
- function getCryptoParams(secretKey: string): { algorithm: string; key: string; iv: string } {
81
+ function getCryptoParams(secretKey: string): { key: string; iv: string } {
57
82
  const key = md5(secretKey)
58
83
  const iv = md5(secretKey + key).slice(0, 16)
59
- return { algorithm, key, iv }
60
- }
61
-
62
- function aes256Key(secretKeyBase64: string): string {
63
- // md5 to match aes-256 key length of 32 bytes
64
- return md5(Buffer.from(secretKeyBase64, 'base64'))
84
+ return { key, iv }
65
85
  }
@@ -1,7 +1,7 @@
1
1
  import * as fs from 'fs'
2
- import { _assert, _stringMapEntries, StringMap } from '@naturalcycles/js-lib'
2
+ import { _assert, StringMap } from '@naturalcycles/js-lib'
3
3
  import { base64ToString } from '..'
4
- import { decryptRandomIVBuffer, decryptString } from './crypto.util'
4
+ import { decryptObject, decryptRandomIVBuffer } from './crypto.util'
5
5
 
6
6
  let loaded = false
7
7
 
@@ -93,12 +93,10 @@ export function loadSecretsFromEncryptedJsonFileValues(
93
93
  `loadSecretsFromEncryptedJsonFileValues() cannot load from path: ${filePath}`,
94
94
  )
95
95
 
96
- const secrets: StringMap = JSON.parse(fs.readFileSync(filePath, 'utf8'))
96
+ let secrets: StringMap = JSON.parse(fs.readFileSync(filePath, 'utf8'))
97
97
 
98
98
  if (secretEncryptionKey) {
99
- _stringMapEntries(secrets).forEach(([k, enc]) => {
100
- secrets[k] = decryptString(enc, secretEncryptionKey)
101
- })
99
+ secrets = decryptObject(secrets, secretEncryptionKey)
102
100
  }
103
101
 
104
102
  Object.entries(secrets).forEach(([k, v]) => (secretMap[k.toUpperCase()] = v))
@@ -2,7 +2,7 @@ import { MemoCache } from '@naturalcycles/js-lib'
2
2
  import LRUCache = require('lru-cache')
3
3
 
4
4
  // Partial, to be able to provide default `max`
5
- export interface LRUMemoCacheOptions<KEY, VALUE> extends Partial<LRUCache.Options<KEY, VALUE>> {}
5
+ export type LRUMemoCacheOptions<KEY, VALUE> = Partial<LRUCache.Options<KEY, VALUE>>
6
6
 
7
7
  /**
8
8
  * @example