secrez 2.1.14 → 2.1.16
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 +9 -0
- package/package.json +4 -4
- package/src/Welcome.js +0 -3
- package/src/commands/Conf.js +0 -19
- package/src/commands/Find.js +250 -8
package/README.md
CHANGED
|
@@ -368,6 +368,15 @@ Secrez is not intended to compete with password managers, so do not expect it to
|
|
|
368
368
|
|
|
369
369
|
## History
|
|
370
370
|
|
|
371
|
+
**2.1.16**
|
|
372
|
+
|
|
373
|
+
- remove legacy second-factor handling from the CLI (`Welcome`, `Conf`)
|
|
374
|
+
- refactor `git` command tests to use a local bare repository instead of a private GitHub remote (no SSH keys or external setup required)
|
|
375
|
+
|
|
376
|
+
**2.1.15**
|
|
377
|
+
|
|
378
|
+
- add `find -R` to look for recent entries only. With `-l` to set a limit (default 10)
|
|
379
|
+
|
|
371
380
|
**2.1.14**
|
|
372
381
|
|
|
373
382
|
- reverse changes done in version 2.1.12
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "secrez",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.16",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"nyc": {
|
|
6
6
|
"include": "src",
|
|
7
7
|
"exclude": []
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@secrez/core": "~1.0.
|
|
11
|
-
"@secrez/crypto": "~1.0.
|
|
10
|
+
"@secrez/core": "~1.0.7",
|
|
11
|
+
"@secrez/crypto": "~1.0.6",
|
|
12
12
|
"@secrez/eth": "~0.0.5",
|
|
13
13
|
"@secrez/fs": "~1.0.8",
|
|
14
14
|
"@secrez/utils": "~1.0.5",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"tiny-cli-editor": "^0.1.1"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@secrez/test-helpers": "~2.0.
|
|
32
|
+
"@secrez/test-helpers": "~2.0.2",
|
|
33
33
|
"chai": "^4.5.0",
|
|
34
34
|
"chalk": "^3.0.0",
|
|
35
35
|
"cross-env": "^7.0.3",
|
package/src/Welcome.js
CHANGED
package/src/commands/Conf.js
CHANGED
|
@@ -43,16 +43,6 @@ class Conf extends require("../Command") {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
async getAllFactors() {
|
|
47
|
-
let allFactors = {};
|
|
48
|
-
const conf = this.secrez.getConf();
|
|
49
|
-
let keys = conf.data.keys || {};
|
|
50
|
-
for (let authenticator in keys) {
|
|
51
|
-
allFactors[authenticator] = keys[authenticator].type;
|
|
52
|
-
}
|
|
53
|
-
return allFactors;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
46
|
async showConf(options) {
|
|
57
47
|
const env = await ConfigUtils.getEnv(this.secrez.config);
|
|
58
48
|
this.Logger.reset(chalk.grey("Container: ") + this.secrez.config.container);
|
|
@@ -86,10 +76,6 @@ class Conf extends require("../Command") {
|
|
|
86
76
|
"Changing password and number of iterations in the same operation not allowed"
|
|
87
77
|
);
|
|
88
78
|
}
|
|
89
|
-
let haveSomeFactors = false;
|
|
90
|
-
if (Object.keys(await this.getAllFactors()).length) {
|
|
91
|
-
haveSomeFactors = true;
|
|
92
|
-
}
|
|
93
79
|
let message =
|
|
94
80
|
"Are you sure you want to upgrade your " +
|
|
95
81
|
(pw ? "password" : "number of iterations") +
|
|
@@ -140,11 +126,6 @@ class Conf extends require("../Command") {
|
|
|
140
126
|
this.Logger.reset(
|
|
141
127
|
'In case you have doubts about it, please, "cat" the file and take a look before exiting.'
|
|
142
128
|
);
|
|
143
|
-
if (haveSomeFactors) {
|
|
144
|
-
this.Logger.yellow(
|
|
145
|
-
"All the second factors have been unregistered."
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
129
|
return;
|
|
149
130
|
}
|
|
150
131
|
}
|
package/src/commands/Find.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const chalk = require("chalk");
|
|
2
2
|
const { Node } = require("@secrez/fs");
|
|
3
|
+
const { config } = require("@secrez/core");
|
|
4
|
+
const Crypto = require("@secrez/crypto");
|
|
3
5
|
|
|
4
6
|
class Find extends require("../Command") {
|
|
5
7
|
setHelpAndCompletion() {
|
|
@@ -56,6 +58,18 @@ class Find extends require("../Command") {
|
|
|
56
58
|
type: Boolean,
|
|
57
59
|
hint: "If global, search also in trash",
|
|
58
60
|
},
|
|
61
|
+
{
|
|
62
|
+
name: "recent",
|
|
63
|
+
alias: "R",
|
|
64
|
+
type: Boolean,
|
|
65
|
+
hint: "Search for recent changes",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "limit",
|
|
69
|
+
alias: "l",
|
|
70
|
+
type: Number,
|
|
71
|
+
hint: "Limit the number of results (default: 10 when recent is enabled)",
|
|
72
|
+
},
|
|
59
73
|
];
|
|
60
74
|
}
|
|
61
75
|
|
|
@@ -83,11 +97,69 @@ class Find extends require("../Command") {
|
|
|
83
97
|
"Search scanning all the versions in all the datasets",
|
|
84
98
|
],
|
|
85
99
|
["find archive:allet", "Search allet in the archive dataset"],
|
|
100
|
+
["find -R", "Show the 10 most recent changes"],
|
|
101
|
+
["find -R -l 20", "Show the 20 most recent changes"],
|
|
86
102
|
],
|
|
87
103
|
};
|
|
88
104
|
}
|
|
89
105
|
|
|
90
106
|
async find(options) {
|
|
107
|
+
// Handle recent mode
|
|
108
|
+
if (options.recent) {
|
|
109
|
+
// Set default limit if not specified by user
|
|
110
|
+
if (options.limit === undefined) {
|
|
111
|
+
options.limit = 10;
|
|
112
|
+
}
|
|
113
|
+
// In recent mode, ignore keywords completely - just show the N most recent entries
|
|
114
|
+
options.name = undefined;
|
|
115
|
+
options.keywords = undefined;
|
|
116
|
+
|
|
117
|
+
if (options.global) {
|
|
118
|
+
let datasetInfo = await this.internalFs.getDatasetsInfo();
|
|
119
|
+
let allResults = [];
|
|
120
|
+
for (let dataset of datasetInfo) {
|
|
121
|
+
if (options.global && !options.trashToo && dataset.index === 1) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
await this.internalFs.mountTree(dataset.index);
|
|
125
|
+
options.tree = this.internalFs.trees[dataset.index];
|
|
126
|
+
options.dataset = dataset.name;
|
|
127
|
+
// Collect raw results (with ts property) for sorting across datasets
|
|
128
|
+
let rawResults = await this._findRecentRaw(options);
|
|
129
|
+
allResults = allResults.concat(rawResults);
|
|
130
|
+
}
|
|
131
|
+
// Sort all results together by timestamp and limit
|
|
132
|
+
allResults.sort((a, b) => {
|
|
133
|
+
return Node.sortEntry(a.ts, b.ts);
|
|
134
|
+
});
|
|
135
|
+
if (allResults.length > options.limit) {
|
|
136
|
+
allResults = allResults.slice(0, options.limit);
|
|
137
|
+
}
|
|
138
|
+
// Format results
|
|
139
|
+
return allResults.map((e) => {
|
|
140
|
+
let result = [
|
|
141
|
+
Node.hashVersion(e.ts),
|
|
142
|
+
e.path + (e.isDir ? "/" : ""),
|
|
143
|
+
e.name,
|
|
144
|
+
undefined,
|
|
145
|
+
];
|
|
146
|
+
// Store timestamp for date formatting in recent mode
|
|
147
|
+
result.ts = e.ts;
|
|
148
|
+
if (e.dataset) {
|
|
149
|
+
result[1] = e.dataset + ":" + result[1];
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
});
|
|
153
|
+
} else {
|
|
154
|
+
let data = await this.internalFs.getTreeIndexAndPath(".");
|
|
155
|
+
// Don't set dataset for non-global search (matches regular find behavior)
|
|
156
|
+
// Dataset prefix is only shown when searching globally
|
|
157
|
+
options.tree = data.tree;
|
|
158
|
+
return await this._findRecent(options);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Regular find mode
|
|
91
163
|
if (!options.name && options.keywords) {
|
|
92
164
|
options.name = options.keywords;
|
|
93
165
|
}
|
|
@@ -133,20 +205,155 @@ class Find extends require("../Command") {
|
|
|
133
205
|
});
|
|
134
206
|
}
|
|
135
207
|
|
|
208
|
+
async _findRecent(options) {
|
|
209
|
+
let rawResults = await this._findRecentRaw(options);
|
|
210
|
+
|
|
211
|
+
// Sort by timestamp (most recent first) and limit
|
|
212
|
+
rawResults.sort((a, b) => {
|
|
213
|
+
return Node.sortEntry(a.ts, b.ts);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Limit results
|
|
217
|
+
if (rawResults.length > options.limit) {
|
|
218
|
+
rawResults = rawResults.slice(0, options.limit);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Format results to match regular find output
|
|
222
|
+
return rawResults.map((e) => {
|
|
223
|
+
let result = [
|
|
224
|
+
Node.hashVersion(e.ts),
|
|
225
|
+
e.path + (e.isDir ? "/" : ""),
|
|
226
|
+
e.name,
|
|
227
|
+
undefined,
|
|
228
|
+
];
|
|
229
|
+
// Store timestamp for date formatting in recent mode
|
|
230
|
+
result.ts = e.ts;
|
|
231
|
+
// Only add dataset prefix if dataset is set (which happens in global mode)
|
|
232
|
+
if (options.dataset) {
|
|
233
|
+
result[1] = options.dataset + ":" + result[1];
|
|
234
|
+
}
|
|
235
|
+
return result;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async _findRecentRaw(options) {
|
|
240
|
+
let start = options.tree[options.root ? "root" : "workingNode"];
|
|
241
|
+
let results = [];
|
|
242
|
+
|
|
243
|
+
// Recursively collect all entries with their timestamps (no keyword filtering in recent mode)
|
|
244
|
+
await this._collectRecentEntries(start, results, options, null);
|
|
245
|
+
|
|
246
|
+
// Add dataset info to results for global mode
|
|
247
|
+
if (options.dataset) {
|
|
248
|
+
results = results.map((e) => {
|
|
249
|
+
e.dataset = options.dataset;
|
|
250
|
+
return e;
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return results;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async _collectRecentEntries(node, results, options, re) {
|
|
258
|
+
// Skip root node
|
|
259
|
+
if (Node.isRoot(node)) {
|
|
260
|
+
// Process children
|
|
261
|
+
if (node.children) {
|
|
262
|
+
for (let id in node.children) {
|
|
263
|
+
await this._collectRecentEntries(
|
|
264
|
+
node.children[id],
|
|
265
|
+
results,
|
|
266
|
+
options,
|
|
267
|
+
re
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Process current node if it has versions
|
|
275
|
+
if (node.versions && node.lastTs) {
|
|
276
|
+
let name = node.getName();
|
|
277
|
+
let path = node.getPath();
|
|
278
|
+
let isDir = Node.isDir(node);
|
|
279
|
+
|
|
280
|
+
// Filter by keywords if provided
|
|
281
|
+
if (re) {
|
|
282
|
+
if (re.test(name)) {
|
|
283
|
+
results.push({
|
|
284
|
+
ts: node.lastTs,
|
|
285
|
+
name: name,
|
|
286
|
+
path: path,
|
|
287
|
+
isDir: isDir,
|
|
288
|
+
});
|
|
289
|
+
} else if (
|
|
290
|
+
options.content &&
|
|
291
|
+
Node.isFile(node) &&
|
|
292
|
+
node.type === config.types.TEXT &&
|
|
293
|
+
options.tree
|
|
294
|
+
) {
|
|
295
|
+
// Check content if content option is enabled
|
|
296
|
+
try {
|
|
297
|
+
let { content } = await options.tree.getEntryDetails(
|
|
298
|
+
node,
|
|
299
|
+
node.lastTs
|
|
300
|
+
);
|
|
301
|
+
if (re.test(content || "")) {
|
|
302
|
+
results.push({
|
|
303
|
+
ts: node.lastTs,
|
|
304
|
+
name: name,
|
|
305
|
+
path: path,
|
|
306
|
+
isDir: isDir,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
} catch (e) {
|
|
310
|
+
// Ignore errors when reading content
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
// No keyword filter, include all entries
|
|
315
|
+
results.push({
|
|
316
|
+
ts: node.lastTs,
|
|
317
|
+
name: name,
|
|
318
|
+
path: path,
|
|
319
|
+
isDir: isDir,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Process children
|
|
325
|
+
if (node.children) {
|
|
326
|
+
for (let id in node.children) {
|
|
327
|
+
await this._collectRecentEntries(
|
|
328
|
+
node.children[id],
|
|
329
|
+
results,
|
|
330
|
+
options,
|
|
331
|
+
re
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
136
337
|
formatResult(result, re) {
|
|
137
|
-
if (re.test(result)) {
|
|
338
|
+
if (re && re.test(result)) {
|
|
138
339
|
return result.replace(re, (a) => chalk.bold(a));
|
|
139
340
|
} else {
|
|
140
341
|
return result;
|
|
141
342
|
}
|
|
142
343
|
}
|
|
143
344
|
|
|
345
|
+
formatDate(ts) {
|
|
346
|
+
let dateArray = Crypto.fromTsToDate(ts);
|
|
347
|
+
let date = dateArray[0].split("Z")[0].split("T")[0]; // Get YYYY-MM-DD format
|
|
348
|
+
return chalk.cyan(date);
|
|
349
|
+
}
|
|
350
|
+
|
|
144
351
|
formatIndex(len, i) {
|
|
145
352
|
return " ".repeat(len.toString().length - i.toString().length) + i;
|
|
146
353
|
}
|
|
147
354
|
|
|
148
355
|
formatList(list, options) {
|
|
149
|
-
let re = Node.getFindRe(options);
|
|
356
|
+
let re = options.name ? Node.getFindRe(options) : null;
|
|
150
357
|
let i = 0;
|
|
151
358
|
const setCache = (i, e) => {
|
|
152
359
|
this.prompt.setCache("findResult", i, e);
|
|
@@ -159,7 +366,7 @@ class Find extends require("../Command") {
|
|
|
159
366
|
let l = p.length;
|
|
160
367
|
let c = p[l - 1] ? p[l - 1] : p[l - 2];
|
|
161
368
|
if (e[2] && e[2] !== c) {
|
|
162
|
-
e[2] = this.formatResult(e[2], re, options.name);
|
|
369
|
+
e[2] = re ? this.formatResult(e[2], re, options.name) : e[2];
|
|
163
370
|
} else {
|
|
164
371
|
e[2] = undefined;
|
|
165
372
|
}
|
|
@@ -169,13 +376,29 @@ class Find extends require("../Command") {
|
|
|
169
376
|
" ",
|
|
170
377
|
chalk.yellow(e[0]),
|
|
171
378
|
" ",
|
|
172
|
-
this.formatResult(e[1], re, options.name),
|
|
379
|
+
re ? this.formatResult(e[1], re, options.name) : e[1],
|
|
173
380
|
" ",
|
|
174
381
|
e[2],
|
|
175
382
|
].join("");
|
|
176
383
|
} else {
|
|
177
384
|
setCache(i, e);
|
|
178
|
-
|
|
385
|
+
// In recent mode, show date before the path
|
|
386
|
+
if (options.recent && e.ts) {
|
|
387
|
+
let dateStr = this.formatDate(e.ts);
|
|
388
|
+
return [
|
|
389
|
+
k,
|
|
390
|
+
" ",
|
|
391
|
+
dateStr,
|
|
392
|
+
" ",
|
|
393
|
+
re ? this.formatResult(e[1], re, options.name) : e[1],
|
|
394
|
+
].join("");
|
|
395
|
+
} else {
|
|
396
|
+
return [
|
|
397
|
+
k,
|
|
398
|
+
" ",
|
|
399
|
+
re ? this.formatResult(e[1], re, options.name) : e[1],
|
|
400
|
+
].join("");
|
|
401
|
+
}
|
|
179
402
|
}
|
|
180
403
|
});
|
|
181
404
|
}
|
|
@@ -186,8 +409,8 @@ class Find extends require("../Command") {
|
|
|
186
409
|
}
|
|
187
410
|
try {
|
|
188
411
|
this.validate(options);
|
|
189
|
-
|
|
190
|
-
if (options.
|
|
412
|
+
// In recent mode, keywords are ignored - just show recent entries
|
|
413
|
+
if (options.recent) {
|
|
191
414
|
try {
|
|
192
415
|
this.lastResult = await this.find(options);
|
|
193
416
|
let list = this.formatList(this.lastResult, options);
|
|
@@ -203,7 +426,26 @@ class Find extends require("../Command") {
|
|
|
203
426
|
this.Logger.red(e.message);
|
|
204
427
|
}
|
|
205
428
|
} else {
|
|
206
|
-
|
|
429
|
+
// Regular find mode requires keywords
|
|
430
|
+
options.name = options.keywords;
|
|
431
|
+
if (options.name) {
|
|
432
|
+
try {
|
|
433
|
+
this.lastResult = await this.find(options);
|
|
434
|
+
let list = this.formatList(this.lastResult, options);
|
|
435
|
+
if (list && list.length) {
|
|
436
|
+
this.Logger.grey(
|
|
437
|
+
`${list.length} result${list.length > 1 ? "s" : ""} found:`
|
|
438
|
+
);
|
|
439
|
+
for (let l of list) this.Logger.reset(l);
|
|
440
|
+
} else {
|
|
441
|
+
this.Logger.grey("No results.");
|
|
442
|
+
}
|
|
443
|
+
} catch (e) {
|
|
444
|
+
this.Logger.red(e.message);
|
|
445
|
+
}
|
|
446
|
+
} else {
|
|
447
|
+
this.Logger.grey("Missing parameters");
|
|
448
|
+
}
|
|
207
449
|
}
|
|
208
450
|
} catch (e) {
|
|
209
451
|
this.Logger.red(e.message);
|