@typinghare/trick 1.0.7 → 2.0.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.
- package/README.md +23 -23
- package/dist/app.d.ts +1 -1
- package/dist/app.js +65 -111
- package/dist/config.d.ts +71 -14
- package/dist/config.js +61 -24
- package/dist/encrypt.d.ts +68 -14
- package/dist/encrypt.js +77 -28
- package/dist/error.d.ts +30 -0
- package/dist/error.js +69 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/passphrase.d.ts +13 -0
- package/dist/passphrase.js +26 -0
- package/eslint.config.js +41 -0
- package/package.json +11 -8
- package/src/app.ts +85 -160
- package/src/config.ts +93 -29
- package/src/encrypt.ts +89 -44
- package/src/error.ts +82 -0
- package/src/index.ts +1 -2
- package/src/passphrase.ts +39 -0
- package/test/resources/really.json +2 -2
- package/test/resources/task.yml +3 -4
- package/test/trick.config.json +13 -0
- package/.wander/jameschan312.cn@gmail.com/.idea/codeStyles/Project.xml +0 -52
- package/.wander/jameschan312.cn@gmail.com/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.wander/jameschan312.cn@gmail.com/.idea/jsLibraryMappings.xml +0 -6
- package/.wander/jameschan312.cn@gmail.com/.idea/misc.xml +0 -6
- package/.wander/jameschan312.cn@gmail.com/.idea/modules.xml +0 -8
- package/.wander/jameschan312.cn@gmail.com/.idea/prettier.xml +0 -6
- package/.wander/jameschan312.cn@gmail.com/.idea/trick.iml +0 -14
- package/.wander/jameschan312.cn@gmail.com/.idea/vcs.xml +0 -6
- package/.wander/jameschan312.cn@gmail.com/.idea/webResources.xml +0 -14
- package/dist/constant.d.ts +0 -2
- package/dist/constant.js +0 -3
- package/dist/secret.d.ts +0 -5
- package/dist/secret.js +0 -14
- package/src/constant.ts +0 -4
- package/src/secret.ts +0 -14
- package/trick.config.json +0 -20
package/README.md
CHANGED
|
@@ -15,34 +15,37 @@ yarn add -g @typinghare/trick
|
|
|
15
15
|
|
|
16
16
|
## Philosophy
|
|
17
17
|
|
|
18
|
-
We often add sensitive files, such as `.env` and `api_key.conf`, to `.gitignore`, preventing them from being committed or even pushed to remote depots for safety reasons. Then, we have to manually copy the file to the server. It
|
|
18
|
+
We often add sensitive and credential files, such as `.env` and `api_key.conf`, to `.gitignore`, preventing them from being committed or even pushed to remote depots for safety reasons. Then, we have to manually copy the file to the server. It would be effortless if we only had one file, but imagine we have a lot in a bigger project. Even worse, some careless people (me) have even lost these sensitive files after changing computers!
|
|
19
19
|
|
|
20
|
-
**Trick** helps you to encrypt sensitive files with a
|
|
20
|
+
**Trick** helps you to encrypt sensitive files with a passphrase so that you can upload the credential file to Git platforms. Later on the server, just use the same passphrase to decrypt the files with ease.
|
|
21
21
|
|
|
22
22
|
## Quick Example
|
|
23
23
|
|
|
24
|
-
Set up the **
|
|
24
|
+
Set up the **target** with the files needed to be encrypted:
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
|
-
# This will create a trick.config.json
|
|
28
|
-
# trick add <
|
|
29
|
-
$ trick add
|
|
27
|
+
# This will create a trick.config.json in the current working directory
|
|
28
|
+
# trick add <target> [files...]
|
|
29
|
+
$ trick add MyTargetName .env api_key.conf
|
|
30
30
|
|
|
31
|
-
# Display the list of
|
|
31
|
+
# Display the list of target names and the files bound
|
|
32
32
|
$ trick list
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Create a `passphrase.json` file under `~/.config` with the following content:
|
|
36
36
|
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"MyTargetName": "Reg5eGPXWdmeW0i08uaygBlfbXP+tJlnu7z551Qt568="
|
|
40
|
+
}
|
|
40
41
|
```
|
|
41
42
|
|
|
43
|
+
Here, the key is the target name, and the value is the `passphrase` that is used to encrypt/decrypt the files associated with this target name.
|
|
44
|
+
|
|
42
45
|
Encrypt the files:
|
|
43
46
|
|
|
44
47
|
```bash
|
|
45
|
-
$ trick encrypt
|
|
48
|
+
$ trick encrypt MyTargetName
|
|
46
49
|
```
|
|
47
50
|
|
|
48
51
|
You will see the following output:
|
|
@@ -52,11 +55,10 @@ You will see the following output:
|
|
|
52
55
|
[ENCRYPTED] api_key.conf -> .trick/encrypted/api_key.conf.enc
|
|
53
56
|
```
|
|
54
57
|
|
|
55
|
-
Encrypted files are all saved to `.trick`. On the server
|
|
58
|
+
Encrypted files are all saved to `.trick`. On the server, set the the `passphrase.json` in the same way, and execute:
|
|
56
59
|
|
|
57
60
|
```bash
|
|
58
|
-
$
|
|
59
|
-
$ trick decrypt AN_EXAMPLE_SECRET
|
|
61
|
+
$ trick decrypt MyTargetName
|
|
60
62
|
```
|
|
61
63
|
|
|
62
64
|
And you will see that the files are restored:
|
|
@@ -67,20 +69,19 @@ And you will see that the files are restored:
|
|
|
67
69
|
```
|
|
68
70
|
|
|
69
71
|
> [!IMPORTANT]
|
|
70
|
-
>
|
|
71
|
-
> You need to keep the secret to yourself! Make a copy on Cloud or write it down!
|
|
72
|
+
> The `passphrase.json` collects all the passphrases you have. Please back it up in multiple devices every time you edit it!
|
|
72
73
|
|
|
73
74
|
## More Features
|
|
74
75
|
|
|
75
|
-
### Default
|
|
76
|
+
### Default Target Name
|
|
76
77
|
|
|
77
|
-
You can set the default
|
|
78
|
+
You can set the default target name so that you don't need to input it every time:
|
|
78
79
|
|
|
79
80
|
```bash
|
|
80
|
-
# Set the default
|
|
81
|
-
$ trick set-default
|
|
81
|
+
# Set the default target name
|
|
82
|
+
$ trick set-default MyTargetName
|
|
82
83
|
|
|
83
|
-
# Display the default
|
|
84
|
+
# Display the default target name
|
|
84
85
|
$ trick get-default
|
|
85
86
|
```
|
|
86
87
|
|
|
@@ -90,4 +91,3 @@ Now you can encrypt and decrypt more easily:
|
|
|
90
91
|
$ trick encrypt
|
|
91
92
|
$ trick decrypt
|
|
92
93
|
```
|
|
93
|
-
|
package/dist/app.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export {};
|
package/dist/app.js
CHANGED
|
@@ -1,128 +1,120 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { getTargetFromConfig,
|
|
3
|
-
import { decryptFiles, encryptFiles
|
|
4
|
-
import { getSecret, SecretNotFoundError } from './secret.js';
|
|
5
|
-
import { TRICK_ENCRYPTED_DIR } from './constant.js';
|
|
2
|
+
import { getTargetFromConfig, updateConfig } from './config.js';
|
|
3
|
+
import { decryptFiles, encryptFiles } from './encrypt.js';
|
|
6
4
|
import fsExtra from 'fs-extra';
|
|
7
5
|
import chalk from 'chalk';
|
|
6
|
+
import { getPassphrase } from './passphrase.js';
|
|
7
|
+
import { resolve_error } from './error.js';
|
|
8
8
|
const program = new Command();
|
|
9
|
-
program.version('
|
|
10
|
-
program.description('Save credential files to remote safely.');
|
|
9
|
+
program.version('2.0.0');
|
|
10
|
+
program.description('Save credential files to remote safely and easily.');
|
|
11
11
|
program
|
|
12
12
|
.command('add')
|
|
13
|
-
.description('Add
|
|
14
|
-
.argument('<
|
|
15
|
-
.argument('[files...]', 'Files
|
|
16
|
-
.action(async (
|
|
13
|
+
.description('Add files to a target.')
|
|
14
|
+
.argument('<name>', 'The name of the target')
|
|
15
|
+
.argument('[files...]', 'Files that are encrypted')
|
|
16
|
+
.action(async (targetName, files) => {
|
|
17
17
|
await updateConfig((config) => {
|
|
18
18
|
try {
|
|
19
|
-
const target = getTargetFromConfig(config,
|
|
19
|
+
const target = getTargetFromConfig(config, targetName);
|
|
20
20
|
target.files.push(...files);
|
|
21
|
-
return true;
|
|
22
21
|
}
|
|
23
22
|
catch (err) {
|
|
24
|
-
config.
|
|
25
|
-
config.targets
|
|
26
|
-
return true;
|
|
23
|
+
config.default_target_name = targetName;
|
|
24
|
+
config.targets[targetName] = { files };
|
|
27
25
|
}
|
|
26
|
+
return true;
|
|
28
27
|
});
|
|
29
28
|
});
|
|
30
29
|
program
|
|
31
30
|
.command('remove')
|
|
32
|
-
.description('Remove files from a
|
|
33
|
-
.argument('<
|
|
34
|
-
.argument('[files...]', 'Files to remove
|
|
31
|
+
.description('Remove files from a target.')
|
|
32
|
+
.argument('<name>', 'The name of the target')
|
|
33
|
+
.argument('[files...]', 'Files to remove')
|
|
35
34
|
.option('-t, --target', 'Remove the target instead.')
|
|
36
|
-
.action(async (
|
|
35
|
+
.action(async (targetName, files, options) => {
|
|
37
36
|
if (options.target) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
config.targets.splice(index, 1);
|
|
45
|
-
console.log(`[SUCCESS] Removed target: ${secretName}`);
|
|
37
|
+
// Remove the target
|
|
38
|
+
return await updateConfig((config) => {
|
|
39
|
+
getTargetFromConfig(config, targetName);
|
|
40
|
+
delete config.targets[targetName];
|
|
41
|
+
console.log(`[SUCCESS] Removed target: ${targetName}`);
|
|
46
42
|
return true;
|
|
47
43
|
});
|
|
48
|
-
return;
|
|
49
44
|
}
|
|
45
|
+
// Remove files from the target
|
|
50
46
|
await updateConfig((config) => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
console.log(chalk.yellow(`[WARNING] File does not exist in the target: ${file}`));
|
|
47
|
+
const target = getTargetFromConfig(config, targetName);
|
|
48
|
+
const removedFiles = [];
|
|
49
|
+
const remainingFiles = [];
|
|
50
|
+
for (const file of target.files) {
|
|
51
|
+
if (files.includes(file)) {
|
|
52
|
+
removedFiles.push(file);
|
|
53
|
+
console.log(`[SUCCESS] Removed file: ${file}`);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
remainingFiles.push(file);
|
|
62
57
|
}
|
|
63
58
|
}
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
target.files = remainingFiles;
|
|
60
|
+
const notFoundFiles = files.filter((it) => !removedFiles.includes(it));
|
|
61
|
+
for (const notFoundFile of notFoundFiles) {
|
|
62
|
+
console.log(`[WARNING] File not found in the target: ${notFoundFile}`);
|
|
66
63
|
}
|
|
67
64
|
return true;
|
|
68
65
|
});
|
|
69
66
|
});
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (!secretName) {
|
|
75
|
-
throw new Error('No secret name given, and the default secret name is not set.');
|
|
67
|
+
function getTargetName(targetNameOrNull, defaultTargetName) {
|
|
68
|
+
const targetName = targetNameOrNull === null ? defaultTargetName : targetNameOrNull;
|
|
69
|
+
if (targetName === null) {
|
|
70
|
+
throw new Error('Target is not specified and the default target name is null!');
|
|
76
71
|
}
|
|
77
|
-
return
|
|
72
|
+
return targetName;
|
|
78
73
|
}
|
|
79
74
|
program
|
|
80
75
|
.command('encrypt')
|
|
81
76
|
.description('Encrypt the credential files.')
|
|
82
|
-
.argument('[
|
|
83
|
-
.action(async (
|
|
77
|
+
.argument('[target]', 'The name of the target', null)
|
|
78
|
+
.action(async (targetNameOrNull) => {
|
|
84
79
|
await updateConfig((config) => {
|
|
85
|
-
|
|
86
|
-
const target = getTargetFromConfig(config,
|
|
87
|
-
const
|
|
80
|
+
const targetName = getTargetName(targetNameOrNull, config.default_target_name);
|
|
81
|
+
const target = getTargetFromConfig(config, targetName);
|
|
82
|
+
const passphrase = getPassphrase(config, targetName);
|
|
88
83
|
const srcFilePaths = target.files;
|
|
89
|
-
fsExtra.ensureDir(
|
|
90
|
-
encryptFiles(srcFilePaths,
|
|
91
|
-
return false;
|
|
84
|
+
fsExtra.ensureDir(config.root_directory);
|
|
85
|
+
encryptFiles(srcFilePaths, config.root_directory, passphrase, config.encryption.iteration_count);
|
|
92
86
|
});
|
|
93
87
|
});
|
|
94
88
|
program
|
|
95
89
|
.command('decrypt')
|
|
96
90
|
.description('Decrypt the credential files.')
|
|
97
|
-
.argument('[
|
|
98
|
-
.action(async (
|
|
91
|
+
.argument('[target]', 'The name of the target', null)
|
|
92
|
+
.action(async (targetNameOrNull) => {
|
|
99
93
|
await updateConfig((config) => {
|
|
100
|
-
|
|
101
|
-
const target = getTargetFromConfig(config,
|
|
102
|
-
const
|
|
94
|
+
const targetName = getTargetName(targetNameOrNull, config.default_target_name);
|
|
95
|
+
const target = getTargetFromConfig(config, targetName);
|
|
96
|
+
const passphrase = getPassphrase(config, targetName);
|
|
103
97
|
const srcFilePaths = target.files;
|
|
104
|
-
fsExtra.ensureDir(
|
|
105
|
-
decryptFiles(srcFilePaths,
|
|
106
|
-
return false;
|
|
98
|
+
fsExtra.ensureDir(config.root_directory);
|
|
99
|
+
decryptFiles(srcFilePaths, config.root_directory, passphrase, config.encryption.iteration_count);
|
|
107
100
|
});
|
|
108
101
|
});
|
|
109
102
|
program
|
|
110
103
|
.command('set-default')
|
|
111
|
-
.description('Set the default
|
|
112
|
-
.argument('<
|
|
113
|
-
.action(async (
|
|
104
|
+
.description('Set the default target name.')
|
|
105
|
+
.argument('<target>', 'The name of the target to set')
|
|
106
|
+
.action(async (targetName) => {
|
|
114
107
|
await updateConfig((config) => {
|
|
115
|
-
config.
|
|
108
|
+
config.default_target_name = targetName;
|
|
116
109
|
return true;
|
|
117
110
|
});
|
|
118
111
|
});
|
|
119
112
|
program
|
|
120
113
|
.command('get-default')
|
|
121
|
-
.description('Get the default
|
|
114
|
+
.description('Get the default target name.')
|
|
122
115
|
.action(async () => {
|
|
123
116
|
await updateConfig((config) => {
|
|
124
|
-
console.log(config.
|
|
125
|
-
return false;
|
|
117
|
+
console.log(config.default_target_name);
|
|
126
118
|
});
|
|
127
119
|
});
|
|
128
120
|
program
|
|
@@ -130,13 +122,12 @@ program
|
|
|
130
122
|
.description('Display a list of targets.')
|
|
131
123
|
.action(async () => {
|
|
132
124
|
await updateConfig((config) => {
|
|
133
|
-
for (const target of config.targets) {
|
|
134
|
-
console.log(chalk.cyan(
|
|
125
|
+
for (const [targetName, target] of Object.entries(config.targets)) {
|
|
126
|
+
console.log(chalk.cyan(targetName));
|
|
135
127
|
for (const file of target.files) {
|
|
136
128
|
console.log(' ' + chalk.yellow(file));
|
|
137
129
|
}
|
|
138
130
|
}
|
|
139
|
-
return false;
|
|
140
131
|
});
|
|
141
132
|
});
|
|
142
133
|
program.parse();
|
|
@@ -144,40 +135,3 @@ process.on('uncaughtException', (err) => {
|
|
|
144
135
|
resolve_error(err);
|
|
145
136
|
process.exit(1);
|
|
146
137
|
});
|
|
147
|
-
export function resolve_error(err) {
|
|
148
|
-
if (!(err instanceof Error)) {
|
|
149
|
-
console.error(`Unknown error: ${err}`);
|
|
150
|
-
process.exit(2);
|
|
151
|
-
}
|
|
152
|
-
if (err instanceof WriteConfigError) {
|
|
153
|
-
console.error(chalk.red('Fail to write Trick config file'));
|
|
154
|
-
}
|
|
155
|
-
else if (err instanceof ReadConfigError) {
|
|
156
|
-
console.error(chalk.red('Fail to read Trick config file'));
|
|
157
|
-
}
|
|
158
|
-
else if (err instanceof SecretNotFoundError) {
|
|
159
|
-
console.error(chalk.red(err.message));
|
|
160
|
-
}
|
|
161
|
-
else if (err instanceof TargetNotFoundError) {
|
|
162
|
-
console.error(chalk.red(err.message));
|
|
163
|
-
}
|
|
164
|
-
else if (err instanceof FailToEncryptFileError) {
|
|
165
|
-
console.error(chalk.red(err.message));
|
|
166
|
-
if (err.opensslErrMessage) {
|
|
167
|
-
console.error(chalk.red(err.opensslErrMessage));
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
console.error(chalk.yellow('Make sure the file exists and you have enough permission to access it'));
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
else if (err instanceof FailToDecryptFileError) {
|
|
174
|
-
console.error(chalk.red(err.message));
|
|
175
|
-
if (err.opensslErrMessage) {
|
|
176
|
-
console.error(chalk.red(err.opensslErrMessage));
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
console.error(chalk.yellow('Make sure the file exists and you have enough permission to access it'));
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
process.exit(1);
|
|
183
|
-
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,23 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The name of the configuration file to look for in the root directory.
|
|
3
|
+
*/
|
|
1
4
|
export declare const CONFIG_FILE_NAME: string;
|
|
5
|
+
/**
|
|
6
|
+
* Config type.
|
|
7
|
+
*
|
|
8
|
+
* @property targets Mapping from target names to target objects.
|
|
9
|
+
* @property default_target_name The name of the default target.
|
|
10
|
+
* @property root_directory The root directory.
|
|
11
|
+
* @property passphrase_file_path The path to the passphrase file.
|
|
12
|
+
* @property encryption Encryption configuration.
|
|
13
|
+
*/
|
|
2
14
|
export interface Config {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
15
|
+
targets: {
|
|
16
|
+
[name: string]: Target;
|
|
17
|
+
};
|
|
18
|
+
default_target_name: string | null;
|
|
19
|
+
root_directory: string;
|
|
20
|
+
passphrase_file_path: string;
|
|
21
|
+
encryption: Encryption;
|
|
6
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Target type.
|
|
25
|
+
*
|
|
26
|
+
* @property files A list of files to encrypt/decrypt.
|
|
27
|
+
*/
|
|
7
28
|
export interface Target {
|
|
8
|
-
secret_name: string;
|
|
9
29
|
files: string[];
|
|
10
30
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Encryption configuration.
|
|
33
|
+
*
|
|
34
|
+
* @property iteration_count The number of iteration.
|
|
35
|
+
*/
|
|
36
|
+
export interface Encryption {
|
|
37
|
+
iteration_count: number;
|
|
14
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Writes a configuration object to the configuration file.
|
|
41
|
+
*
|
|
42
|
+
* @param config The configuration to write.
|
|
43
|
+
* @throws {WriteConfigError} If error occurs when writing to the configuration
|
|
44
|
+
* file.
|
|
45
|
+
*/
|
|
15
46
|
export declare function writeConfig(config: Config): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Retrieves the configuration object from the configuration file.
|
|
49
|
+
*
|
|
50
|
+
* @return The configuration object retrieved from the configuration object;
|
|
51
|
+
* null if the configuration file doesn't exist.
|
|
52
|
+
* @throws {ReadConfigError} If error occurs when reading the configuration
|
|
53
|
+
* file.
|
|
54
|
+
*/
|
|
16
55
|
export declare function readConfig(): Promise<Config | null>;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Updates the configuration object.
|
|
58
|
+
*
|
|
59
|
+
* This function first retrieves the configuration object fromthe configuration
|
|
60
|
+
* file. If the configuration file doesn't exist, the default configuration will
|
|
61
|
+
* be used instead.
|
|
62
|
+
*
|
|
63
|
+
* Then it calls the callback function by passing on the configuration object.
|
|
64
|
+
* If the callback function returns `true`, then the object will be written to
|
|
65
|
+
* the configuration file.
|
|
66
|
+
*
|
|
67
|
+
* @param callback The callback function taking the configuraition object
|
|
68
|
+
* retrieved from the configuration file.
|
|
69
|
+
* @see DEFAULT_CONFIG
|
|
70
|
+
*/
|
|
71
|
+
export declare function updateConfig(callback: (Config: Config) => boolean | void): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Gets a target object from a specified configuration object.
|
|
74
|
+
*
|
|
75
|
+
* @param config The configuration object to get the target from.
|
|
76
|
+
* @param targetName The name of the target to get.
|
|
77
|
+
* @return The target object associated with the given name.
|
|
78
|
+
* @throws {TargetNotFoundError} If the target object is not found.
|
|
79
|
+
*/
|
|
80
|
+
export declare function getTargetFromConfig(config: Config, targetName: string): Target;
|
package/dist/config.js
CHANGED
|
@@ -1,21 +1,44 @@
|
|
|
1
1
|
import fsExtra from 'fs-extra';
|
|
2
|
+
import { ReadConfigError, TargetNotFoundError, WriteConfigError, } from './error.js';
|
|
3
|
+
/**
|
|
4
|
+
* The name of the configuration file to look for in the root directory.
|
|
5
|
+
*/
|
|
2
6
|
export const CONFIG_FILE_NAME = 'trick.config.json';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Default configuration.
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_CONFIG = {
|
|
11
|
+
targets: {},
|
|
12
|
+
default_target_name: null,
|
|
13
|
+
root_directory: '.trick',
|
|
14
|
+
passphrase_file_path: '~/.config/trick_passphrase.json',
|
|
15
|
+
encryption: {
|
|
16
|
+
iteration_count: 0,
|
|
17
|
+
},
|
|
6
18
|
};
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Writes a configuration object to the configuration file.
|
|
21
|
+
*
|
|
22
|
+
* @param config The configuration to write.
|
|
23
|
+
* @throws {WriteConfigError} If error occurs when writing to the configuration
|
|
24
|
+
* file.
|
|
25
|
+
*/
|
|
11
26
|
export async function writeConfig(config) {
|
|
12
27
|
try {
|
|
13
28
|
await fsExtra.writeFile(CONFIG_FILE_NAME, JSON.stringify(config, null, 2));
|
|
14
29
|
}
|
|
15
30
|
catch (err) {
|
|
16
|
-
throw new WriteConfigError();
|
|
31
|
+
throw new WriteConfigError(err);
|
|
17
32
|
}
|
|
18
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Retrieves the configuration object from the configuration file.
|
|
36
|
+
*
|
|
37
|
+
* @return The configuration object retrieved from the configuration object;
|
|
38
|
+
* null if the configuration file doesn't exist.
|
|
39
|
+
* @throws {ReadConfigError} If error occurs when reading the configuration
|
|
40
|
+
* file.
|
|
41
|
+
*/
|
|
19
42
|
export async function readConfig() {
|
|
20
43
|
if (!fsExtra.existsSync(CONFIG_FILE_NAME)) {
|
|
21
44
|
return null;
|
|
@@ -24,28 +47,42 @@ export async function readConfig() {
|
|
|
24
47
|
return (await fsExtra.readJSON(CONFIG_FILE_NAME));
|
|
25
48
|
}
|
|
26
49
|
catch (err) {
|
|
27
|
-
throw new ReadConfigError();
|
|
50
|
+
throw new ReadConfigError(err);
|
|
28
51
|
}
|
|
29
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Updates the configuration object.
|
|
55
|
+
*
|
|
56
|
+
* This function first retrieves the configuration object fromthe configuration
|
|
57
|
+
* file. If the configuration file doesn't exist, the default configuration will
|
|
58
|
+
* be used instead.
|
|
59
|
+
*
|
|
60
|
+
* Then it calls the callback function by passing on the configuration object.
|
|
61
|
+
* If the callback function returns `true`, then the object will be written to
|
|
62
|
+
* the configuration file.
|
|
63
|
+
*
|
|
64
|
+
* @param callback The callback function taking the configuraition object
|
|
65
|
+
* retrieved from the configuration file.
|
|
66
|
+
* @see DEFAULT_CONFIG
|
|
67
|
+
*/
|
|
30
68
|
export async function updateConfig(callback) {
|
|
31
|
-
const config = (await readConfig()) ||
|
|
69
|
+
const config = (await readConfig()) || DEFAULT_CONFIG;
|
|
32
70
|
if (callback(config)) {
|
|
33
71
|
await writeConfig(config);
|
|
34
72
|
}
|
|
35
73
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
74
|
+
/**
|
|
75
|
+
* Gets a target object from a specified configuration object.
|
|
76
|
+
*
|
|
77
|
+
* @param config The configuration object to get the target from.
|
|
78
|
+
* @param targetName The name of the target to get.
|
|
79
|
+
* @return The target object associated with the given name.
|
|
80
|
+
* @throws {TargetNotFoundError} If the target object is not found.
|
|
81
|
+
*/
|
|
82
|
+
export function getTargetFromConfig(config, targetName) {
|
|
83
|
+
const target = config.targets[targetName];
|
|
84
|
+
if (!target) {
|
|
85
|
+
throw new TargetNotFoundError(targetName);
|
|
49
86
|
}
|
|
50
|
-
|
|
87
|
+
return target;
|
|
51
88
|
}
|
package/dist/encrypt.d.ts
CHANGED
|
@@ -1,14 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Encrypts a file using OpenSSL with AES-256-CBC and PBKDF2 key derivation.
|
|
3
|
+
*
|
|
4
|
+
* This function checks whether the source file exists, constructs an OpenSSL
|
|
5
|
+
* command, ensures the destination directory exists, and then executes the
|
|
6
|
+
* encryption command.
|
|
7
|
+
*
|
|
8
|
+
* @param srcFilePath The path to the source file that needs to be encrypted.
|
|
9
|
+
* @param destFilePath The path where the encrypted file will be saved.
|
|
10
|
+
* @param passphrase The passphrase used for encryption.
|
|
11
|
+
* @param iteration_count The number of iterations to use for PBKDF2.
|
|
12
|
+
* @returns Resolves when the file is successfully encrypted.
|
|
13
|
+
* @throws {FailToEncryptFileError} If the source file does not exist or if
|
|
14
|
+
* OpenSSL returns an error during encryption.
|
|
15
|
+
* @throws {FailToDecryptFileError} If an unknown error occurs during
|
|
16
|
+
* encryption.
|
|
17
|
+
*/
|
|
18
|
+
export declare function encryptFile(srcFilePath: string, destFilePath: string, passphrase: string, iteration_count: number): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Decrypts a file using OpenSSL with AES-256-CBC and PBKDF2 key derivation.
|
|
21
|
+
*
|
|
22
|
+
* This function checks whether the encrypted file exists, constructs an OpenSSL
|
|
23
|
+
* decryption command, ensures the destination directory exists, and then
|
|
24
|
+
* executes the decryption command.
|
|
25
|
+
*
|
|
26
|
+
* @param srcFilePath The path where the decrypted file will be saved.
|
|
27
|
+
* @param destFilePath The path to the encrypted source file.
|
|
28
|
+
* @param passphrase The passphrase used for decryption.
|
|
29
|
+
* @param iteration_count The number of iterations used for PBKDF2.
|
|
30
|
+
* @returns Resolves when the file is successfully decrypted.
|
|
31
|
+
* @throws {FailToDecryptFileError} If the encrypted file does not exist or if
|
|
32
|
+
* OpenSSL returns an error during decryption.
|
|
33
|
+
* @throws {FailToDecryptFileError} If an unknown error occurs during
|
|
34
|
+
* decryption.
|
|
35
|
+
*/
|
|
36
|
+
export declare function decryptFile(srcFilePath: string, destFilePath: string, passphrase: string, iteration_count: number): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Encrypts multiple files using OpenSSL with AES-256-CBC and PBKDF2 key
|
|
39
|
+
* derivation.
|
|
40
|
+
*
|
|
41
|
+
* For each source file path provided, this function constructs the destination
|
|
42
|
+
* file path by appending `.enc`, then calls `encryptFile` and logs the
|
|
43
|
+
* operation.
|
|
44
|
+
*
|
|
45
|
+
* @param srcFilePaths An array of file paths to be encrypted.
|
|
46
|
+
* @param destDir The directory where the encrypted files will be saved.
|
|
47
|
+
* @param passphrase The passphrase used for encryption.
|
|
48
|
+
* @param iteration_count The number of iterations to use for PBKDF2.
|
|
49
|
+
* @returns Resolves when all files are successfully encrypted.
|
|
50
|
+
* @throws {FailToEncryptFileError} If any file fails to encrypt.
|
|
51
|
+
*/
|
|
52
|
+
export declare function encryptFiles(srcFilePaths: string[], destDir: string, passphrase: string, iteration_count: number): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Decrypts multiple files using OpenSSL with AES-256-CBC and PBKDF2 key
|
|
55
|
+
* derivation.
|
|
56
|
+
*
|
|
57
|
+
* For each source file path provided, this function assumes the corresponding
|
|
58
|
+
* encrypted file has the `.enc` extension and calls `decryptFile`, logging the
|
|
59
|
+
* operation.
|
|
60
|
+
*
|
|
61
|
+
* @param srcFilePaths An array of original file paths that were encrypted.
|
|
62
|
+
* @param destDir The directory containing the encrypted files.
|
|
63
|
+
* @param passphrase The passphrase used for decryption.
|
|
64
|
+
* @param iteration_count The number of iterations used for PBKDF2.
|
|
65
|
+
* @returns Resolves when all files are successfully decrypted.
|
|
66
|
+
* @throws {FailToDecryptFileError} If any file fails to decrypt.
|
|
67
|
+
*/
|
|
68
|
+
export declare function decryptFiles(srcFilePaths: string[], destDir: string, passphrase: string, iteration_count: number): Promise<void>;
|