dsh-vault 1.5.0 → 1.6.0-rc.2

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-zh.md CHANGED
@@ -51,6 +51,9 @@ dsh-vault 是一个面向 DeepSeek Harness 的安全加密插件:把你在使
51
51
  | `vault_totp` | 为存储的 otpSecret(或直接传入的 Base32/otpauth URI)生成当前 6 位动态验证码 |
52
52
  | `vault_generate_password` | 生成强随机密码(长度/字符集/分组可选)**或易记口令短语**(`passphrase: true`,EFF 词表,`words`/`separator`/`wordDigits`) |
53
53
  | `vault_strength` | 零依赖密码强度评估(0–100 分,weak/fair/strong/very strong) |
54
+ | `vault_password_history` | 列出条目的历史密码(1Password/Bitwarden 风格,最新在前,上限 10 条;不含当前密码) |
55
+ | `kind: card` | 银行卡/信用卡条目:`cardNumber`/`cardExpiry`(MM/YY)/`cardCvv`/`cardHolder`;搜索摘要只暴露有效期和持卡人(绝不显示卡号和 CVV);Bitwarden JSON 导出映射为 card 条目(type 3,自动识别卡品牌) |
56
+ | `vault_password_rollback` | 将条目密码回滚到某条历史记录(当前密码先归档,可逆) |
54
57
  | `vault_rekey` | 原地升级 scrypt KDF 参数并重加密 |
55
58
  | `vault_backup` | 带时间戳的加密备份,支持保留策略:超过 `maxBackups`(默认 10)的旧备份自动清理 |
56
59
  | `vault_import_csv` | 从 CSV 批量导入凭据(自定义列变为 fields;`overwrite: true` 合并字段到已有条目,不再产生重复) |
package/README.md CHANGED
@@ -53,6 +53,9 @@ Each record has a `title`, an optional `kind`, and any combination of fields:
53
53
  | `vault_totp` | Generate the current 6-digit code for a stored otpSecret (or a bare Base32 / otpauth URI) |
54
54
  | `vault_generate_password` | Generate a strong random password (length/classes/grouping) **or a memorable passphrase** (`passphrase: true`, EFF-style word list, `words`/`separator`/`wordDigits`) |
55
55
  | `vault_strength` | Zero-dependency password strength estimate (score 0–100, weak/fair/strong/very strong) |
56
+ | `vault_password_history` | List an entry's previous passwords (1Password/Bitwarden-style, newest first, capped at 10; current password excluded) |
57
+ | `kind: card` | Bank/credit-card entries: `cardNumber`/`cardExpiry` (MM/YY)/`cardCvv`/`cardHolder`; search summaries expose expiry + holder only (never the number or CVV); Bitwarden JSON export maps to a `card` item (type 3, brand inferred) |
58
+ | `vault_password_rollback` | Restore an entry password to a stored history entry (current password is archived first, so it is reversible) |
56
59
  | `vault_rekey` | Upgrade the vault to fresh scrypt KDF parameters in place |
57
60
  | `vault_backup` | Timestamped encrypted backup with retention; optional `note` |
58
61
  | `vault_import_csv` | Bulk-import credentials from a CSV file (custom columns become fields; `overwrite: true` merges fields into existing entries instead of duplicating) |
