@naturalcycles/nodejs-lib 12.66.0 → 12.67.0

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.
@@ -6,18 +6,22 @@ const colors_1 = require("../colors");
6
6
  const script_1 = require("../script");
7
7
  const secrets_decrypt_util_1 = require("../secret/secrets-decrypt.util");
8
8
  (0, script_1.runScript)(() => {
9
- const { dir, encKey, del } = getDecryptCLIOptions();
10
- (0, secrets_decrypt_util_1.secretsDecrypt)(dir, encKey, del);
9
+ const { dir, file, encKey, del, jsonMode } = getDecryptCLIOptions();
10
+ (0, secrets_decrypt_util_1.secretsDecrypt)(dir, file, encKey, del, jsonMode);
11
11
  });
12
12
  function getDecryptCLIOptions() {
13
13
  require('dotenv').config();
14
- let { dir, encKey, encKeyVar, del } = yargs.options({
14
+ let { dir, file, encKey, encKeyVar, del, jsonMode } = yargs.options({
15
15
  dir: {
16
16
  type: 'array',
17
17
  desc: 'Directory with secrets. Can be many',
18
18
  // demandOption: true,
19
19
  default: './secret',
20
20
  },
21
+ file: {
22
+ type: 'string',
23
+ desc: 'Single file to decrypt. Useful in jsonMode',
24
+ },
21
25
  encKey: {
22
26
  type: 'string',
23
27
  desc: 'Encryption key',
@@ -37,6 +41,11 @@ function getDecryptCLIOptions() {
37
41
  type: 'boolean',
38
42
  desc: 'Delete source files after encryption/decryption. Be careful!',
39
43
  },
44
+ jsonMode: {
45
+ type: 'boolean',
46
+ desc: 'JSON mode. Encrypts only json values, not the whole file',
47
+ default: false,
48
+ },
40
49
  }).argv;
41
50
  if (!encKey) {
42
51
  encKey = process.env[encKeyVar];
@@ -48,5 +57,5 @@ function getDecryptCLIOptions() {
48
57
  }
49
58
  }
50
59
  // `as any` because @types/yargs can't handle string[] type properly
51
- return { dir: dir, encKey, del };
60
+ return { dir: dir, file, encKey, del, jsonMode };
52
61
  }
@@ -6,12 +6,12 @@ const colors_1 = require("../colors");
6
6
  const script_1 = require("../script");
7
7
  const secrets_encrypt_util_1 = require("../secret/secrets-encrypt.util");
8
8
  (0, script_1.runScript)(() => {
9
- const { pattern, encKey, del } = getEncryptCLIOptions();
10
- (0, secrets_encrypt_util_1.secretsEncrypt)(pattern, encKey, del);
9
+ const { pattern, file, encKey, del, jsonMode } = getEncryptCLIOptions();
10
+ (0, secrets_encrypt_util_1.secretsEncrypt)(pattern, file, encKey, del, jsonMode);
11
11
  });
12
12
  function getEncryptCLIOptions() {
13
13
  require('dotenv').config();
14
- let { pattern, encKey, encKeyVar, del } = yargs.options({
14
+ let { pattern, file, encKey, encKeyVar, del, jsonMode } = yargs.options({
15
15
  pattern: {
16
16
  type: 'string',
17
17
  array: true,
@@ -19,6 +19,10 @@ function getEncryptCLIOptions() {
19
19
  // demandOption: true,
20
20
  default: './secret/**',
21
21
  },
22
+ file: {
23
+ type: 'string',
24
+ desc: 'Single file to decrypt. Useful in jsonMode',
25
+ },
22
26
  encKey: {
23
27
  type: 'string',
24
28
  desc: 'Encryption key',
@@ -37,6 +41,12 @@ function getEncryptCLIOptions() {
37
41
  del: {
38
42
  type: 'boolean',
39
43
  desc: 'Delete source files after encryption/decryption. Be careful!',
44
+ default: false,
45
+ },
46
+ jsonMode: {
47
+ type: 'boolean',
48
+ desc: 'JSON mode. Encrypts only json values, not the whole file',
49
+ default: false,
40
50
  },
41
51
  }).argv;
42
52
  if (!encKey) {
@@ -49,5 +59,5 @@ function getEncryptCLIOptions() {
49
59
  }
50
60
  }
51
61
  // `as any` because @types/yargs can't handle string[] type properly
52
- return { pattern: pattern, encKey, del };
62
+ return { pattern: pattern, file, encKey, del, jsonMode };
53
63
  }
@@ -1,11 +1,12 @@
1
1
  export interface DecryptCLIOptions {
2
2
  dir: string[];
3
+ file?: string;
3
4
  encKey: string;
4
- algorithm?: string;
5
5
  del?: boolean;
6
+ jsonMode?: boolean;
6
7
  }
7
8
  /**
8
9
  * Decrypts all files in given directory (*.enc), saves decrypted versions without ending `.enc`.
9
10
  * Using provided encKey.
10
11
  */
11
- export declare function secretsDecrypt(dir: string[], encKey: string, del?: boolean): void;
12
+ export declare function secretsDecrypt(dir: string[], file: string | undefined, encKey: string, del?: boolean, jsonMode?: boolean): void;
@@ -2,22 +2,40 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.secretsDecrypt = void 0;
4
4
  const path = require("path");
5
+ const js_lib_1 = require("@naturalcycles/js-lib");
5
6
  const fs = require("fs-extra");
6
7
  const globby = require("globby");
7
8
  const colors_1 = require("../colors");
8
9
  const crypto_util_1 = require("../security/crypto.util");
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
+ // yarn tsn ./src/bin/secrets-encrypt.ts --file ./src/test/secrets2.plain.json --jsonMode --encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
9
13
  /**
10
14
  * Decrypts all files in given directory (*.enc), saves decrypted versions without ending `.enc`.
11
15
  * Using provided encKey.
12
16
  */
13
- function secretsDecrypt(dir, encKey, del) {
14
- const patterns = dir.map(d => `${d}/**/*.enc`);
17
+ function secretsDecrypt(dir, file, encKey, del = false, jsonMode = false) {
18
+ // If `file` is provided - only this one file is used
19
+ const patterns = file ? [file] : dir.map(d => `${d}/**/*.enc`);
15
20
  const filenames = globby.sync(patterns);
16
21
  filenames.forEach(filename => {
17
- const enc = fs.readFileSync(filename);
18
- const plain = (0, crypto_util_1.decryptRandomIVBuffer)(enc, encKey);
19
- const plainFilename = filename.slice(0, filename.length - '.enc'.length);
20
- fs.writeFileSync(plainFilename, plain);
22
+ let plainFilename;
23
+ if (jsonMode) {
24
+ (0, js_lib_1._assert)(filename.endsWith('.json'), `${path.basename(filename)} MUST end with '.json'`);
25
+ (0, js_lib_1._assert)(!filename.endsWith('.plain.json'), `${path.basename(filename)} MUST NOT end with '.plain.json'`);
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
+ });
31
+ fs.writeFileSync(plainFilename, JSON.stringify(json, null, 2));
32
+ }
33
+ else {
34
+ const enc = fs.readFileSync(filename);
35
+ const plain = (0, crypto_util_1.decryptRandomIVBuffer)(enc, encKey);
36
+ plainFilename = filename.slice(0, filename.length - '.enc'.length);
37
+ fs.writeFileSync(plainFilename, plain);
38
+ }
21
39
  if (del) {
22
40
  fs.unlinkSync(filename);
23
41
  }
@@ -1,11 +1,12 @@
1
1
  export interface EncryptCLIOptions {
2
2
  pattern: string[];
3
+ file?: string;
3
4
  encKey: string;
4
- algorithm?: string;
5
5
  del?: boolean;
6
+ jsonMode?: boolean;
6
7
  }
7
8
  /**
8
9
  * Encrypts all files in given directory (except *.enc), saves encrypted versions as filename.ext.enc.
9
10
  * Using provided encKey.
10
11
  */
11
- export declare function secretsEncrypt(pattern: string[], encKey: string, del?: boolean): void;
12
+ export declare function secretsEncrypt(pattern: string[], file: string | undefined, encKey: string, del?: boolean, jsonMode?: boolean): void;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.secretsEncrypt = void 0;
4
4
  const path = require("path");
5
+ const js_lib_1 = require("@naturalcycles/js-lib");
5
6
  const fs = require("fs-extra");
6
7
  const globby = require("globby");
7
8
  const colors_1 = require("../colors");
@@ -10,17 +11,31 @@ const crypto_util_1 = require("../security/crypto.util");
10
11
  * Encrypts all files in given directory (except *.enc), saves encrypted versions as filename.ext.enc.
11
12
  * Using provided encKey.
12
13
  */
13
- function secretsEncrypt(pattern, encKey, del) {
14
- const patterns = [
15
- ...pattern,
16
- `!**/*.enc`, // excluding already encoded
17
- ];
14
+ function secretsEncrypt(pattern, file, encKey, del = false, jsonMode = false) {
15
+ const patterns = file
16
+ ? [file]
17
+ : [
18
+ ...pattern,
19
+ `!**/*.enc`, // excluding already encoded
20
+ ];
18
21
  const filenames = globby.sync(patterns);
22
+ let encFilename;
19
23
  filenames.forEach(filename => {
20
- const plain = fs.readFileSync(filename);
21
- const enc = (0, crypto_util_1.encryptRandomIVBuffer)(plain, encKey);
22
- const encFilename = `${filename}.enc`;
23
- fs.writeFileSync(encFilename, enc);
24
+ if (jsonMode) {
25
+ (0, js_lib_1._assert)(filename.endsWith('.plain.json'), `${path.basename(filename)} MUST end with '.plain.json'`);
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
+ });
31
+ fs.writeFileSync(encFilename, JSON.stringify(json, null, 2));
32
+ }
33
+ else {
34
+ const plain = fs.readFileSync(filename);
35
+ const enc = (0, crypto_util_1.encryptRandomIVBuffer)(plain, encKey);
36
+ encFilename = `${filename}.enc`;
37
+ fs.writeFileSync(encFilename, enc);
38
+ }
24
39
  if (del) {
25
40
  fs.unlinkSync(filename);
26
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
- "version": "12.66.0",
3
+ "version": "12.67.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "docs-serve": "vuepress dev docs",
@@ -6,21 +6,25 @@ import { runScript } from '../script'
6
6
  import { DecryptCLIOptions, secretsDecrypt } from '../secret/secrets-decrypt.util'
7
7
 
8
8
  runScript(() => {
9
- const { dir, encKey, del } = getDecryptCLIOptions()
9
+ const { dir, file, encKey, del, jsonMode } = getDecryptCLIOptions()
10
10
 
11
- secretsDecrypt(dir, encKey, del)
11
+ secretsDecrypt(dir, file, encKey, del, jsonMode)
12
12
  })
13
13
 
14
14
  function getDecryptCLIOptions(): DecryptCLIOptions {
15
15
  require('dotenv').config()
16
16
 
17
- let { dir, encKey, encKeyVar, del } = yargs.options({
17
+ let { dir, file, encKey, encKeyVar, del, jsonMode } = yargs.options({
18
18
  dir: {
19
19
  type: 'array',
20
20
  desc: 'Directory with secrets. Can be many',
21
21
  // demandOption: true,
22
22
  default: './secret',
23
23
  },
24
+ file: {
25
+ type: 'string',
26
+ desc: 'Single file to decrypt. Useful in jsonMode',
27
+ },
24
28
  encKey: {
25
29
  type: 'string',
26
30
  desc: 'Encryption key',
@@ -40,6 +44,11 @@ function getDecryptCLIOptions(): DecryptCLIOptions {
40
44
  type: 'boolean',
41
45
  desc: 'Delete source files after encryption/decryption. Be careful!',
42
46
  },
47
+ jsonMode: {
48
+ type: 'boolean',
49
+ desc: 'JSON mode. Encrypts only json values, not the whole file',
50
+ default: false,
51
+ },
43
52
  }).argv
44
53
 
45
54
  if (!encKey) {
@@ -55,5 +64,5 @@ function getDecryptCLIOptions(): DecryptCLIOptions {
55
64
  }
56
65
 
57
66
  // `as any` because @types/yargs can't handle string[] type properly
58
- return { dir: dir as any, encKey, del }
67
+ return { dir: dir as any, file, encKey, del, jsonMode }
59
68
  }
@@ -6,15 +6,15 @@ import { runScript } from '../script'
6
6
  import { EncryptCLIOptions, secretsEncrypt } from '../secret/secrets-encrypt.util'
7
7
 
8
8
  runScript(() => {
9
- const { pattern, encKey, del } = getEncryptCLIOptions()
9
+ const { pattern, file, encKey, del, jsonMode } = getEncryptCLIOptions()
10
10
 
11
- secretsEncrypt(pattern, encKey, del)
11
+ secretsEncrypt(pattern, file, encKey, del, jsonMode)
12
12
  })
13
13
 
14
14
  function getEncryptCLIOptions(): EncryptCLIOptions {
15
15
  require('dotenv').config()
16
16
 
17
- let { pattern, encKey, encKeyVar, del } = yargs.options({
17
+ let { pattern, file, encKey, encKeyVar, del, jsonMode } = yargs.options({
18
18
  pattern: {
19
19
  type: 'string',
20
20
  array: true,
@@ -22,6 +22,10 @@ function getEncryptCLIOptions(): EncryptCLIOptions {
22
22
  // demandOption: true,
23
23
  default: './secret/**',
24
24
  },
25
+ file: {
26
+ type: 'string',
27
+ desc: 'Single file to decrypt. Useful in jsonMode',
28
+ },
25
29
  encKey: {
26
30
  type: 'string',
27
31
  desc: 'Encryption key',
@@ -40,6 +44,12 @@ function getEncryptCLIOptions(): EncryptCLIOptions {
40
44
  del: {
41
45
  type: 'boolean',
42
46
  desc: 'Delete source files after encryption/decryption. Be careful!',
47
+ default: false,
48
+ },
49
+ jsonMode: {
50
+ type: 'boolean',
51
+ desc: 'JSON mode. Encrypts only json values, not the whole file',
52
+ default: false,
43
53
  },
44
54
  }).argv
45
55
 
@@ -56,5 +66,5 @@ function getEncryptCLIOptions(): EncryptCLIOptions {
56
66
  }
57
67
 
58
68
  // `as any` because @types/yargs can't handle string[] type properly
59
- return { pattern: pattern as any, encKey, del }
69
+ return { pattern: pattern as any, file, encKey, del, jsonMode }
60
70
  }
@@ -1,31 +1,61 @@
1
1
  import * as path from 'path'
2
+ import { _assert, _stringMapEntries, StringMap } from '@naturalcycles/js-lib'
2
3
  import * as fs from 'fs-extra'
3
4
  import globby = require('globby')
4
5
  import { dimGrey, yellow } from '../colors'
5
- import { decryptRandomIVBuffer } from '../security/crypto.util'
6
+ import { decryptRandomIVBuffer, decryptString } from '../security/crypto.util'
6
7
 
7
8
  export interface DecryptCLIOptions {
8
9
  dir: string[]
10
+ file?: string
9
11
  encKey: string
10
- algorithm?: string
11
12
  del?: boolean
13
+ jsonMode?: boolean
12
14
  }
13
15
 
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
+ // yarn tsn ./src/bin/secrets-encrypt.ts --file ./src/test/secrets2.plain.json --jsonMode --encKey MPd/30v0Zcce4I5mfwF4NSXrpTYD9OO4/fIqw6rjNiWp2b1GN9Xm8nQZqr7c9kKSsATqtwe0HkJFDUGzDSow44GDgDICgB1u1rGa5eNqtxnOVGRR+lIinCvN/1OnpjzeoJy2bStXPj1DKx8anMqgA8SoOZdlWRNSkEeZlolru8Ey0ujZo22dfwMyRIEniLcqvBm/iMiAkV82fn/TxYw05GarAoJcrfPeDBvuOXsARnMCyX18qTFL0iojxeTU8JHxr8TX3eXDq9cJJmridEKlwRIAzADwtetI4ttlP8lwJj1pmgsBIN3iqYssZYCkZ3HMV6BoEc7LTI5z/45rKrAT1A==
19
+
14
20
  /**
15
21
  * Decrypts all files in given directory (*.enc), saves decrypted versions without ending `.enc`.
16
22
  * Using provided encKey.
17
23
  */
18
- export function secretsDecrypt(dir: string[], encKey: string, del?: boolean): void {
19
- const patterns = dir.map(d => `${d}/**/*.enc`)
24
+ export function secretsDecrypt(
25
+ dir: string[],
26
+ file: string | undefined,
27
+ encKey: string,
28
+ del = false,
29
+ jsonMode = false,
30
+ ): void {
31
+ // If `file` is provided - only this one file is used
32
+ const patterns = file ? [file] : dir.map(d => `${d}/**/*.enc`)
20
33
 
21
34
  const filenames = globby.sync(patterns)
22
35
 
23
36
  filenames.forEach(filename => {
24
- const enc = fs.readFileSync(filename)
25
- const plain = decryptRandomIVBuffer(enc, encKey)
37
+ let plainFilename
38
+
39
+ if (jsonMode) {
40
+ _assert(filename.endsWith('.json'), `${path.basename(filename)} MUST end with '.json'`)
41
+ _assert(
42
+ !filename.endsWith('.plain.json'),
43
+ `${path.basename(filename)} MUST NOT end with '.plain.json'`,
44
+ )
45
+ plainFilename = filename.replace('.json', '.plain.json')
26
46
 
27
- const plainFilename = filename.slice(0, filename.length - '.enc'.length)
28
- fs.writeFileSync(plainFilename, plain)
47
+ const json: StringMap = JSON.parse(fs.readFileSync(filename, 'utf8'))
48
+ _stringMapEntries(json).forEach(([k, v]) => {
49
+ json[k] = decryptString(v, encKey)
50
+ })
51
+
52
+ fs.writeFileSync(plainFilename, JSON.stringify(json, null, 2))
53
+ } else {
54
+ const enc = fs.readFileSync(filename)
55
+ const plain = decryptRandomIVBuffer(enc, encKey)
56
+ plainFilename = filename.slice(0, filename.length - '.enc'.length)
57
+ fs.writeFileSync(plainFilename, plain)
58
+ }
29
59
 
30
60
  if (del) {
31
61
  fs.unlinkSync(filename)
@@ -1,33 +1,59 @@
1
1
  import * as path from 'path'
2
+ import { _assert, _stringMapEntries, StringMap } from '@naturalcycles/js-lib'
2
3
  import * as fs from 'fs-extra'
3
4
  import globby = require('globby')
4
5
  import { dimGrey, yellow } from '../colors'
5
- import { encryptRandomIVBuffer } from '../security/crypto.util'
6
+ import { encryptRandomIVBuffer, encryptString } from '../security/crypto.util'
6
7
 
7
8
  export interface EncryptCLIOptions {
8
9
  pattern: string[]
10
+ file?: string
9
11
  encKey: string
10
- algorithm?: string
11
12
  del?: boolean
13
+ jsonMode?: boolean
12
14
  }
13
15
 
14
16
  /**
15
17
  * Encrypts all files in given directory (except *.enc), saves encrypted versions as filename.ext.enc.
16
18
  * Using provided encKey.
17
19
  */
18
- export function secretsEncrypt(pattern: string[], encKey: string, del?: boolean): void {
19
- const patterns = [
20
- ...pattern,
21
- `!**/*.enc`, // excluding already encoded
22
- ]
20
+ export function secretsEncrypt(
21
+ pattern: string[],
22
+ file: string | undefined,
23
+ encKey: string,
24
+ del = false,
25
+ jsonMode = false,
26
+ ): void {
27
+ const patterns = file
28
+ ? [file]
29
+ : [
30
+ ...pattern,
31
+ `!**/*.enc`, // excluding already encoded
32
+ ]
23
33
  const filenames = globby.sync(patterns)
34
+ let encFilename
24
35
 
25
36
  filenames.forEach(filename => {
26
- const plain = fs.readFileSync(filename)
27
- const enc = encryptRandomIVBuffer(plain, encKey)
37
+ if (jsonMode) {
38
+ _assert(
39
+ filename.endsWith('.plain.json'),
40
+ `${path.basename(filename)} MUST end with '.plain.json'`,
41
+ )
42
+ encFilename = filename.replace('.plain', '')
28
43
 
29
- const encFilename = `${filename}.enc`
30
- fs.writeFileSync(encFilename, enc)
44
+ const json: StringMap = JSON.parse(fs.readFileSync(filename, 'utf8'))
45
+
46
+ _stringMapEntries(json).forEach(([k, plain]) => {
47
+ json[k] = encryptString(plain, encKey)
48
+ })
49
+
50
+ fs.writeFileSync(encFilename, JSON.stringify(json, null, 2))
51
+ } else {
52
+ const plain = fs.readFileSync(filename)
53
+ const enc = encryptRandomIVBuffer(plain, encKey)
54
+ encFilename = `${filename}.enc`
55
+ fs.writeFileSync(encFilename, enc)
56
+ }
31
57
 
32
58
  if (del) {
33
59
  fs.unlinkSync(filename)