dsh-vault 1.5.0 → 1.6.0-rc.1

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,8 @@ 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
+ | `vault_password_rollback` | 将条目密码回滚到某条历史记录(当前密码先归档,可逆) |
54
56
  | `vault_rekey` | 原地升级 scrypt KDF 参数并重加密 |
55
57
  | `vault_backup` | 带时间戳的加密备份,支持保留策略:超过 `maxBackups`(默认 10)的旧备份自动清理 |
56
58
  | `vault_import_csv` | 从 CSV 批量导入凭据(自定义列变为 fields;`overwrite: true` 合并字段到已有条目,不再产生重复) |
package/README.md CHANGED
@@ -53,6 +53,8 @@ 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
+ | `vault_password_rollback` | Restore an entry password to a stored history entry (current password is archived first, so it is reversible) |
56
58
  | `vault_rekey` | Upgrade the vault to fresh scrypt KDF parameters in place |
57
59
  | `vault_backup` | Timestamped encrypted backup with retention; optional `note` |
58
60
  | `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",
20
+ "tab": "t_j5va_tab",
21
+ "retryButton": "t_j5va_retryButton",
22
+ "saveButton": "t_j5va_saveButton",
23
+ "empty": "t_j5va_empty",
24
+ "totpRing": "t_j5va_totpRing",
25
+ "reportTitle": "t_j5va_reportTitle",
26
+ "tabPane": "t_j5va_tabPane",
27
+ "sortButton": "t_j5va_sortButton",
25
28
  "field": "t_j5va_field",
29
+ "resultCount": "t_j5va_resultCount",
26
30
  "revealButton": "t_j5va_revealButton",
27
- "badgeWarn": "t_j5va_badgeWarn",
28
- "genOptRow": "t_j5va_genOptRow",
29
- "tabPane": "t_j5va_tabPane",
30
- "identity": "t_j5va_identity",
31
- "dupNames": "t_j5va_dupNames",
32
- "srOnly": "t_j5va_srOnly",
31
+ "error": "t_j5va_error",
33
32
  "rowDue": "t_j5va_rowDue",
34
- "toolbar": "t_j5va_toolbar",
33
+ "dueBadge": "t_j5va_dueBadge",
34
+ "secretField": "t_j5va_secretField",
35
+ "auditRow": "t_j5va_auditRow",
36
+ "addButton": "t_j5va_addButton",
37
+ "editor": "t_j5va_editor",
38
+ "editorBody": "t_j5va_editorBody",
39
+ "scoreRing": "t_j5va_scoreRing",
35
40
  "detailItem": "t_j5va_detailItem",
36
- "pwWeak": "t_j5va_pwWeak",
37
- "tabActive": "t_j5va_tabActive",
38
- "modeAsk": "t_j5va_modeAsk",
39
- "policyField": "t_j5va_policyField",
40
- "modeAuto": "t_j5va_modeAuto",
41
+ "toolbar": "t_j5va_toolbar",
42
+ "totp": "t_j5va_totp",
43
+ "clearButton": "t_j5va_clearButton",
41
44
  "list": "t_j5va_list",
42
- "retryButton": "t_j5va_retryButton",
43
- "tabs": "t_j5va_tabs",
45
+ "pwStrong": "t_j5va_pwStrong",
46
+ "title": "t_j5va_title",
47
+ "row": "t_j5va_row",
48
+ "rowMain": "t_j5va_rowMain",
49
+ "intro": "t_j5va_intro",
50
+ "dupMerge": "t_j5va_dupMerge",
51
+ "lockedTag": "t_j5va_lockedTag",
52
+ "badgeDanger": "t_j5va_badgeDanger",
53
+ "policyField": "t_j5va_policyField",
44
54
  "emptyBox": "t_j5va_emptyBox",
45
- "detailBox": "t_j5va_detailBox",
46
- "searchBox": "t_j5va_searchBox",
47
- "status": "t_j5va_status",
48
- "reportSub": "t_j5va_reportSub",
49
- "kindFilter": "t_j5va_kindFilter",
50
55
  "backupButton": "t_j5va_backupButton",
51
- "pwBar": "t_j5va_pwBar",
56
+ "pwMeter": "t_j5va_pwMeter",
57
+ "tabs": "t_j5va_tabs",
58
+ "tabActive": "t_j5va_tabActive",
59
+ "kindFilter": "t_j5va_kindFilter",
60
+ "pinStar": "t_j5va_pinStar",
61
+ "dupNames": "t_j5va_dupNames",
62
+ "auditIssues": "t_j5va_auditIssues",
63
+ "editorActions": "t_j5va_editorActions",
64
+ "emptyHint": "t_j5va_emptyHint",
52
65
  "pwFair": "t_j5va_pwFair",
53
- "rowMain": "t_j5va_rowMain",
54
- "kindChip": "t_j5va_kindChip",
55
- "error": "t_j5va_error",
56
- "saveButton": "t_j5va_saveButton",
57
- "editor": "t_j5va_editor",
58
- "policyBar": "t_j5va_policyBar",
59
- "trashButton": "t_j5va_trashButton",
60
- "scoreRing": "t_j5va_scoreRing",
61
- "footer": "t_j5va_footer",
62
66
  "reportLine": "t_j5va_reportLine",
63
- "copied": "t_j5va_copied",
64
- "rowActions": "t_j5va_rowActions",
65
- "deleteButton": "t_j5va_deleteButton",
66
- "auditRow": "t_j5va_auditRow",
67
- "genHist": "t_j5va_genHist",
67
+ "trashButton": "t_j5va_trashButton",
68
68
  "healthBar": "t_j5va_healthBar",
69
+ "footer": "t_j5va_footer",
69
70
  "genOpts": "t_j5va_genOpts",
70
- "totpRing": "t_j5va_totpRing",
71
- "clearButton": "t_j5va_clearButton",
72
- "badgeDanger": "t_j5va_badgeDanger",
73
- "badge": "t_j5va_badge",
74
- "pwStrong": "t_j5va_pwStrong",
75
- "row": "t_j5va_row",
76
- "title": "t_j5va_title",
71
+ "lockedBanner": "t_j5va_lockedBanner",
72
+ "policyBar": "t_j5va_policyBar",
73
+ "reportBox": "t_j5va_reportBox",
74
+ "deleteButton": "t_j5va_deleteButton",
75
+ "modeAuto": "t_j5va_modeAuto",
77
76
  "checkField": "t_j5va_checkField",
78
- "pwMeter": "t_j5va_pwMeter",
79
- "lockedTag": "t_j5va_lockedTag",
80
- "auditIssues": "t_j5va_auditIssues",
77
+ "reportSub": "t_j5va_reportSub",
78
+ "dangerButton": "t_j5va_dangerButton",
79
+ "detailBox": "t_j5va_detailBox",
80
+ "pwWeak": "t_j5va_pwWeak",
81
+ "badge": "t_j5va_badge",
82
+ "pwBar": "t_j5va_pwBar",
83
+ "modeAsk": "t_j5va_modeAsk",
81
84
  "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
- "addButton": "t_j5va_addButton",
93
- "totp": "t_j5va_totp",
94
- "reportTitle": "t_j5va_reportTitle",
95
- "secretField": "t_j5va_secretField",
96
- "dueBadge": "t_j5va_dueBadge",
85
+ "pwLabel": "t_j5va_pwLabel",
86
+ "identity": "t_j5va_identity",
87
+ "rowActions": "t_j5va_rowActions",
97
88
  "kindIcon": "t_j5va_kindIcon",
89
+ "kindChip": "t_j5va_kindChip",
90
+ "genHist": "t_j5va_genHist",
91
+ "genOptRow": "t_j5va_genOptRow",
92
+ "uriCode": "t_j5va_uriCode",
98
93
  "rowExpired": "t_j5va_rowExpired",
94
+ "status": "t_j5va_status",
95
+ "dupGroup": "t_j5va_dupGroup",
96
+ "highBadge": "t_j5va_highBadge",
97
+ "copied": "t_j5va_copied",
98
+ "badgeWarn": "t_j5va_badgeWarn",
99
+ "modeReadonly": "t_j5va_modeReadonly",
99
100
  "section": "t_j5va_section",
100
- "pwLabel": "t_j5va_pwLabel",
101
- "uriCode": "t_j5va_uriCode",
102
- "tab": "t_j5va_tab"
101
+ "searchBox": "t_j5va_searchBox",
102
+ "srOnly": "t_j5va_srOnly"
103
103
  };
104
104
  //#endregion
105
105
  //#region src/client/VaultSection.tsx
@@ -360,7 +360,10 @@ window.__ModuleLoader__.load({
360
360
  }, 250);
361
361
  return () => window.clearTimeout(timer);
362
362
  }, [form.password, strength]);
363
- /** Apply a template's field values to the current form. */
363
+ /** Apply a template's field values to the current form. The form is reset
364
+ * to its empty state first (so fields the template does not set are cleared
365
+ * rather than leaking the previous template's values), then the template's
366
+ * fields are applied. Secret-ish fields are never filled from a template. */
364
367
  function applyTemplate(name) {
365
368
  const tpl = tplList.find((t) => t.name === name);
366
369
  if (!tpl) return;
@@ -370,10 +373,26 @@ window.__ModuleLoader__.load({
370
373
  if (key === "password" || key === "otpSecret" || key === "apiKey" || key === "secret") continue;
371
374
  next[key] = value;
372
375
  }
373
- setForm((previous) => ({
374
- ...previous,
376
+ setForm({
377
+ ...emptyForm(),
375
378
  ...next
376
- }));
379
+ });
380
+ }
381
+ /** Change the entry kind. When CREATING a new entry, unrelated fields from
382
+ * the previous kind are cleared so the form does not carry stale values; when
383
+ * EDITING an existing entry the other fields are kept (they may be valid for
384
+ * the new kind too, and clearing would risk data loss). */
385
+ function changeKind(kind) {
386
+ setForm((previous) => {
387
+ if (editor.status === "creating") return {
388
+ ...emptyForm(),
389
+ kind
390
+ };
391
+ return {
392
+ ...previous,
393
+ kind
394
+ };
395
+ });
377
396
  }
378
397
  /** Save the current form as a reusable template. */
379
398
  async function saveAsTemplate() {
@@ -2927,10 +2946,7 @@ window.__ModuleLoader__.load({
2927
2946
  className: VaultSection_module_css_default.field,
2928
2947
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(field.label) }), field.key === "kind" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
2929
2948
  value: form.kind ?? "login",
2930
- onChange: (event) => setForm((previous) => ({
2931
- ...previous,
2932
- kind: event.target.value
2933
- })),
2949
+ onChange: (event) => changeKind(event.target.value),
2934
2950
  children: Object.entries(KIND_KEYS).map(([value, key]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2935
2951
  value,
2936
2952
  children: t(key)