dsh-vault 0.6.8 → 0.7.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/lib/client.js +34 -34
- package/lib/index.js +24 -2
- package/lib/password.js +8 -0
- package/lib/store.js +10 -2
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -17,48 +17,48 @@ window.__ModuleLoader__.load({
|
|
|
17
17
|
document.head.appendChild(tag);
|
|
18
18
|
}
|
|
19
19
|
var VaultSection_module_css_default = {
|
|
20
|
-
"
|
|
21
|
-
"error": "t_j5va_error",
|
|
22
|
-
"modeAuto": "t_j5va_modeAuto",
|
|
23
|
-
"editorActions": "t_j5va_editorActions",
|
|
24
|
-
"reportTitle": "t_j5va_reportTitle",
|
|
25
|
-
"policyField": "t_j5va_policyField",
|
|
26
|
-
"rowActions": "t_j5va_rowActions",
|
|
27
|
-
"editorBody": "t_j5va_editorBody",
|
|
28
|
-
"kindFilter": "t_j5va_kindFilter",
|
|
29
|
-
"status": "t_j5va_status",
|
|
30
|
-
"modeAsk": "t_j5va_modeAsk",
|
|
31
|
-
"pinStar": "t_j5va_pinStar",
|
|
32
|
-
"rowMain": "t_j5va_rowMain",
|
|
33
|
-
"policyBar": "t_j5va_policyBar",
|
|
34
|
-
"editor": "t_j5va_editor",
|
|
35
|
-
"field": "t_j5va_field",
|
|
20
|
+
"list": "t_j5va_list",
|
|
36
21
|
"intro": "t_j5va_intro",
|
|
37
|
-
"
|
|
22
|
+
"emptyHint": "t_j5va_emptyHint",
|
|
23
|
+
"saveButton": "t_j5va_saveButton",
|
|
24
|
+
"identity": "t_j5va_identity",
|
|
25
|
+
"copied": "t_j5va_copied",
|
|
38
26
|
"secretField": "t_j5va_secretField",
|
|
39
|
-
"toolbar": "t_j5va_toolbar",
|
|
40
27
|
"totp": "t_j5va_totp",
|
|
28
|
+
"status": "t_j5va_status",
|
|
29
|
+
"policyField": "t_j5va_policyField",
|
|
30
|
+
"reportTitle": "t_j5va_reportTitle",
|
|
31
|
+
"dangerButton": "t_j5va_dangerButton",
|
|
32
|
+
"revealButton": "t_j5va_revealButton",
|
|
33
|
+
"deleteButton": "t_j5va_deleteButton",
|
|
34
|
+
"modeReadonly": "t_j5va_modeReadonly",
|
|
35
|
+
"error": "t_j5va_error",
|
|
36
|
+
"policyBar": "t_j5va_policyBar",
|
|
37
|
+
"editorActions": "t_j5va_editorActions",
|
|
38
|
+
"rowMain": "t_j5va_rowMain",
|
|
39
|
+
"reportBox": "t_j5va_reportBox",
|
|
40
|
+
"kindFilter": "t_j5va_kindFilter",
|
|
41
41
|
"highBadge": "t_j5va_highBadge",
|
|
42
42
|
"clearButton": "t_j5va_clearButton",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
43
|
+
"empty": "t_j5va_empty",
|
|
44
|
+
"editorBody": "t_j5va_editorBody",
|
|
45
|
+
"emptyBox": "t_j5va_emptyBox",
|
|
46
|
+
"kindIcon": "t_j5va_kindIcon",
|
|
47
|
+
"editor": "t_j5va_editor",
|
|
48
|
+
"addButton": "t_j5va_addButton",
|
|
49
|
+
"toolbar": "t_j5va_toolbar",
|
|
50
|
+
"section": "t_j5va_section",
|
|
51
|
+
"pinStar": "t_j5va_pinStar",
|
|
52
|
+
"title": "t_j5va_title",
|
|
45
53
|
"trashButton": "t_j5va_trashButton",
|
|
46
|
-
"footer": "t_j5va_footer",
|
|
47
|
-
"reportBox": "t_j5va_reportBox",
|
|
48
54
|
"row": "t_j5va_row",
|
|
49
|
-
"
|
|
50
|
-
"revealButton": "t_j5va_revealButton",
|
|
51
|
-
"saveButton": "t_j5va_saveButton",
|
|
52
|
-
"dangerButton": "t_j5va_dangerButton",
|
|
53
|
-
"section": "t_j5va_section",
|
|
55
|
+
"rowActions": "t_j5va_rowActions",
|
|
54
56
|
"reportLine": "t_j5va_reportLine",
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"emptyBox": "t_j5va_emptyBox",
|
|
61
|
-
"searchBox": "t_j5va_searchBox"
|
|
57
|
+
"footer": "t_j5va_footer",
|
|
58
|
+
"searchBox": "t_j5va_searchBox",
|
|
59
|
+
"modeAsk": "t_j5va_modeAsk",
|
|
60
|
+
"modeAuto": "t_j5va_modeAuto",
|
|
61
|
+
"field": "t_j5va_field"
|
|
62
62
|
};
|
|
63
63
|
//#endregion
|
|
64
64
|
//#region src/client/VaultSection.tsx
|
package/lib/index.js
CHANGED
|
@@ -504,6 +504,8 @@ export async function apply(ctx, config) {
|
|
|
504
504
|
symbols: { type: 'boolean', description: 'Include symbols (default true).' },
|
|
505
505
|
excludeAmbiguous: { type: 'boolean', description: 'Exclude 0/O/1/l/I (default false).' },
|
|
506
506
|
group: { type: 'integer', description: 'Insert "-" every N characters (e.g. 3 → vK7-mQ2-zt9).' },
|
|
507
|
+
prefix: { type: 'string', description: 'Fixed prefix prepended to the random core (site requirements).' },
|
|
508
|
+
suffix: { type: 'string', description: 'Fixed suffix appended to the random core (site requirements).' },
|
|
507
509
|
},
|
|
508
510
|
output: {
|
|
509
511
|
schema: {
|
|
@@ -525,6 +527,8 @@ export async function apply(ctx, config) {
|
|
|
525
527
|
...(args.symbols !== undefined ? { symbols: args.symbols } : {}),
|
|
526
528
|
...(args.excludeAmbiguous !== undefined ? { excludeAmbiguous: args.excludeAmbiguous } : {}),
|
|
527
529
|
...(args.group !== undefined ? { group: args.group } : {}),
|
|
530
|
+
...(args.prefix !== undefined ? { prefix: args.prefix } : {}),
|
|
531
|
+
...(args.suffix !== undefined ? { suffix: args.suffix } : {}),
|
|
528
532
|
});
|
|
529
533
|
return { password, length: password.length };
|
|
530
534
|
},
|
|
@@ -575,7 +579,7 @@ export async function apply(ctx, config) {
|
|
|
575
579
|
label: { type: 'string', description: 'Account label in the URI (default: entry title or "dsh-vault").' },
|
|
576
580
|
issuer: { type: 'string', description: 'Issuer name (default: "dsh-vault").' },
|
|
577
581
|
},
|
|
578
|
-
output: { schema: { type: 'object', additionalProperties: false, properties: { uri: { type: 'string', required: true }, qr: { type: 'string'
|
|
582
|
+
output: { schema: { type: 'object', additionalProperties: false, properties: { uri: { type: 'string', required: true }, qr: { type: 'string' } } }, render: (_a, v) => [{ type: 'text', text: v.uri }] },
|
|
579
583
|
async execute(args) {
|
|
580
584
|
if ((args.id === undefined) === (args.secret === undefined)) {
|
|
581
585
|
throw new Error('vault_totp_uri: provide exactly one of id or secret');
|
|
@@ -757,6 +761,24 @@ export async function apply(ctx, config) {
|
|
|
757
761
|
return { ok: issues.length === 0, issues };
|
|
758
762
|
},
|
|
759
763
|
}));
|
|
764
|
+
// ── vault_mask: redact likely secrets in free text ──────────────────────────
|
|
765
|
+
ctx.tools.register(defineTool({
|
|
766
|
+
name: 'vault_mask',
|
|
767
|
+
description: 'Redact likely credentials in arbitrary text (API keys, tokens, passwords, private keys) '
|
|
768
|
+
+ 'so it can be logged or quoted safely. Returns the masked text and a count of redactions.',
|
|
769
|
+
parameters: { text: { type: 'string', required: true, description: 'Text to mask.' } },
|
|
770
|
+
output: { schema: { type: 'object', additionalProperties: false, properties: { masked: { type: 'string', required: true }, redacted: { type: 'integer', required: true } } }, render: (_a, v) => [{ type: 'text', text: v.masked }] },
|
|
771
|
+
async execute(args) {
|
|
772
|
+
let count = 0;
|
|
773
|
+
const masked = args.text
|
|
774
|
+
.replace(/(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}/g, () => { count++; return '[REDACTED:TOKEN]'; })
|
|
775
|
+
.replace(/(npm|npms)_[A-Za-z0-9]{20,}/g, () => { count++; return '[REDACTED:NPM]'; })
|
|
776
|
+
.replace(/(sk|pk|rk|ak)_[A-Za-z0-9]{20,}/g, () => { count++; return '[REDACTED:KEY]'; })
|
|
777
|
+
.replace(/(-----BEGIN [A-Z ]*PRIVATE KEY-----)[\s\S]*?(-----END [A-Z ]*PRIVATE KEY-----)/g, () => { count++; return '[REDACTED:PRIVATE-KEY]'; })
|
|
778
|
+
.replace(/(Bearer\s+)[A-Za-z0-9._~+/-]+=*/gi, (m, p1) => { count++; return p1 + '[REDACTED:BEARER]'; });
|
|
779
|
+
return { masked, redacted: count };
|
|
780
|
+
},
|
|
781
|
+
}));
|
|
760
782
|
// ── vault_recent: most recently touched entries ─────────────────────────────
|
|
761
783
|
ctx.tools.register(defineTool({
|
|
762
784
|
name: 'vault_recent',
|
|
@@ -936,7 +958,7 @@ export async function apply(ctx, config) {
|
|
|
936
958
|
+ 'across entries. Returns non-secret findings (entry summaries grouped by the reused value).',
|
|
937
959
|
parameters: {},
|
|
938
960
|
output: {
|
|
939
|
-
schema: { type: 'object', additionalProperties: false, properties: { weak: { type: 'array', required: true, items: { type: 'json' } }, reused: { type: 'array', required: true, items: { type: 'json' } } } },
|
|
961
|
+
schema: { type: 'object', additionalProperties: false, properties: { weak: { type: 'array', required: true, items: { type: 'json' } }, reused: { type: 'array', required: true, items: { type: 'json' } }, strength: { type: 'json', required: true } } },
|
|
940
962
|
render: (_a, v) => [{ type: 'text', text: `weak: ${v.weak.length}, reused groups: ${v.reused.length}` }],
|
|
941
963
|
},
|
|
942
964
|
async execute() {
|
package/lib/password.js
CHANGED
|
@@ -73,6 +73,14 @@ export function generatePassword(options = {}) {
|
|
|
73
73
|
[chars[i], chars[j]] = [chars[j], chars[i]];
|
|
74
74
|
}
|
|
75
75
|
let password = chars.join('');
|
|
76
|
+
const coreLength = length;
|
|
77
|
+
void coreLength;
|
|
78
|
+
if (options.prefix !== undefined && options.prefix.length > 0) {
|
|
79
|
+
password = options.prefix + password;
|
|
80
|
+
}
|
|
81
|
+
if (options.suffix !== undefined && options.suffix.length > 0) {
|
|
82
|
+
password = password + options.suffix;
|
|
83
|
+
}
|
|
76
84
|
if (options.group !== undefined && options.group > 1 && password.length > options.group) {
|
|
77
85
|
password = password.match(new RegExp(`.{1,${options.group}}`, 'g')).join('-');
|
|
78
86
|
}
|
package/lib/store.js
CHANGED
|
@@ -371,13 +371,21 @@ export class VaultStore {
|
|
|
371
371
|
*/
|
|
372
372
|
health() {
|
|
373
373
|
const weak = [];
|
|
374
|
+
const strength = { weak: 0, fair: 0, strong: 0 };
|
|
374
375
|
const passwordCounts = new Map();
|
|
375
376
|
const keyCounts = new Map();
|
|
376
377
|
for (const entry of this.list()) {
|
|
377
378
|
const summary = toSummary(entry);
|
|
378
379
|
if (entry.password !== undefined) {
|
|
379
|
-
|
|
380
|
+
const len = entry.password.length;
|
|
381
|
+
if (len < VaultStore.MIN_PASSWORD_LENGTH) {
|
|
380
382
|
weak.push(summary);
|
|
383
|
+
strength.weak++;
|
|
384
|
+
}
|
|
385
|
+
else if (len < 20)
|
|
386
|
+
strength.fair++;
|
|
387
|
+
else
|
|
388
|
+
strength.strong++;
|
|
381
389
|
const list = passwordCounts.get(entry.password) ?? [];
|
|
382
390
|
list.push(summary);
|
|
383
391
|
passwordCounts.set(entry.password, list);
|
|
@@ -394,7 +402,7 @@ export class VaultStore {
|
|
|
394
402
|
...[...passwordCounts.entries()].filter(([, v]) => v.length > 1),
|
|
395
403
|
...[...keyCounts.entries()].filter(([, v]) => v.length > 1),
|
|
396
404
|
].map(([value, entries]) => ({ value, entries }));
|
|
397
|
-
return { weak, reused };
|
|
405
|
+
return { weak, reused, strength };
|
|
398
406
|
}
|
|
399
407
|
/**
|
|
400
408
|
* Export the whole vault (including trash) as a single encrypted blob under
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-vault",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Encrypted credential vault for DeepSeek Harness: store and retrieve usernames, emails, phone numbers, passwords, TOTP secrets, SSH/API-key/OAuth developer credentials through model tools and a Settings UI page.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|