@typinghare/trick 2.0.1 β 2.1.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/LICENSE +22 -0
- package/README.md +175 -41
- package/dist/app.js +157 -65
- package/dist/color.d.ts +2 -0
- package/dist/color.js +7 -0
- package/dist/config.d.ts +45 -26
- package/dist/config.js +70 -29
- package/dist/console.d.ts +3 -0
- package/dist/console.js +9 -0
- package/dist/encrypt.d.ts +24 -32
- package/dist/encrypt.js +31 -38
- package/dist/error.d.ts +25 -6
- package/dist/error.js +36 -17
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/passphrase.d.ts +11 -3
- package/dist/passphrase.js +17 -11
- package/env.sh +1 -0
- package/package.json +27 -12
- package/src/app.ts +232 -155
- package/src/color.ts +9 -0
- package/src/config.ts +112 -69
- package/src/console.ts +11 -0
- package/src/encrypt.ts +104 -127
- package/src/error.ts +70 -57
- package/src/index.ts +3 -0
- package/src/passphrase.ts +21 -23
- package/test/resources/task_info.yml +4 -0
- package/test/resources/user_info.json +5 -0
- package/test/trick.config.json +16 -11
- package/test/resources/really.json +0 -4
- package/test/resources/task.yml +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 James Chen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
# [Trick](https://github.com/typinghare/trick)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Trick** is a CLI tool that helps you **safely encrypt sensitive files** (such as `.env`, API keys, or credentials) so they can be stored in Git repositories and easily restored on other machines or servers.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It uses **OpenSSL (AES-256-CBC + PBKDF2)** under the hood and keeps encryption keys **outside your repository**.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
* π Encrypt and decrypt sensitive files with strong encryption
|
|
10
|
+
* π― Group files into **targets**
|
|
11
|
+
* π¦ Store encrypted files under a dedicated `.trick/` directory
|
|
12
|
+
* ποΈ Keep passphrases outside your repo (per-target, permission-protected)
|
|
13
|
+
* π Works across machines and servers
|
|
14
|
+
* βοΈ Fully configurable, project-aware
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
6
19
|
# npm
|
|
7
20
|
npm install -g @typinghare/trick
|
|
8
21
|
|
|
@@ -13,81 +26,202 @@ pnpm add -g @typinghare/trick
|
|
|
13
26
|
yarn add -g @typinghare/trick
|
|
14
27
|
```
|
|
15
28
|
|
|
29
|
+
> **Requirements**
|
|
30
|
+
>
|
|
31
|
+
> * Node.js β₯ 18
|
|
32
|
+
> * `openssl` available in your system PATH
|
|
33
|
+
|
|
16
34
|
## Philosophy
|
|
17
35
|
|
|
18
|
-
|
|
36
|
+
Sensitive files are usually added to `.gitignore` to avoid accidental leaks.
|
|
37
|
+
But that means:
|
|
38
|
+
|
|
39
|
+
* You must manually copy them to every new machine
|
|
40
|
+
* Theyβre easy to lose
|
|
41
|
+
* They donβt version well
|
|
42
|
+
|
|
43
|
+
**Trick encrypts those files**, allowing you to commit the encrypted versions safely, while keeping passphrases out of Git entirely.
|
|
44
|
+
|
|
19
45
|
|
|
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
46
|
|
|
22
|
-
##
|
|
47
|
+
## Getting Started
|
|
23
48
|
|
|
24
|
-
|
|
49
|
+
### 1. Initialize Trick
|
|
50
|
+
|
|
51
|
+
Run this inside your project:
|
|
25
52
|
|
|
26
53
|
```bash
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
54
|
+
trick init
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This creates a `trick.config.json` in your project root.
|
|
58
|
+
|
|
30
59
|
|
|
31
|
-
|
|
32
|
-
|
|
60
|
+
|
|
61
|
+
### 2. Add Files to a Target
|
|
62
|
+
|
|
63
|
+
A **target** is a named group of files to encrypt together.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
trick add MyTarget .env api_key.conf
|
|
33
67
|
```
|
|
34
68
|
|
|
35
|
-
|
|
69
|
+
List all targets:
|
|
36
70
|
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
"MyTargetName": "Reg5eGPXWdmeW0i08uaygBlfbXP+tJlnu7z551Qt568="
|
|
40
|
-
}
|
|
71
|
+
```bash
|
|
72
|
+
trick list
|
|
41
73
|
```
|
|
42
74
|
|
|
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
75
|
|
|
45
|
-
|
|
76
|
+
|
|
77
|
+
### 3. Set a Passphrase for the Target
|
|
78
|
+
|
|
79
|
+
Each target has its **own passphrase file** stored locally (not in Git).
|
|
46
80
|
|
|
47
81
|
```bash
|
|
48
|
-
|
|
82
|
+
trick set-passphrase MyTarget
|
|
49
83
|
```
|
|
50
84
|
|
|
51
|
-
|
|
85
|
+
This creates a file at:
|
|
52
86
|
|
|
53
|
-
```text
|
|
54
|
-
[ENCRYPTED] .env -> .trick/encrypted/.env.enc
|
|
55
|
-
[ENCRYPTED] api_key.conf -> .trick/encrypted/api_key.conf.enc
|
|
56
87
|
```
|
|
88
|
+
~/.config/trick/passphrases/MyTarget
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
* File permissions are set to `600`
|
|
92
|
+
* You must manually edit this file and paste your passphrase
|
|
93
|
+
* The file content is read as plain text (trimmed)
|
|
57
94
|
|
|
58
|
-
|
|
95
|
+
> β οΈ **Important**
|
|
96
|
+
> Back up your passphrase files. Losing them means losing access to your encrypted data.
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
### 4. Encrypt Files
|
|
59
101
|
|
|
60
102
|
```bash
|
|
61
|
-
|
|
103
|
+
trick encrypt MyTarget
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Encrypted files are written to:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
.trick/<original-path>.enc
|
|
62
110
|
```
|
|
63
111
|
|
|
64
|
-
|
|
112
|
+
Example output:
|
|
65
113
|
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
|
|
114
|
+
```
|
|
115
|
+
π© Encrypted: .env -> .trick/.env.enc
|
|
116
|
+
π© Encrypted: api_key.conf -> .trick/api_key.conf.enc
|
|
69
117
|
```
|
|
70
118
|
|
|
71
|
-
|
|
72
|
-
> The `passphrase.json` collects all the passphrases you have. Please back it up in multiple devices every time you edit it!
|
|
119
|
+
You can now commit the `.trick/` directory safely.
|
|
73
120
|
|
|
74
|
-
## More Features
|
|
75
121
|
|
|
76
|
-
### Default Target Name
|
|
77
122
|
|
|
78
|
-
|
|
123
|
+
### 5. Decrypt Files (on another machine or server)
|
|
124
|
+
|
|
125
|
+
1. Copy or recreate the passphrase file:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
~/.config/trick/passphrases/MyTarget
|
|
129
|
+
```
|
|
130
|
+
2. Run:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
trick decrypt MyTarget
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Files are restored to their original locations.
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
## Default Targets
|
|
141
|
+
|
|
142
|
+
You can mark targets as **default**, so you donβt need to specify them every time.
|
|
79
143
|
|
|
80
144
|
```bash
|
|
81
|
-
|
|
82
|
-
|
|
145
|
+
trick add-default MyTarget
|
|
146
|
+
```
|
|
83
147
|
|
|
84
|
-
|
|
85
|
-
|
|
148
|
+
List default targets:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
trick list-defaults
|
|
86
152
|
```
|
|
87
153
|
|
|
88
|
-
Now you can
|
|
154
|
+
Now you can simply run:
|
|
89
155
|
|
|
90
156
|
```bash
|
|
91
|
-
|
|
92
|
-
|
|
157
|
+
trick encrypt
|
|
158
|
+
trick decrypt
|
|
93
159
|
```
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
## Configuration
|
|
164
|
+
|
|
165
|
+
### `trick.config.json`
|
|
166
|
+
|
|
167
|
+
Example:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"targets": {
|
|
172
|
+
"MyTarget": {
|
|
173
|
+
"files": [".env", "api_key.conf"]
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"trickRootDirectory": ".trick",
|
|
177
|
+
"passphraseDirectory": "~/.config/trick/passphrases",
|
|
178
|
+
"defaultTargetNames": ["MyTarget"],
|
|
179
|
+
"encryption": {
|
|
180
|
+
"iterationCount": 100000
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Key Fields
|
|
186
|
+
|
|
187
|
+
| Field | Description |
|
|
188
|
+
| ------------------------ | ------------------------------------- |
|
|
189
|
+
| `targets` | Mapping of target names to file lists |
|
|
190
|
+
| `trickRootDirectory` | Where encrypted files are stored |
|
|
191
|
+
| `passphraseDirectory` | Where passphrase files live |
|
|
192
|
+
| `defaultTargetNames` | Targets used when none specified |
|
|
193
|
+
| `encryption.iterationCount` | PBKDF2 iteration count |
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
## Commands Overview
|
|
198
|
+
|
|
199
|
+
| Command | Description |
|
|
200
|
+
| ---------------------------------- | -------------------------- |
|
|
201
|
+
| `trick init` | Initialize configuration |
|
|
202
|
+
| `trick config` | Print current config |
|
|
203
|
+
| `trick add <target> [files...]` | Add files to a target |
|
|
204
|
+
| `trick remove <target> [files...]` | Remove files from a target |
|
|
205
|
+
| `trick remove <target> --target` | Remove a target |
|
|
206
|
+
| `trick list` | List targets and files |
|
|
207
|
+
| `trick set-passphrase <target>` | Create passphrase file |
|
|
208
|
+
| `trick encrypt [targets...]` | Encrypt files |
|
|
209
|
+
| `trick decrypt [targets...]` | Decrypt files |
|
|
210
|
+
| `trick add-default [targets...]` | Add default targets |
|
|
211
|
+
| `trick list-defaults` | Show default targets |
|
|
212
|
+
|
|
213
|
+
## Security Notes
|
|
214
|
+
|
|
215
|
+
* Encryption uses:
|
|
216
|
+
|
|
217
|
+
* **AES-256-CBC**
|
|
218
|
+
* **PBKDF2** with configurable iteration count
|
|
219
|
+
* Passphrases:
|
|
220
|
+
|
|
221
|
+
* Never stored in Git
|
|
222
|
+
* Stored as local files with strict permissions
|
|
223
|
+
* Losing passphrases = losing access to encrypted files
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT
|
package/dist/app.js
CHANGED
|
@@ -1,27 +1,62 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { getTargetFromConfig, updateConfig } from './config.js';
|
|
2
|
+
import { CONFIG_FILE_NAME, getRootDirectory, getTargetFromConfig, updateConfig, } from './config.js';
|
|
3
3
|
import { decryptFiles, encryptFiles } from './encrypt.js';
|
|
4
4
|
import fsExtra from 'fs-extra';
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
5
|
+
import { getPassphrase, getPassphraseDirectory } from './passphrase.js';
|
|
6
|
+
import { resolveError } from './error.js';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { colorFilePath, colorTargetName } from './color.js';
|
|
9
|
+
import { success, warning } from './console.js';
|
|
8
10
|
const program = new Command();
|
|
9
|
-
program.version('2.0
|
|
11
|
+
program.version('2.1.0');
|
|
10
12
|
program.description('Save credential files to remote safely and easily.');
|
|
13
|
+
program
|
|
14
|
+
.command('config')
|
|
15
|
+
.description('Display the current configuration.')
|
|
16
|
+
.action(function () {
|
|
17
|
+
updateConfig((config) => {
|
|
18
|
+
console.log(JSON.stringify(config, null, 2));
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
program
|
|
22
|
+
.command('init')
|
|
23
|
+
.description('Initialize the configuration file.')
|
|
24
|
+
.option('-r, --root', 'Create the configuration file in the root directory.', false)
|
|
25
|
+
.action(function (options) {
|
|
26
|
+
const configFilePath = options.root
|
|
27
|
+
? path.join(getRootDirectory(), CONFIG_FILE_NAME)
|
|
28
|
+
: path.join(process.cwd(), CONFIG_FILE_NAME);
|
|
29
|
+
if (fsExtra.existsSync(configFilePath)) {
|
|
30
|
+
console.log(warning(`Configuration file already exists: ${configFilePath}`));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
updateConfig(() => true, options.root);
|
|
35
|
+
console.log(success(`Initialized configuration file: ${configFilePath}`));
|
|
36
|
+
}
|
|
37
|
+
});
|
|
11
38
|
program
|
|
12
39
|
.command('add')
|
|
13
40
|
.description('Add files to a target.')
|
|
14
|
-
.argument('<target>', 'The name of the target')
|
|
15
|
-
.argument('[files...]', 'Files that are
|
|
16
|
-
.action(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
target.files.push(...files);
|
|
21
|
-
}
|
|
22
|
-
catch (err) {
|
|
23
|
-
config.default_target_name = targetName;
|
|
41
|
+
.argument('<target>', 'The name of the target to add to')
|
|
42
|
+
.argument('[files...]', 'Files that are added to the target')
|
|
43
|
+
.action(function (targetName, files) {
|
|
44
|
+
updateConfig((config) => {
|
|
45
|
+
const target = config.targets[targetName];
|
|
46
|
+
if (!target) {
|
|
24
47
|
config.targets[targetName] = { files };
|
|
48
|
+
console.log(success(`Added files to target: ${targetName}`));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
for (const file of files) {
|
|
52
|
+
if (target.files.includes(file)) {
|
|
53
|
+
console.log(warning(`File already exists in the target: ${file}`));
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
target.files.push(file);
|
|
57
|
+
console.log(success(`Added file to target: ${file}`));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
25
60
|
}
|
|
26
61
|
return true;
|
|
27
62
|
});
|
|
@@ -29,13 +64,13 @@ program
|
|
|
29
64
|
program
|
|
30
65
|
.command('remove')
|
|
31
66
|
.description('Remove files from a target.')
|
|
32
|
-
.argument('<target>', 'The name of the target')
|
|
33
|
-
.argument('[files...]', 'Files to remove')
|
|
67
|
+
.argument('<target>', 'The name of the target to remove from')
|
|
68
|
+
.argument('[files...]', 'Files to remove from the target')
|
|
34
69
|
.option('-t, --target', 'Remove the target instead.')
|
|
35
|
-
.action(
|
|
70
|
+
.action(function (targetName, files, options) {
|
|
36
71
|
if (options.target) {
|
|
37
72
|
// Remove the target
|
|
38
|
-
return
|
|
73
|
+
return updateConfig((config) => {
|
|
39
74
|
getTargetFromConfig(config, targetName);
|
|
40
75
|
delete config.targets[targetName];
|
|
41
76
|
console.log(`[SUCCESS] Removed target: ${targetName}`);
|
|
@@ -43,14 +78,14 @@ program
|
|
|
43
78
|
});
|
|
44
79
|
}
|
|
45
80
|
// Remove files from the target
|
|
46
|
-
|
|
81
|
+
updateConfig((config) => {
|
|
47
82
|
const target = getTargetFromConfig(config, targetName);
|
|
48
83
|
const removedFiles = [];
|
|
49
84
|
const remainingFiles = [];
|
|
50
85
|
for (const file of target.files) {
|
|
51
86
|
if (files.includes(file)) {
|
|
52
87
|
removedFiles.push(file);
|
|
53
|
-
console.log(`
|
|
88
|
+
console.log(success(`Removed file: ${file}`));
|
|
54
89
|
}
|
|
55
90
|
else {
|
|
56
91
|
remainingFiles.push(file);
|
|
@@ -59,79 +94,136 @@ program
|
|
|
59
94
|
target.files = remainingFiles;
|
|
60
95
|
const notFoundFiles = files.filter((it) => !removedFiles.includes(it));
|
|
61
96
|
for (const notFoundFile of notFoundFiles) {
|
|
62
|
-
console.log(`
|
|
97
|
+
console.log(warning(`File not found in the target: ${notFoundFile}`));
|
|
63
98
|
}
|
|
64
99
|
return true;
|
|
65
100
|
});
|
|
66
101
|
});
|
|
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!');
|
|
71
|
-
}
|
|
72
|
-
return targetName;
|
|
73
|
-
}
|
|
74
102
|
program
|
|
75
103
|
.command('encrypt')
|
|
76
104
|
.description('Encrypt the credential files.')
|
|
77
|
-
.argument('[
|
|
78
|
-
.action(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
105
|
+
.argument('[targetNames...]', 'The names of targets')
|
|
106
|
+
.action(function (targetNames) {
|
|
107
|
+
updateConfig((config) => {
|
|
108
|
+
if (targetNames.length === 0) {
|
|
109
|
+
targetNames.push(...config.defaultTargetNames);
|
|
110
|
+
}
|
|
111
|
+
if (targetNames.length === 0) {
|
|
112
|
+
console.log(warning('No target names specified and no default targets set.'));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const rootDirectory = getRootDirectory();
|
|
116
|
+
const trickRootDirectory = path.resolve(rootDirectory, config.trickRootDirectory);
|
|
117
|
+
for (const targetName of targetNames) {
|
|
118
|
+
const target = getTargetFromConfig(config, targetName);
|
|
119
|
+
const passphrase = getPassphrase(config, targetName);
|
|
120
|
+
const srcFilePaths = target.files;
|
|
121
|
+
fsExtra.ensureDir(trickRootDirectory);
|
|
122
|
+
encryptFiles(srcFilePaths, trickRootDirectory, passphrase, config.encryption.iterationCount);
|
|
123
|
+
}
|
|
86
124
|
});
|
|
87
125
|
});
|
|
88
126
|
program
|
|
89
127
|
.command('decrypt')
|
|
90
128
|
.description('Decrypt the credential files.')
|
|
91
|
-
.argument('[
|
|
92
|
-
.action(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
129
|
+
.argument('[targetNames...]', 'The names of the targets')
|
|
130
|
+
.action(function (targetNames) {
|
|
131
|
+
updateConfig((config) => {
|
|
132
|
+
if (targetNames.length === 0) {
|
|
133
|
+
targetNames.push(...config.defaultTargetNames);
|
|
134
|
+
}
|
|
135
|
+
if (targetNames.length === 0) {
|
|
136
|
+
console.log(warning('No target names specified and no default targets set.'));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const rootDirectory = getRootDirectory();
|
|
140
|
+
const trickRootDirectory = path.resolve(rootDirectory, config.trickRootDirectory);
|
|
141
|
+
for (const targetName of targetNames) {
|
|
142
|
+
const target = getTargetFromConfig(config, targetName);
|
|
143
|
+
const passphrase = getPassphrase(config, targetName);
|
|
144
|
+
const srcFilePaths = target.files;
|
|
145
|
+
fsExtra.ensureDir(trickRootDirectory);
|
|
146
|
+
decryptFiles(srcFilePaths, trickRootDirectory, passphrase, config.encryption.iterationCount);
|
|
147
|
+
}
|
|
100
148
|
});
|
|
101
149
|
});
|
|
102
150
|
program
|
|
103
|
-
.command('
|
|
104
|
-
.description('
|
|
105
|
-
.argument('
|
|
106
|
-
.action(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
151
|
+
.command('add-default')
|
|
152
|
+
.description('Add default target names.')
|
|
153
|
+
.argument('[targetNames...]', 'The names of targets to add')
|
|
154
|
+
.action(function (targetNames) {
|
|
155
|
+
updateConfig((config) => {
|
|
156
|
+
let addedAny = false;
|
|
157
|
+
for (const targetName of targetNames) {
|
|
158
|
+
if (!config.targets[targetName]) {
|
|
159
|
+
console.log(warning(`Target not found: ${targetName}`));
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (config.defaultTargetNames.includes(targetName)) {
|
|
163
|
+
console.log(warning(`Target name already in default list: ${targetName}`));
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
config.defaultTargetNames.push(targetName);
|
|
167
|
+
console.log(success(`Added default target name: ${targetName}`));
|
|
168
|
+
addedAny = true;
|
|
169
|
+
}
|
|
170
|
+
return addedAny;
|
|
110
171
|
});
|
|
111
172
|
});
|
|
112
173
|
program
|
|
113
|
-
.command('
|
|
114
|
-
.description('
|
|
115
|
-
.action(
|
|
116
|
-
|
|
117
|
-
|
|
174
|
+
.command('list-defaults')
|
|
175
|
+
.description('Display the default target name.')
|
|
176
|
+
.action(function () {
|
|
177
|
+
updateConfig((config) => {
|
|
178
|
+
for (const targetName of config.defaultTargetNames) {
|
|
179
|
+
console.log(colorTargetName(targetName));
|
|
180
|
+
}
|
|
118
181
|
});
|
|
119
182
|
});
|
|
120
183
|
program
|
|
121
184
|
.command('list')
|
|
122
185
|
.description('Display a list of targets.')
|
|
123
|
-
.action(
|
|
124
|
-
|
|
186
|
+
.action(function () {
|
|
187
|
+
updateConfig((config) => {
|
|
125
188
|
for (const [targetName, target] of Object.entries(config.targets)) {
|
|
126
|
-
console.log(
|
|
189
|
+
console.log(colorTargetName(targetName));
|
|
127
190
|
for (const file of target.files) {
|
|
128
|
-
console.log(' ' +
|
|
191
|
+
console.log(' ' + colorFilePath(file));
|
|
129
192
|
}
|
|
130
193
|
}
|
|
131
194
|
});
|
|
132
195
|
});
|
|
133
|
-
program
|
|
196
|
+
program
|
|
197
|
+
.command('set-passphrase')
|
|
198
|
+
.description('Set passphrase for a target.')
|
|
199
|
+
.argument('<target>', 'The name of the target to set passphrase for')
|
|
200
|
+
.action(function (targetName) {
|
|
201
|
+
updateConfig((config) => {
|
|
202
|
+
const passphraseDirectory = getPassphraseDirectory(config);
|
|
203
|
+
if (!fsExtra.existsSync(passphraseDirectory)) {
|
|
204
|
+
fsExtra.ensureDirSync(passphraseDirectory);
|
|
205
|
+
console.log(success(`Created passphrase directory: ${passphraseDirectory}`));
|
|
206
|
+
}
|
|
207
|
+
const passphraseFile = path.join(passphraseDirectory, targetName);
|
|
208
|
+
if (!fsExtra.existsSync(passphraseFile)) {
|
|
209
|
+
fsExtra.createFileSync(passphraseFile);
|
|
210
|
+
fsExtra.chmodSync(passphraseFile, 0o600);
|
|
211
|
+
console.log(success(`Created passphrase file: ${passphraseFile}`));
|
|
212
|
+
console.log(success(`You have to edit the file to set the passphrase.`));
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.log(warning(`Passphrase file already exists: ${passphraseFile}`));
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
try {
|
|
220
|
+
program.parse();
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
resolveError(err);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
134
226
|
process.on('uncaughtException', (err) => {
|
|
135
|
-
|
|
227
|
+
resolveError(err);
|
|
136
228
|
process.exit(1);
|
|
137
229
|
});
|
package/dist/color.d.ts
ADDED