1 | import * as path from 'path'
|
2 | import { _assert } from '@naturalcycles/js-lib'
|
3 | import * as fs from 'fs-extra'
|
4 | import { dimGrey, yellow } from '../colors'
|
5 | import { fastGlob } from '../index'
|
6 | import { decryptObject, decryptRandomIVBuffer } from '../security/crypto.util'
|
7 |
|
8 | export interface DecryptCLIOptions {
|
9 | dir: string[]
|
10 | file?: string
|
11 | encKey: string
|
12 | del?: boolean
|
13 | jsonMode?: boolean
|
14 | }
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | export function secretsDecrypt(
|
25 | dir: string[],
|
26 | file: string | undefined,
|
27 | encKey: string,
|
28 | del = false,
|
29 | jsonMode = false,
|
30 | ): void {
|
31 |
|
32 | const patterns = file ? [file] : dir.map(d => `${d}/**/*.enc`)
|
33 |
|
34 | const filenames = fastGlob.sync(patterns)
|
35 |
|
36 | filenames.forEach(filename => {
|
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')
|
46 |
|
47 | const json = decryptObject(JSON.parse(fs.readFileSync(filename, 'utf8')), encKey)
|
48 |
|
49 | fs.writeFileSync(plainFilename, JSON.stringify(json, null, 2))
|
50 | } else {
|
51 | const enc = fs.readFileSync(filename)
|
52 | const plain = decryptRandomIVBuffer(enc, encKey)
|
53 | plainFilename = filename.slice(0, filename.length - '.enc'.length)
|
54 | fs.writeFileSync(plainFilename, plain)
|
55 | }
|
56 |
|
57 | if (del) {
|
58 | fs.unlinkSync(filename)
|
59 | }
|
60 |
|
61 | console.log(` ${path.basename(filename)} > ${path.basename(plainFilename)}`)
|
62 | })
|
63 |
|
64 | console.log(`decrypted ${yellow(filenames.length)} files in ${dimGrey(dir.join(' '))}`)
|
65 | }
|