dsh-vault 1.2.0-rc.2 → 1.2.0-rc.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/lib/client.js +61 -61
- package/lib/index.js +174 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -17,80 +17,80 @@ window.__ModuleLoader__.load({
|
|
|
17
17
|
document.head.appendChild(tag);
|
|
18
18
|
}
|
|
19
19
|
var VaultSection_module_css_default = {
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"emptyHint": "t_j5va_emptyHint",
|
|
24
|
-
"status": "t_j5va_status",
|
|
25
|
-
"kindIcon": "t_j5va_kindIcon",
|
|
26
|
-
"searchBox": "t_j5va_searchBox",
|
|
27
|
-
"intro": "t_j5va_intro",
|
|
28
|
-
"detailItem": "t_j5va_detailItem",
|
|
29
|
-
"policyField": "t_j5va_policyField",
|
|
30
|
-
"field": "t_j5va_field",
|
|
31
|
-
"pwFair": "t_j5va_pwFair",
|
|
32
|
-
"identity": "t_j5va_identity",
|
|
33
|
-
"checkField": "t_j5va_checkField",
|
|
34
|
-
"pwLabel": "t_j5va_pwLabel",
|
|
35
|
-
"dupGroup": "t_j5va_dupGroup",
|
|
36
|
-
"modeReadonly": "t_j5va_modeReadonly",
|
|
37
|
-
"badge": "t_j5va_badge",
|
|
38
|
-
"dupNames": "t_j5va_dupNames",
|
|
39
|
-
"badgeWarn": "t_j5va_badgeWarn",
|
|
40
|
-
"auditRow": "t_j5va_auditRow",
|
|
41
|
-
"genOptRow": "t_j5va_genOptRow",
|
|
20
|
+
"sortButton": "t_j5va_sortButton",
|
|
21
|
+
"reportLine": "t_j5va_reportLine",
|
|
22
|
+
"clearButton": "t_j5va_clearButton",
|
|
42
23
|
"rowDue": "t_j5va_rowDue",
|
|
43
|
-
"
|
|
24
|
+
"dangerButton": "t_j5va_dangerButton",
|
|
44
25
|
"detailBox": "t_j5va_detailBox",
|
|
26
|
+
"scoreRing": "t_j5va_scoreRing",
|
|
45
27
|
"emptyBox": "t_j5va_emptyBox",
|
|
28
|
+
"totpRing": "t_j5va_totpRing",
|
|
29
|
+
"pwFair": "t_j5va_pwFair",
|
|
30
|
+
"policyBar": "t_j5va_policyBar",
|
|
31
|
+
"footer": "t_j5va_footer",
|
|
32
|
+
"editor": "t_j5va_editor",
|
|
33
|
+
"healthBar": "t_j5va_healthBar",
|
|
34
|
+
"lockedBanner": "t_j5va_lockedBanner",
|
|
35
|
+
"kindIcon": "t_j5va_kindIcon",
|
|
36
|
+
"pwLabel": "t_j5va_pwLabel",
|
|
46
37
|
"rowActions": "t_j5va_rowActions",
|
|
47
|
-
"
|
|
38
|
+
"badge": "t_j5va_badge",
|
|
39
|
+
"editorActions": "t_j5va_editorActions",
|
|
40
|
+
"retryButton": "t_j5va_retryButton",
|
|
41
|
+
"rowMain": "t_j5va_rowMain",
|
|
48
42
|
"reportTitle": "t_j5va_reportTitle",
|
|
49
|
-
"
|
|
50
|
-
"pwWeak": "t_j5va_pwWeak",
|
|
43
|
+
"secretField": "t_j5va_secretField",
|
|
51
44
|
"copied": "t_j5va_copied",
|
|
52
|
-
"scoreRing": "t_j5va_scoreRing",
|
|
53
|
-
"dangerButton": "t_j5va_dangerButton",
|
|
54
|
-
"pwBar": "t_j5va_pwBar",
|
|
55
|
-
"list": "t_j5va_list",
|
|
56
|
-
"error": "t_j5va_error",
|
|
57
|
-
"sortButton": "t_j5va_sortButton",
|
|
58
|
-
"editorBody": "t_j5va_editorBody",
|
|
59
|
-
"trashButton": "t_j5va_trashButton",
|
|
60
|
-
"retryButton": "t_j5va_retryButton",
|
|
61
|
-
"title": "t_j5va_title",
|
|
62
45
|
"badgeOk": "t_j5va_badgeOk",
|
|
63
|
-
"dupMerge": "t_j5va_dupMerge",
|
|
64
|
-
"reportLine": "t_j5va_reportLine",
|
|
65
|
-
"totp": "t_j5va_totp",
|
|
66
|
-
"reportSub": "t_j5va_reportSub",
|
|
67
|
-
"secretField": "t_j5va_secretField",
|
|
68
|
-
"genOpts": "t_j5va_genOpts",
|
|
69
|
-
"dueBadge": "t_j5va_dueBadge",
|
|
70
|
-
"rowMain": "t_j5va_rowMain",
|
|
71
|
-
"revealButton": "t_j5va_revealButton",
|
|
72
|
-
"pinStar": "t_j5va_pinStar",
|
|
73
|
-
"rowExpired": "t_j5va_rowExpired",
|
|
74
|
-
"pwMeter": "t_j5va_pwMeter",
|
|
75
|
-
"lockedBanner": "t_j5va_lockedBanner",
|
|
76
46
|
"modeAuto": "t_j5va_modeAuto",
|
|
77
|
-
"
|
|
47
|
+
"addButton": "t_j5va_addButton",
|
|
78
48
|
"badgeDanger": "t_j5va_badgeDanger",
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
49
|
+
"status": "t_j5va_status",
|
|
50
|
+
"reportBox": "t_j5va_reportBox",
|
|
51
|
+
"pinStar": "t_j5va_pinStar",
|
|
52
|
+
"dupMerge": "t_j5va_dupMerge",
|
|
82
53
|
"pwStrong": "t_j5va_pwStrong",
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
54
|
+
"auditRow": "t_j5va_auditRow",
|
|
55
|
+
"auditIssues": "t_j5va_auditIssues",
|
|
56
|
+
"dupNames": "t_j5va_dupNames",
|
|
57
|
+
"modeAsk": "t_j5va_modeAsk",
|
|
58
|
+
"saveButton": "t_j5va_saveButton",
|
|
59
|
+
"detailItem": "t_j5va_detailItem",
|
|
60
|
+
"pwWeak": "t_j5va_pwWeak",
|
|
61
|
+
"trashButton": "t_j5va_trashButton",
|
|
62
|
+
"identity": "t_j5va_identity",
|
|
86
63
|
"toolbar": "t_j5va_toolbar",
|
|
87
|
-
"
|
|
64
|
+
"kindFilter": "t_j5va_kindFilter",
|
|
65
|
+
"badgeWarn": "t_j5va_badgeWarn",
|
|
66
|
+
"searchBox": "t_j5va_searchBox",
|
|
67
|
+
"genOpts": "t_j5va_genOpts",
|
|
68
|
+
"pwBar": "t_j5va_pwBar",
|
|
69
|
+
"intro": "t_j5va_intro",
|
|
70
|
+
"totp": "t_j5va_totp",
|
|
71
|
+
"dupGroup": "t_j5va_dupGroup",
|
|
72
|
+
"reportSub": "t_j5va_reportSub",
|
|
73
|
+
"pwMeter": "t_j5va_pwMeter",
|
|
88
74
|
"highBadge": "t_j5va_highBadge",
|
|
75
|
+
"section": "t_j5va_section",
|
|
76
|
+
"checkField": "t_j5va_checkField",
|
|
77
|
+
"error": "t_j5va_error",
|
|
78
|
+
"field": "t_j5va_field",
|
|
79
|
+
"empty": "t_j5va_empty",
|
|
80
|
+
"title": "t_j5va_title",
|
|
81
|
+
"rowExpired": "t_j5va_rowExpired",
|
|
82
|
+
"modeReadonly": "t_j5va_modeReadonly",
|
|
83
|
+
"emptyHint": "t_j5va_emptyHint",
|
|
89
84
|
"row": "t_j5va_row",
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
85
|
+
"dueBadge": "t_j5va_dueBadge",
|
|
86
|
+
"deleteButton": "t_j5va_deleteButton",
|
|
87
|
+
"revealButton": "t_j5va_revealButton",
|
|
88
|
+
"backupButton": "t_j5va_backupButton",
|
|
89
|
+
"genOptRow": "t_j5va_genOptRow",
|
|
90
|
+
"srOnly": "t_j5va_srOnly",
|
|
91
|
+
"list": "t_j5va_list",
|
|
92
|
+
"policyField": "t_j5va_policyField",
|
|
93
|
+
"editorBody": "t_j5va_editorBody"
|
|
94
94
|
};
|
|
95
95
|
//#endregion
|
|
96
96
|
//#region src/client/VaultSection.tsx
|
package/lib/index.js
CHANGED
|
@@ -1574,7 +1574,36 @@ export async function apply(ctx, config) {
|
|
|
1574
1574
|
xml += `<username>${x(e.username ?? e.email)}</username>\n`;
|
|
1575
1575
|
xml += `<password>${x(e.password)}</password>\n`;
|
|
1576
1576
|
xml += `<url>${x(e.url)}</url>\n`;
|
|
1577
|
-
xml += `<notes>${x(e.notes)}</notes>\n
|
|
1577
|
+
xml += `<notes>${x(e.notes)}</notes>\n`;
|
|
1578
|
+
if (e.otpSecret !== undefined) {
|
|
1579
|
+
const uri = e.otpSecret.startsWith('otpauth://') ? e.otpSecret : `otpauth://totp/${encodeURIComponent(e.title)}?secret=${e.otpSecret}`;
|
|
1580
|
+
xml += `<otp><name>dsh-vault</name><otpauth>${x(uri)}</otpauth></otp>\n`;
|
|
1581
|
+
}
|
|
1582
|
+
const strings = [];
|
|
1583
|
+
if (e.host !== undefined)
|
|
1584
|
+
strings.push(['host', e.host]);
|
|
1585
|
+
if (e.port !== undefined)
|
|
1586
|
+
strings.push(['port', e.port]);
|
|
1587
|
+
if (e.apiKey !== undefined)
|
|
1588
|
+
strings.push(['apiKey', e.apiKey]);
|
|
1589
|
+
if (e.secret !== undefined)
|
|
1590
|
+
strings.push(['secret', e.secret]);
|
|
1591
|
+
if (e.accessToken !== undefined)
|
|
1592
|
+
strings.push(['accessToken', e.accessToken]);
|
|
1593
|
+
if (e.refreshToken !== undefined)
|
|
1594
|
+
strings.push(['refreshToken', e.refreshToken]);
|
|
1595
|
+
if (e.privateKey !== undefined)
|
|
1596
|
+
strings.push(['privateKey', e.privateKey]);
|
|
1597
|
+
if (e.expiresAt !== undefined)
|
|
1598
|
+
strings.push(['expiresAt', e.expiresAt]);
|
|
1599
|
+
if (e.rotationDays !== undefined)
|
|
1600
|
+
strings.push(['rotationDays', e.rotationDays]);
|
|
1601
|
+
for (const [k, v] of Object.entries(e.fields ?? {}))
|
|
1602
|
+
strings.push([k, v]);
|
|
1603
|
+
for (const [k, v] of strings) {
|
|
1604
|
+
xml += `<String><Key>${x(k)}</Key><Value>${x(v)}</Value></String>\n`;
|
|
1605
|
+
}
|
|
1606
|
+
xml += `</entry>\n`;
|
|
1578
1607
|
}
|
|
1579
1608
|
xml += `</group>\n`;
|
|
1580
1609
|
}
|
|
@@ -1638,6 +1667,8 @@ export async function apply(ctx, config) {
|
|
|
1638
1667
|
url: header.indexOf('url'),
|
|
1639
1668
|
username: header.indexOf('username'),
|
|
1640
1669
|
password: header.indexOf('password'),
|
|
1670
|
+
otpauth: header.indexOf('otpauth'),
|
|
1671
|
+
notes: header.indexOf('notes'),
|
|
1641
1672
|
};
|
|
1642
1673
|
if (idx.name < 0 || idx.password < 0)
|
|
1643
1674
|
return { added: 0, skipped: rows.length - 1, updated: 0 };
|
|
@@ -1660,6 +1691,8 @@ export async function apply(ctx, config) {
|
|
|
1660
1691
|
...(idx.url >= 0 && idx.url < row.length && row[idx.url] ? { url: row[idx.url] } : {}),
|
|
1661
1692
|
...(idx.username >= 0 && idx.username < row.length && row[idx.username] ? { username: row[idx.username] } : {}),
|
|
1662
1693
|
...(idx.password >= 0 && idx.password < row.length && row[idx.password] ? { password: row[idx.password] } : {}),
|
|
1694
|
+
...(idx.otpauth >= 0 && idx.otpauth < row.length && row[idx.otpauth] ? { otpSecret: row[idx.otpauth] } : {}),
|
|
1695
|
+
...(idx.notes >= 0 && idx.notes < row.length && row[idx.notes] ? { notes: row[idx.notes] } : {}),
|
|
1663
1696
|
};
|
|
1664
1697
|
const existing = s.list().find(e => e.title === name);
|
|
1665
1698
|
if (existing && !args.overwrite) {
|
|
@@ -2338,6 +2371,146 @@ export async function apply(ctx, config) {
|
|
|
2338
2371
|
return { path: file, count: entries.length };
|
|
2339
2372
|
},
|
|
2340
2373
|
}));
|
|
2374
|
+
// ── vault_import_bitwarden: import a Bitwarden JSON export ─────────────────
|
|
2375
|
+
ctx.tools.register(defineTool({
|
|
2376
|
+
name: 'vault_import_bitwarden',
|
|
2377
|
+
description: 'Import a Bitwarden (or Vaultwarden) JSON export: maps each item into a vault entry '
|
|
2378
|
+
+ '(title, username/password, totp, notes, url, favorite, custom fields). Same-title entries are '
|
|
2379
|
+
+ 'skipped unless overwrite is set. Returns added/skipped/updated counts.',
|
|
2380
|
+
parameters: {
|
|
2381
|
+
path: { type: 'string', required: true, description: 'Absolute path of the Bitwarden .json export.' },
|
|
2382
|
+
overwrite: { type: 'boolean', description: 'Update existing entries with the same title (default false).' },
|
|
2383
|
+
},
|
|
2384
|
+
output: { schema: { type: 'object', additionalProperties: false, properties: { added: { type: 'integer', required: true }, skipped: { type: 'integer', required: true }, updated: { type: 'integer', required: true } } }, render: (_a, v) => [{ type: 'text', text: `imported ${v.added}, updated ${v.updated}, skipped ${v.skipped}` }] },
|
|
2385
|
+
async execute(args) {
|
|
2386
|
+
assertWritable('vault_import_bitwarden');
|
|
2387
|
+
const s = await guardStore();
|
|
2388
|
+
const raw = JSON.parse(await readFile(args.path, 'utf8'));
|
|
2389
|
+
const items = Array.isArray(raw.items) ? raw.items : [];
|
|
2390
|
+
let added = 0;
|
|
2391
|
+
let skipped = 0;
|
|
2392
|
+
let updated = 0;
|
|
2393
|
+
for (const item of items) {
|
|
2394
|
+
const title = (item.name ?? '').trim();
|
|
2395
|
+
if (!title) {
|
|
2396
|
+
skipped++;
|
|
2397
|
+
continue;
|
|
2398
|
+
}
|
|
2399
|
+
const patch = {};
|
|
2400
|
+
const login = item.login;
|
|
2401
|
+
if (login?.username !== undefined)
|
|
2402
|
+
patch.username = login.username;
|
|
2403
|
+
if (login?.password !== undefined)
|
|
2404
|
+
patch.password = login.password;
|
|
2405
|
+
if (login?.totp !== undefined)
|
|
2406
|
+
patch.otpSecret = login.totp;
|
|
2407
|
+
const uri = login?.uris?.find(u => u.uri)?.uri;
|
|
2408
|
+
if (uri !== undefined)
|
|
2409
|
+
patch.url = uri;
|
|
2410
|
+
if (item.notes !== undefined && item.notes !== null)
|
|
2411
|
+
patch.notes = item.notes;
|
|
2412
|
+
if (item.favorite === true)
|
|
2413
|
+
patch.favorite = true;
|
|
2414
|
+
const fields = {};
|
|
2415
|
+
for (const f of item.fields ?? []) {
|
|
2416
|
+
if (f.name !== undefined && f.value !== undefined)
|
|
2417
|
+
fields[f.name] = f.value;
|
|
2418
|
+
}
|
|
2419
|
+
// Promote known custom fields back onto the entry model.
|
|
2420
|
+
for (const key of ['host', 'port', 'apiKey', 'secret', 'accessToken', 'refreshToken', 'privateKey', 'expiresAt', 'rotationDays']) {
|
|
2421
|
+
if (fields[key] !== undefined) {
|
|
2422
|
+
;
|
|
2423
|
+
patch[key] = key === 'port' || key === 'expiresAt' || key === 'rotationDays' ? Number(fields[key]) : fields[key];
|
|
2424
|
+
delete fields[key];
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
if (Object.keys(fields).length > 0)
|
|
2428
|
+
patch.fields = fields;
|
|
2429
|
+
const existing = s.list().find(e => e.title === title);
|
|
2430
|
+
if (existing && !args.overwrite) {
|
|
2431
|
+
skipped++;
|
|
2432
|
+
continue;
|
|
2433
|
+
}
|
|
2434
|
+
if (existing && args.overwrite) {
|
|
2435
|
+
await s.update(existing.id, patch);
|
|
2436
|
+
updated++;
|
|
2437
|
+
continue;
|
|
2438
|
+
}
|
|
2439
|
+
await s.add({ title, ...patch });
|
|
2440
|
+
added++;
|
|
2441
|
+
}
|
|
2442
|
+
return { added, skipped, updated };
|
|
2443
|
+
},
|
|
2444
|
+
}));
|
|
2445
|
+
// ── vault_export_bitwarden: Bitwarden-compatible JSON export ───────────────
|
|
2446
|
+
ctx.tools.register(defineTool({
|
|
2447
|
+
name: 'vault_export_bitwarden',
|
|
2448
|
+
description: 'Export entries in the Bitwarden JSON format (encrypted:false) so they can be '
|
|
2449
|
+
+ 'imported into Bitwarden, Vaultwarden, or other tools that accept that format. Contains '
|
|
2450
|
+
+ 'plaintext secrets — write it to a protected file. Returns the output path and count.',
|
|
2451
|
+
parameters: { path: { type: 'string', required: true, description: 'Absolute output .json path.' } },
|
|
2452
|
+
output: { schema: { type: 'object', additionalProperties: false, properties: { path: { type: 'string', required: true }, count: { type: 'integer', required: true } } }, render: (_a, v) => [{ type: 'text', text: `exported ${v.count} entries to ${v.path}` }] },
|
|
2453
|
+
async execute(args) {
|
|
2454
|
+
assertWritable('vault_export_bitwarden');
|
|
2455
|
+
const s = await guardStore();
|
|
2456
|
+
const items = [];
|
|
2457
|
+
for (const e of s.list()) {
|
|
2458
|
+
const uris = e.url !== undefined ? [{ match: null, uri: e.url }] : null;
|
|
2459
|
+
const login = {};
|
|
2460
|
+
if (e.username !== undefined)
|
|
2461
|
+
login.username = e.username;
|
|
2462
|
+
if (e.email !== undefined && login.username === undefined)
|
|
2463
|
+
login.username = e.email;
|
|
2464
|
+
if (e.password !== undefined)
|
|
2465
|
+
login.password = e.password;
|
|
2466
|
+
if (e.otpSecret !== undefined)
|
|
2467
|
+
login.totp = e.otpSecret;
|
|
2468
|
+
if (uris !== null)
|
|
2469
|
+
login.uris = uris;
|
|
2470
|
+
const fields = [];
|
|
2471
|
+
for (const [k, v] of Object.entries(e.fields ?? {})) {
|
|
2472
|
+
if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {
|
|
2473
|
+
fields.push({ name: k, value: String(v), type: 0 });
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
if (e.host !== undefined)
|
|
2477
|
+
fields.push({ name: 'host', value: e.host, type: 0 });
|
|
2478
|
+
if (e.port !== undefined)
|
|
2479
|
+
fields.push({ name: 'port', value: String(e.port), type: 0 });
|
|
2480
|
+
if (e.apiKey !== undefined)
|
|
2481
|
+
fields.push({ name: 'apiKey', value: e.apiKey, type: 0 });
|
|
2482
|
+
if (e.secret !== undefined)
|
|
2483
|
+
fields.push({ name: 'secret', value: e.secret, type: 0 });
|
|
2484
|
+
if (e.accessToken !== undefined)
|
|
2485
|
+
fields.push({ name: 'accessToken', value: e.accessToken, type: 0 });
|
|
2486
|
+
if (e.refreshToken !== undefined)
|
|
2487
|
+
fields.push({ name: 'refreshToken', value: e.refreshToken, type: 0 });
|
|
2488
|
+
if (e.privateKey !== undefined)
|
|
2489
|
+
fields.push({ name: 'privateKey', value: e.privateKey, type: 0 });
|
|
2490
|
+
if (e.rotationDays !== undefined)
|
|
2491
|
+
fields.push({ name: 'rotationDays', value: String(e.rotationDays), type: 0 });
|
|
2492
|
+
if (e.expiresAt !== undefined)
|
|
2493
|
+
fields.push({ name: 'expiresAt', value: String(e.expiresAt), type: 0 });
|
|
2494
|
+
items.push({
|
|
2495
|
+
id: e.id,
|
|
2496
|
+
organizationId: null,
|
|
2497
|
+
folderId: null,
|
|
2498
|
+
type: 1,
|
|
2499
|
+
reprompt: 0,
|
|
2500
|
+
name: e.title,
|
|
2501
|
+
notes: e.notes ?? null,
|
|
2502
|
+
favorite: e.favorite === true,
|
|
2503
|
+
login: Object.keys(login).length > 0 ? login : null,
|
|
2504
|
+
fields: fields.length > 0 ? fields : null,
|
|
2505
|
+
collectionIds: null,
|
|
2506
|
+
});
|
|
2507
|
+
}
|
|
2508
|
+
const doc = { encrypted: false, folders: [], items };
|
|
2509
|
+
await mkdir(dirname(args.path), { recursive: true, mode: 0o700 });
|
|
2510
|
+
await writeFile(args.path, JSON.stringify(doc, null, 2), { mode: 0o600 });
|
|
2511
|
+
return { path: args.path, count: items.length };
|
|
2512
|
+
},
|
|
2513
|
+
}));
|
|
2341
2514
|
// ── vault_backup: one-shot backup with a timestamped filename ───────────────
|
|
2342
2515
|
ctx.tools.register(defineTool({
|
|
2343
2516
|
name: 'vault_backup',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-vault",
|
|
3
|
-
"version": "1.2.0-rc.
|
|
3
|
+
"version": "1.2.0-rc.3",
|
|
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",
|