secrez 1.1.1 → 1.1.3
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 +503 -444
- package/bin/secrez.js +50 -47
- package/coverage.report +91 -85
- package/package.json +10 -12
- package/src/Command.js +78 -57
- package/src/PreCommand.js +75 -70
- package/src/Welcome.js +144 -134
- package/src/cliConfig.js +14 -14
- package/src/commands/Alias.js +123 -100
- package/src/commands/Bash.js +10 -12
- package/src/commands/Cat.js +117 -107
- package/src/commands/Cd.js +39 -42
- package/src/commands/Chat.js +75 -63
- package/src/commands/Conf.js +123 -99
- package/src/commands/Contacts.js +189 -171
- package/src/commands/Copy.js +132 -113
- package/src/commands/Courier.js +123 -105
- package/src/commands/Ds.js +88 -76
- package/src/commands/Edit.js +122 -103
- package/src/commands/Export.js +201 -116
- package/src/commands/Find.js +115 -110
- package/src/commands/Help.js +20 -23
- package/src/commands/Import.js +296 -225
- package/src/commands/Lcat.js +36 -39
- package/src/commands/Lcd.js +38 -39
- package/src/commands/Lls.js +58 -55
- package/src/commands/Lpwd.js +20 -24
- package/src/commands/Ls.js +107 -97
- package/src/commands/Mkdir.js +35 -38
- package/src/commands/Mv.js +147 -114
- package/src/commands/Paste.js +68 -65
- package/src/commands/Pwd.js +18 -23
- package/src/commands/Quit.js +22 -24
- package/src/commands/Rm.js +78 -70
- package/src/commands/Shell.js +31 -32
- package/src/commands/Ssh.js +77 -63
- package/src/commands/Tag.js +133 -112
- package/src/commands/Totp.js +166 -136
- package/src/commands/Touch.js +169 -56
- package/src/commands/Use.js +44 -41
- package/src/commands/Ver.js +16 -18
- package/src/commands/Whoami.js +34 -37
- package/src/commands/chat/Contacts.js +41 -44
- package/src/commands/chat/Help.js +20 -23
- package/src/commands/chat/Join.js +59 -55
- package/src/commands/chat/Leave.js +16 -22
- package/src/commands/chat/Quit.js +19 -24
- package/src/commands/chat/Send.js +58 -57
- package/src/commands/chat/Show.js +60 -51
- package/src/commands/chat/Whoami.js +18 -22
- package/src/commands/index.js +20 -22
- package/src/index.js +3 -3
- package/src/prompts/ChatPrompt.js +87 -82
- package/src/prompts/ChatPromptMock.js +11 -17
- package/src/prompts/CommandPrompt.js +146 -138
- package/src/prompts/Completion.js +64 -69
- package/src/prompts/MainPrompt.js +84 -77
- package/src/prompts/MainPromptMock.js +19 -30
- package/src/prompts/MultiEditorPrompt.js +21 -22
- package/src/prompts/SigintManager.js +21 -24
- package/src/utils/AliasManager.js +16 -18
- package/src/utils/ContactManager.js +15 -17
- package/src/utils/Fido2Client.js +59 -49
- package/src/utils/HelpProto.js +130 -117
- package/src/utils/Logger.js +48 -50
- package/.eslintignore +0 -0
- package/.eslintrc +0 -33
- package/.jshintrc +0 -3
package/src/commands/Export.js
CHANGED
@@ -1,197 +1,282 @@
|
|
1
|
-
const fs = require(
|
2
|
-
const path = require(
|
3
|
-
const chalk = require(
|
1
|
+
const fs = require("fs-extra");
|
2
|
+
const path = require("path");
|
3
|
+
const chalk = require("chalk");
|
4
4
|
|
5
|
-
const Crypto = require(
|
6
|
-
const {sleep} = require(
|
7
|
-
|
8
|
-
const {Node, FileCipher} = require(
|
9
|
-
|
10
|
-
class Export extends require('../Command') {
|
5
|
+
const Crypto = require("@secrez/crypto");
|
6
|
+
const { sleep, yamlParse } = require("@secrez/utils");
|
7
|
+
const { encryptPrivateKeyAsKeystoreJson } = require("@secrez/eth");
|
8
|
+
const { Node, FileCipher } = require("@secrez/fs");
|
11
9
|
|
10
|
+
class Export extends require("../Command") {
|
12
11
|
setHelpAndCompletion() {
|
13
12
|
this.cliConfig.completion.export = {
|
14
13
|
_func: this.selfCompletion(this),
|
15
|
-
_self: this
|
16
|
-
}
|
17
|
-
this.cliConfig.completion.help.export = true
|
14
|
+
_self: this,
|
15
|
+
};
|
16
|
+
this.cliConfig.completion.help.export = true;
|
18
17
|
this.optionDefinitions = [
|
19
18
|
{
|
20
|
-
name:
|
21
|
-
alias:
|
22
|
-
type: Boolean
|
19
|
+
name: "help",
|
20
|
+
alias: "h",
|
21
|
+
type: Boolean,
|
23
22
|
},
|
24
23
|
{
|
25
|
-
name:
|
26
|
-
completionType:
|
27
|
-
alias:
|
24
|
+
name: "path",
|
25
|
+
completionType: "file",
|
26
|
+
alias: "p",
|
28
27
|
defaultOption: true,
|
29
|
-
type: String
|
28
|
+
type: String,
|
30
29
|
},
|
31
30
|
{
|
32
|
-
name:
|
33
|
-
alias:
|
34
|
-
type: Boolean
|
31
|
+
name: "version",
|
32
|
+
alias: "v",
|
33
|
+
type: Boolean,
|
35
34
|
},
|
36
35
|
{
|
37
|
-
name:
|
38
|
-
alias:
|
39
|
-
type: Number
|
36
|
+
name: "duration",
|
37
|
+
alias: "d",
|
38
|
+
type: Number,
|
40
39
|
},
|
41
40
|
{
|
42
|
-
name:
|
43
|
-
alias:
|
44
|
-
type: Boolean
|
41
|
+
name: "encrypt",
|
42
|
+
alias: "e",
|
43
|
+
type: Boolean,
|
45
44
|
},
|
46
45
|
{
|
47
|
-
name:
|
48
|
-
alias:
|
46
|
+
name: "contacts",
|
47
|
+
alias: "c",
|
49
48
|
multiple: true,
|
50
|
-
type: String
|
49
|
+
type: String,
|
51
50
|
},
|
52
51
|
{
|
53
|
-
name:
|
52
|
+
name: "public-keys",
|
54
53
|
multiple: true,
|
55
|
-
type: String
|
54
|
+
type: String,
|
56
55
|
},
|
57
56
|
{
|
58
|
-
name:
|
59
|
-
type: String
|
57
|
+
name: "password",
|
58
|
+
type: String,
|
60
59
|
},
|
61
60
|
{
|
62
|
-
name:
|
63
|
-
type: Boolean
|
64
|
-
}
|
65
|
-
|
61
|
+
name: "include-me",
|
62
|
+
type: Boolean,
|
63
|
+
},
|
64
|
+
{
|
65
|
+
name: "keystore",
|
66
|
+
alias: "k",
|
67
|
+
type: Boolean,
|
68
|
+
},
|
69
|
+
];
|
66
70
|
}
|
67
71
|
|
68
72
|
help() {
|
69
73
|
return {
|
70
74
|
description: [
|
71
|
-
|
72
|
-
|
75
|
+
"Export encrypted data to the OS in the current local folder",
|
76
|
+
"Files and folders are decrypted during the process.",
|
73
77
|
],
|
74
78
|
examples: [
|
75
|
-
[
|
76
|
-
[
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
[
|
81
|
-
[
|
82
|
-
|
83
|
-
|
84
|
-
|
79
|
+
["export seed.json", "decrypts and copies seed.json to the disk"],
|
80
|
+
[
|
81
|
+
"export seed.json -d 30",
|
82
|
+
"export seed.json and remove it from disk after 30 seconds",
|
83
|
+
],
|
84
|
+
["export ethKeys -v 8uW3", "exports version 8uW3 of the file"],
|
85
|
+
[
|
86
|
+
"export seed.json -e",
|
87
|
+
'asks for a password and encrypts seed.json before exporting it. The final file will have the extension ".secrez"',
|
88
|
+
],
|
89
|
+
[
|
90
|
+
'export seed.json -e --password "some strong password"',
|
91
|
+
"uses the typed password to encrypt seed.json before exporting it",
|
92
|
+
],
|
93
|
+
[
|
94
|
+
"export seed.json -ec bob alice",
|
95
|
+
"encrypts seed.json using a key shared with the contacts Bob and Alice, before exporting it",
|
96
|
+
],
|
97
|
+
[
|
98
|
+
"export seed.json -e --public-keys TCpDvTiVpHwNiS....",
|
99
|
+
"encrypts seed.json using shared keys generated from the specified public keys",
|
100
|
+
],
|
101
|
+
[
|
102
|
+
"export seed.json -e --include-me",
|
103
|
+
"encrypts seed.json also using your key",
|
104
|
+
],
|
105
|
+
[
|
106
|
+
"export my-wallet.yml -k",
|
107
|
+
"it will export a private key from the entry to a keystore file. The fill will be named as the entry replacing the extension with '.keystore.json'. If in the entry there are more than one private_key, it will ask which one to export. If no '--password' is specified, it will ask for a password to encrypt the keystore file. The entry must be a valid card, with at least one 'private_key' field.",
|
108
|
+
],
|
109
|
+
],
|
110
|
+
};
|
85
111
|
}
|
86
112
|
|
87
113
|
async export(options = {}) {
|
88
|
-
let efs = this.externalFs
|
89
|
-
let fileCipher = new FileCipher(this.secrez)
|
90
|
-
let cat = this.prompt.commands.cat
|
91
|
-
let lpwd = this.prompt.commands.lpwd
|
92
|
-
let originalPath = options.path
|
93
|
-
let data = await this.internalFs.getTreeIndexAndPath(options.path)
|
94
|
-
options.path = data.path
|
95
|
-
let tree = data.tree
|
96
|
-
let p = tree.getNormalizedPath(options.path)
|
97
|
-
let file = tree.root.getChildFromPath(p)
|
114
|
+
let efs = this.externalFs;
|
115
|
+
let fileCipher = new FileCipher(this.secrez);
|
116
|
+
let cat = this.prompt.commands.cat;
|
117
|
+
let lpwd = this.prompt.commands.lpwd;
|
118
|
+
let originalPath = options.path;
|
119
|
+
let data = await this.internalFs.getTreeIndexAndPath(options.path);
|
120
|
+
options.path = data.path;
|
121
|
+
let tree = data.tree;
|
122
|
+
let p = tree.getNormalizedPath(options.path);
|
123
|
+
let file = tree.root.getChildFromPath(p);
|
98
124
|
if (Node.isFile(file)) {
|
99
|
-
let entry = (
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
let
|
107
|
-
let
|
108
|
-
|
109
|
-
|
125
|
+
let entry = (
|
126
|
+
await cat.cat({
|
127
|
+
path: originalPath,
|
128
|
+
version: options.version,
|
129
|
+
unformatted: true,
|
130
|
+
})
|
131
|
+
)[0];
|
132
|
+
let dir = await lpwd.lpwd();
|
133
|
+
let newPath = path.join(
|
134
|
+
dir,
|
135
|
+
path.basename(p) +
|
136
|
+
(options.encrypt ? ".secrez" + (Node.isBinary(entry) ? "b" : "") : "")
|
137
|
+
);
|
138
|
+
let name = await efs.getVersionedBasename(newPath);
|
139
|
+
let content = entry.content;
|
140
|
+
if (Node.isBinary(entry) && typeof content === "string") {
|
141
|
+
content = Crypto.bs64.decode(content);
|
110
142
|
}
|
111
|
-
if (options.
|
112
|
-
|
143
|
+
if (options.keystore) {
|
144
|
+
let card;
|
145
|
+
try {
|
146
|
+
card = yamlParse(content);
|
147
|
+
} catch (e) {
|
148
|
+
throw new Error("The entry is not a valid card");
|
149
|
+
}
|
150
|
+
let pks = [];
|
151
|
+
for (let k in card) {
|
152
|
+
if (/private_key/.test(k)) {
|
153
|
+
pks.push(k);
|
154
|
+
}
|
155
|
+
}
|
156
|
+
if (!pks.length) {
|
157
|
+
throw new Error("The entry does not contain any private key");
|
158
|
+
}
|
159
|
+
let privateKey = card[pks[0]];
|
160
|
+
if (pks.length > 1) {
|
161
|
+
let pk = await this.useInput({
|
162
|
+
type: "list",
|
163
|
+
message: "Which private key do you want to export?",
|
164
|
+
choices: pks,
|
165
|
+
});
|
166
|
+
privateKey = card[pk];
|
167
|
+
}
|
168
|
+
let pwd =
|
169
|
+
options.password ||
|
170
|
+
(await this.useInput({
|
171
|
+
type: "password",
|
172
|
+
message: "Type the password to encrypt the keystore file",
|
173
|
+
}));
|
174
|
+
if (!pwd) {
|
175
|
+
throw new Error("Operation canceled");
|
176
|
+
}
|
177
|
+
content = await encryptPrivateKeyAsKeystoreJson(privateKey, pwd);
|
178
|
+
name = name.replace(/\.[^.]+$/, ".keystore.json");
|
179
|
+
} else if (options.encrypt) {
|
180
|
+
const myPublicKey = this.secrez.getPublicKey();
|
113
181
|
if (options.publicKeys) {
|
114
|
-
if (
|
115
|
-
options.
|
182
|
+
if (
|
183
|
+
options.includeMe &&
|
184
|
+
options.publicKeys.indexOf(myPublicKey) === -1
|
185
|
+
) {
|
186
|
+
options.publicKeys.push(myPublicKey);
|
116
187
|
}
|
117
188
|
} else if (options.contacts) {
|
118
|
-
options.publicKeys = await this.getContactsPublicKeys(options)
|
189
|
+
options.publicKeys = await this.getContactsPublicKeys(options);
|
119
190
|
if (options.includeMe) {
|
120
|
-
options.publicKeys.push(myPublicKey)
|
191
|
+
options.publicKeys.push(myPublicKey);
|
121
192
|
}
|
122
193
|
} else if (options.includeMe) {
|
123
|
-
options.publicKeys = [myPublicKey]
|
194
|
+
options.publicKeys = [myPublicKey];
|
124
195
|
} else {
|
125
|
-
let pwd =
|
126
|
-
|
127
|
-
|
128
|
-
|
196
|
+
let pwd =
|
197
|
+
options.password ||
|
198
|
+
(await this.useInput({
|
199
|
+
type: "password",
|
200
|
+
message: "Type the password",
|
201
|
+
}));
|
129
202
|
if (!pwd) {
|
130
|
-
throw new Error(
|
203
|
+
throw new Error("Operation canceled");
|
131
204
|
}
|
132
|
-
let pwd2 =
|
133
|
-
|
134
|
-
|
135
|
-
|
205
|
+
let pwd2 =
|
206
|
+
options.password ||
|
207
|
+
(await this.useInput({
|
208
|
+
type: "password",
|
209
|
+
message: "Retype it",
|
210
|
+
}));
|
136
211
|
if (!pwd2) {
|
137
|
-
throw new Error(
|
212
|
+
throw new Error("Operation canceled");
|
138
213
|
}
|
139
214
|
if (pwd !== pwd2) {
|
140
|
-
throw new Error(
|
215
|
+
throw new Error("The two password do not match");
|
141
216
|
}
|
142
|
-
options.password = pwd
|
217
|
+
options.password = pwd;
|
143
218
|
}
|
144
|
-
content = fileCipher.encryptFile(content, options).join(
|
219
|
+
content = fileCipher.encryptFile(content, options).join(",");
|
145
220
|
}
|
146
|
-
let fn = path.join(dir, name)
|
147
|
-
await fs.writeFile(fn, content)
|
221
|
+
let fn = path.join(dir, name);
|
222
|
+
await fs.writeFile(fn, content);
|
148
223
|
if (options.duration) {
|
149
|
-
|
224
|
+
// we do not wait for the deletion
|
225
|
+
this.deleteFromDisk(fn, options.duration).then();
|
150
226
|
}
|
151
|
-
return name
|
227
|
+
return name;
|
152
228
|
} else {
|
153
|
-
throw new Error(
|
229
|
+
throw new Error("Cannot export a folder");
|
154
230
|
}
|
155
231
|
}
|
156
232
|
|
157
233
|
async getContactsPublicKeys(options) {
|
158
|
-
let contacts = await this.prompt.commands.contacts.contacts({
|
159
|
-
|
234
|
+
let contacts = await this.prompt.commands.contacts.contacts({
|
235
|
+
list: true,
|
236
|
+
asIs: true,
|
237
|
+
});
|
238
|
+
let publicKeys = [];
|
160
239
|
for (let contact of contacts) {
|
161
240
|
if (options.contacts.indexOf(contact[0]) !== -1) {
|
162
|
-
publicKeys.push(contact[1].publicKey)
|
241
|
+
publicKeys.push(contact[1].publicKey);
|
163
242
|
}
|
164
243
|
}
|
165
|
-
return publicKeys
|
244
|
+
return publicKeys;
|
166
245
|
}
|
167
246
|
|
168
247
|
async deleteFromDisk(fn, duration) {
|
169
|
-
await sleep(1000 * duration)
|
248
|
+
await sleep(1000 * duration);
|
170
249
|
if (await fs.pathExists(fn)) {
|
171
|
-
fs.unlink(fn)
|
250
|
+
fs.unlink(fn);
|
172
251
|
}
|
173
252
|
}
|
174
253
|
|
175
254
|
async exec(options = {}) {
|
176
255
|
if (options.help) {
|
177
|
-
return this.showHelp()
|
256
|
+
return this.showHelp();
|
178
257
|
}
|
179
258
|
try {
|
180
|
-
this.validate(options)
|
181
|
-
let name = await this.export(options)
|
182
|
-
this.Logger.grey(
|
183
|
-
this.Logger.reset(name)
|
184
|
-
if (
|
185
|
-
|
186
|
-
|
259
|
+
this.validate(options);
|
260
|
+
let name = await this.export(options);
|
261
|
+
this.Logger.grey("Exported file:");
|
262
|
+
this.Logger.reset(name);
|
263
|
+
if (
|
264
|
+
options.encrypt &&
|
265
|
+
!options.password &&
|
266
|
+
!options.includeMe &&
|
267
|
+
!this.alerted
|
268
|
+
) {
|
269
|
+
this.Logger.yellow(
|
270
|
+
chalk.red("One time alert: ") +
|
271
|
+
"Only the users for which you encrypted the data can decrypt it; not even you can decrypt the exported data. Be careful!"
|
272
|
+
);
|
273
|
+
this.alerted = true;
|
187
274
|
}
|
188
275
|
} catch (e) {
|
189
|
-
this.Logger.red(e.message)
|
276
|
+
this.Logger.red(e.message);
|
190
277
|
}
|
191
|
-
await this.prompt.run()
|
278
|
+
await this.prompt.run();
|
192
279
|
}
|
193
280
|
}
|
194
281
|
|
195
|
-
module.exports = Export
|
196
|
-
|
197
|
-
|
282
|
+
module.exports = Export;
|