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 CHANGED
@@ -17,48 +17,48 @@ window.__ModuleLoader__.load({
17
17
  document.head.appendChild(tag);
18
18
  }
19
19
  var VaultSection_module_css_default = {
20
- "addButton": "t_j5va_addButton",
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
- "empty": "t_j5va_empty",
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
- "copied": "t_j5va_copied",
44
- "identity": "t_j5va_identity",
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
- "list": "t_j5va_list",
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
- "deleteButton": "t_j5va_deleteButton",
56
- "kindIcon": "t_j5va_kindIcon",
57
- "title": "t_j5va_title",
58
- "emptyHint": "t_j5va_emptyHint",
59
- "modeReadonly": "t_j5va_modeReadonly",
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', required: true } } }, render: (_a, v) => [{ type: 'text', text: v.uri }] },
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
- if (entry.password.length < VaultStore.MIN_PASSWORD_LENGTH)
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.6.8",
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",