package/lib/client.js CHANGED
@@ -17,89 +17,89 @@ window.__ModuleLoader__.load({
17
17
  document.head.appendChild(tag);
18
18
  }
19
19
  var VaultSection_module_css_default = {
20
- "lockedBanner": "t_j5va_lockedBanner",
21
- "dupGroup": "t_j5va_dupGroup",
22
- "reportBox": "t_j5va_reportBox",
23
- "dangerButton": "t_j5va_dangerButton",
24
- "dupMerge": "t_j5va_dupMerge",
25
- "field": "t_j5va_field",
26
- "revealButton": "t_j5va_revealButton",
27
- "badgeWarn": "t_j5va_badgeWarn",
28
- "genOptRow": "t_j5va_genOptRow",
29
- "tabPane": "t_j5va_tabPane",
30
- "identity": "t_j5va_identity",
20
+ "pwFair": "t_j5va_pwFair",
21
+ "kindChip": "t_j5va_kindChip",
22
+ "auditRow": "t_j5va_auditRow",
23
+ "clearButton": "t_j5va_clearButton",
24
+ "healthBar": "t_j5va_healthBar",
25
+ "title": "t_j5va_title",
26
+ "rowDue": "t_j5va_rowDue",
31
27
  "dupNames": "t_j5va_dupNames",
28
+ "pinStar": "t_j5va_pinStar",
29
+ "saveButton": "t_j5va_saveButton",
30
+ "tabPane": "t_j5va_tabPane",
31
+ "secretField": "t_j5va_secretField",
32
32
  "srOnly": "t_j5va_srOnly",
33
- "rowDue": "t_j5va_rowDue",
34
- "toolbar": "t_j5va_toolbar",
35
- "detailItem": "t_j5va_detailItem",
33
+ "dueBadge": "t_j5va_dueBadge",
34
+ "genOptRow": "t_j5va_genOptRow",
35
+ "backupButton": "t_j5va_backupButton",
36
+ "resultCount": "t_j5va_resultCount",
37
+ "rowMain": "t_j5va_rowMain",
38
+ "editorActions": "t_j5va_editorActions",
39
+ "kindIcon": "t_j5va_kindIcon",
40
+ "highBadge": "t_j5va_highBadge",
41
+ "policyBar": "t_j5va_policyBar",
36
42
  "pwWeak": "t_j5va_pwWeak",
37
- "tabActive": "t_j5va_tabActive",
38
- "modeAsk": "t_j5va_modeAsk",
39
- "policyField": "t_j5va_policyField",
43
+ "reportTitle": "t_j5va_reportTitle",
44
+ "genOpts": "t_j5va_genOpts",
40
45
  "modeAuto": "t_j5va_modeAuto",
41
- "list": "t_j5va_list",
42
- "retryButton": "t_j5va_retryButton",
46
+ "reportLine": "t_j5va_reportLine",
47
+ "field": "t_j5va_field",
48
+ "rowExpired": "t_j5va_rowExpired",
49
+ "pwLabel": "t_j5va_pwLabel",
50
+ "dangerButton": "t_j5va_dangerButton",
51
+ "genHist": "t_j5va_genHist",
43
52
  "tabs": "t_j5va_tabs",
44
- "emptyBox": "t_j5va_emptyBox",
45
- "detailBox": "t_j5va_detailBox",
46
- "searchBox": "t_j5va_searchBox",
53
+ "toolbar": "t_j5va_toolbar",
54
+ "totp": "t_j5va_totp",
55
+ "row": "t_j5va_row",
47
56
  "status": "t_j5va_status",
48
- "reportSub": "t_j5va_reportSub",
49
- "kindFilter": "t_j5va_kindFilter",
50
- "backupButton": "t_j5va_backupButton",
57
+ "editorBody": "t_j5va_editorBody",
58
+ "dupGroup": "t_j5va_dupGroup",
59
+ "dupMerge": "t_j5va_dupMerge",
51
60
  "pwBar": "t_j5va_pwBar",
52
- "pwFair": "t_j5va_pwFair",
53
- "rowMain": "t_j5va_rowMain",
54
- "kindChip": "t_j5va_kindChip",
61
+ "modeReadonly": "t_j5va_modeReadonly",
62
+ "reportSub": "t_j5va_reportSub",
63
+ "sortButton": "t_j5va_sortButton",
64
+ "retryButton": "t_j5va_retryButton",
55
65
  "error": "t_j5va_error",
56
- "saveButton": "t_j5va_saveButton",
57
- "editor": "t_j5va_editor",
58
- "policyBar": "t_j5va_policyBar",
59
- "trashButton": "t_j5va_trashButton",
66
+ "detailBox": "t_j5va_detailBox",
67
+ "lockedTag": "t_j5va_lockedTag",
68
+ "searchBox": "t_j5va_searchBox",
69
+ "section": "t_j5va_section",
70
+ "modeAsk": "t_j5va_modeAsk",
71
+ "pwMeter": "t_j5va_pwMeter",
72
+ "lockedBanner": "t_j5va_lockedBanner",
73
+ "reportBox": "t_j5va_reportBox",
74
+ "totpRing": "t_j5va_totpRing",
75
+ "detailItem": "t_j5va_detailItem",
76
+ "tab": "t_j5va_tab",
77
+ "badge": "t_j5va_badge",
78
+ "emptyHint": "t_j5va_emptyHint",
79
+ "empty": "t_j5va_empty",
80
+ "policyField": "t_j5va_policyField",
81
+ "badgeOk": "t_j5va_badgeOk",
82
+ "badgeWarn": "t_j5va_badgeWarn",
83
+ "tabActive": "t_j5va_tabActive",
84
+ "intro": "t_j5va_intro",
85
+ "revealButton": "t_j5va_revealButton",
86
+ "pwStrong": "t_j5va_pwStrong",
87
+ "deleteButton": "t_j5va_deleteButton",
60
88
  "scoreRing": "t_j5va_scoreRing",
61
89
  "footer": "t_j5va_footer",
62
- "reportLine": "t_j5va_reportLine",
90
+ "uriCode": "t_j5va_uriCode",
63
91
  "copied": "t_j5va_copied",
92
+ "kindFilter": "t_j5va_kindFilter",
64
93
  "rowActions": "t_j5va_rowActions",
65
- "deleteButton": "t_j5va_deleteButton",
66
- "auditRow": "t_j5va_auditRow",
67
- "genHist": "t_j5va_genHist",
68
- "healthBar": "t_j5va_healthBar",
69
- "genOpts": "t_j5va_genOpts",
70
- "totpRing": "t_j5va_totpRing",
71
- "clearButton": "t_j5va_clearButton",
94
+ "list": "t_j5va_list",
95
+ "emptyBox": "t_j5va_emptyBox",
96
+ "identity": "t_j5va_identity",
97
+ "trashButton": "t_j5va_trashButton",
72
98
  "badgeDanger": "t_j5va_badgeDanger",
73
- "badge": "t_j5va_badge",
74
- "pwStrong": "t_j5va_pwStrong",
75
- "row": "t_j5va_row",
76
- "title": "t_j5va_title",
77
- "checkField": "t_j5va_checkField",
78
- "pwMeter": "t_j5va_pwMeter",
79
- "lockedTag": "t_j5va_lockedTag",
80
- "auditIssues": "t_j5va_auditIssues",
81
- "badgeOk": "t_j5va_badgeOk",
82
- "pinStar": "t_j5va_pinStar",
83
- "resultCount": "t_j5va_resultCount",
84
- "modeReadonly": "t_j5va_modeReadonly",
85
- "intro": "t_j5va_intro",
86
- "highBadge": "t_j5va_highBadge",
87
- "editorBody": "t_j5va_editorBody",
88
- "empty": "t_j5va_empty",
89
- "sortButton": "t_j5va_sortButton",
90
- "emptyHint": "t_j5va_emptyHint",
91
- "editorActions": "t_j5va_editorActions",
92
99
  "addButton": "t_j5va_addButton",
93
- "totp": "t_j5va_totp",
94
- "reportTitle": "t_j5va_reportTitle",
95
- "secretField": "t_j5va_secretField",
96
- "dueBadge": "t_j5va_dueBadge",
97
- "kindIcon": "t_j5va_kindIcon",
98
- "rowExpired": "t_j5va_rowExpired",
99
- "section": "t_j5va_section",
100
- "pwLabel": "t_j5va_pwLabel",
101
- "uriCode": "t_j5va_uriCode",
102
- "tab": "t_j5va_tab"
100
+ "checkField": "t_j5va_checkField",
101
+ "editor": "t_j5va_editor",
102
+ "auditIssues": "t_j5va_auditIssues"
103
103
  };
104
104
  //#endregion
105
105
  //#region src/client/VaultSection.tsx
@@ -161,6 +161,22 @@ window.__ModuleLoader__.load({
161
161
  key: "otpSecret",
162
162
  label: "fieldOtpSecret"
163
163
  },
164
+ {
165
+ key: "cardNumber",
166
+ label: "fieldCardNumber"
167
+ },
168
+ {
169
+ key: "cardExpiry",
170
+ label: "fieldCardExpiry"
171
+ },
172
+ {
173
+ key: "cardCvv",
174
+ label: "fieldCardCvv"
175
+ },
176
+ {
177
+ key: "cardHolder",
178
+ label: "fieldCardHolder"
179
+ },
164
180
  {
165
181
  key: "url",
166
182
  label: "fieldUrl"
@@ -232,6 +248,7 @@ window.__ModuleLoader__.load({
232
248
  secret: "kindSecret",
233
249
  oauth: "kindOauth",
234
250
  cookie: "kindCookie",
251
+ card: "kindCard",
235
252
  custom: "kindCustom"
236
253
  };
237
254
  function emptyForm() {
@@ -360,7 +377,10 @@ window.__ModuleLoader__.load({
360
377
  }, 250);
361
378
  return () => window.clearTimeout(timer);
362
379
  }, [form.password, strength]);
363
- /** Apply a template's field values to the current form. */
380
+ /** Apply a template's field values to the current form. The form is reset
381
+ * to its empty state first (so fields the template does not set are cleared
382
+ * rather than leaking the previous template's values), then the template's
383
+ * fields are applied. Secret-ish fields are never filled from a template. */
364
384
  function applyTemplate(name) {
365
385
  const tpl = tplList.find((t) => t.name === name);
366
386
  if (!tpl) return;
@@ -370,10 +390,26 @@ window.__ModuleLoader__.load({
370
390
  if (key === "password" || key === "otpSecret" || key === "apiKey" || key === "secret") continue;
371
391
  next[key] = value;
372
392
  }
373
- setForm((previous) => ({
374
- ...previous,
393
+ setForm({
394
+ ...emptyForm(),
375
395
  ...next
376
- }));
396
+ });
397
+ }
398
+ /** Change the entry kind. When CREATING a new entry, unrelated fields from
399
+ * the previous kind are cleared so the form does not carry stale values; when
400
+ * EDITING an existing entry the other fields are kept (they may be valid for
401
+ * the new kind too, and clearing would risk data loss). */
402
+ function changeKind(kind) {
403
+ setForm((previous) => {
404
+ if (editor.status === "creating") return {
405
+ ...emptyForm(),
406
+ kind
407
+ };
408
+ return {
409
+ ...previous,
410
+ kind
411
+ };
412
+ });
377
413
  }
378
414
  /** Save the current form as a reusable template. */
379
415
  async function saveAsTemplate() {
@@ -1296,6 +1332,7 @@ window.__ModuleLoader__.load({
1296
1332
  case "oauth": return "🔐";
1297
1333
  case "secret": return "🤫";
1298
1334
  case "cookie": return "🍪";
1335
+ case "card": return "💳";
1299
1336
  case "custom": return "🧩";
1300
1337
  default: return "👤";
1301
1338
  }
@@ -2923,14 +2960,15 @@ window.__ModuleLoader__.load({
2923
2960
  children: t("tplSave")
2924
2961
  })]
2925
2962
  }),
2926
- FORM_FIELDS.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2963
+ FORM_FIELDS.filter((f) => {
2964
+ const kind = form.kind ?? "login";
2965
+ if (f.key === "cardNumber" || f.key === "cardExpiry" || f.key === "cardCvv" || f.key === "cardHolder") return kind === "card";
2966
+ return kind !== "card" || f.key === "title" || f.key === "kind" || f.key === "notes" || f.key === "icon" || f.key === "color";
2967
+ }).map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2927
2968
  className: VaultSection_module_css_default.field,
2928
2969
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(field.label) }), field.key === "kind" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
2929
2970
  value: form.kind ?? "login",
2930
- onChange: (event) => setForm((previous) => ({
2931
- ...previous,
2932
- kind: event.target.value
2933
- })),
2971
+ onChange: (event) => changeKind(event.target.value),
2934
2972
  children: Object.entries(KIND_KEYS).map(([value, key]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2935
2973
  value,
2936
2974
  children: t(key)
@@ -3419,6 +3457,10 @@ window.__ModuleLoader__.load({
3419
3457
  fieldRefreshToken: "Refresh token",
3420
3458
  fieldOtpSecret: "OTP secret",
3421
3459
  fieldUrl: "URL",
3460
+ fieldCardNumber: "Card number",
3461
+ fieldCardExpiry: "Expiry (MM/YY)",
3462
+ fieldCardCvv: "CVV",
3463
+ fieldCardHolder: "Card holder",
3422
3464
  fieldNotes: "Notes",
3423
3465
  fieldTags: "Tags",
3424
3466
  fieldIcon: "Icon (emoji)",
@@ -3439,6 +3481,7 @@ window.__ModuleLoader__.load({
3439
3481
  kindSecret: "Secret",
3440
3482
  kindOauth: "OAuth",
3441
3483
  kindCookie: "Session cookies",
3484
+ kindCard: "Card",
3442
3485
  kindCustom: "Custom"
3443
3486
  };
3444
3487
  /** Chinese strings (same keys as English). */
@@ -3687,6 +3730,10 @@ window.__ModuleLoader__.load({
3687
3730
  fieldRefreshToken: "刷新令牌",
3688
3731
  fieldOtpSecret: "TOTP 密钥",
3689
3732
  fieldUrl: "URL",
3733
+ fieldCardNumber: "卡号",
3734
+ fieldCardExpiry: "有效期(MM/YY)",
3735
+ fieldCardCvv: "CVV",
3736
+ fieldCardHolder: "持卡人",
3690
3737
  fieldNotes: "备注",
3691
3738
  fieldTags: "标签",
3692
3739
  fieldIcon: "图标(emoji)",
@@ -3707,6 +3754,7 @@ window.__ModuleLoader__.load({
3707
3754
  kindSecret: "Secret",
3708
3755
  kindOauth: "OAuth",
3709
3756
  kindCookie: "会话 Cookies",
3757
+ kindCard: "银行卡",
3710
3758
  kindCustom: "自定义"
3711
3759
  };
3712
3760
  //#endregion