@tacet-ink/journal-core 0.1.4 → 0.1.5

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.md CHANGED
@@ -22,8 +22,8 @@
22
22
  - **extractable 鐵律**:要被 exportKey/wrap 的 key(noteKey 全部產生路徑),
23
23
  import 當下就必須 `extractable=true`;KEK/guest key 恆 nonextractable。
24
24
  - **opt-in 原語**:選配契約(cipherGuest/wrapDual/wrapShare/pinLock/cipherAttach/cipherLocal)
25
- 未配置即拒絕,不配置的產品行為完全不受影響(cipherGuest 未配置時 bound 路徑不受牽連,
26
- 解密面 guest 家族整面拒絕、不明字串不當明文顯示)。
25
+ 未配置即拒絕,各 fork 未選用的原語行為不受影響(cipherGuest 未配置時 bound 路徑不受牽連,
26
+ 解密面 guest 家族整面拒絕、不明字串與畸形空字串配置不當明文顯示)。
27
27
 
28
28
  ## 模組
29
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tacet-ink/journal-core",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Zero-knowledge journal core — e2e crypto, passphrase-only auth, transport, ratelimit. The server never sees plaintext.",
5
5
  "homepage": "https://tacet.ink",
6
6
  "repository": {
@@ -506,6 +506,19 @@ await A('配置 guest → decryptNote 舊明文相容層原樣(既有契約不
506
506
  await A('既有 guest 配置 roundtrip 不受選配收編影響',
507
507
  (await decryptNote(TACET, makeHeldKey(), cipherGuest, 'noteId:n1', { current: () => identityA })) === note);
508
508
 
509
+ // 畸形配置 ''(空字串)正規化面(follow-up ②,t_44239f5f):空字串前綴=startsWith('') 恆真,
510
+ // bound 列會被誤導 guest 分支回 null。正規化後:加密面與未配置同拒、解密面 bound 照解、
511
+ // guest 密文(他家族形)null——與「未配置」行為完全同構。
512
+ const TACET_EMPTYGUEST: NoteCryptoConfig = { ...TACET, cipherGuest: '' };
513
+ await A("畸形 guest 前綴 '' → encryptNote guest 路徑同 ERR_GUEST_NOT_CONFIGURED(truthiness 對稱)",
514
+ (await (async () => { try { await encryptNote(TACET_EMPTYGUEST, makeHeldKey(), note, 'noteId:n1', { current: () => identityA }); return null; } catch (e) { return (e as Error).message; } })()) === 'ERR_GUEST_NOT_CONFIGURED');
515
+ await A("畸形 guest 前綴 '' → decryptNote bound 密文照解(不誤導 guest 分支回 null)",
516
+ (await decryptNote(TACET_EMPTYGUEST, heldBound, cipherBound, 'noteId:n1', { current: () => identityA })) === note);
517
+ await A("畸形 guest 前綴 '' → decryptNote guest 密文 null(guest 家族整面拒絕)",
518
+ (await decryptNote(TACET_EMPTYGUEST, makeHeldKey(), cipherGuest, 'noteId:n1', { current: () => identityA })) === null);
519
+ await A("畸形 guest 前綴 '' → decryptNote 舊明文相容層同「未配置」形(null,不當明文)",
520
+ (await decryptNote(TACET_EMPTYGUEST, makeHeldKey(), '純舊明文', 'x', { current: () => identityA })) === null);
521
+
509
522
  // ── 決議 ────────────────────────────────────────────────────────────────────
510
523
 
511
524
  console.log(`\n${passed} 斷言全綠` + (failures.length ? `;${failures.length} 失敗` : ''));
@@ -464,7 +464,10 @@ export async function decryptNote(
464
464
  idp: IdentityProvider,
465
465
  ): Promise<string | null> {
466
466
  try {
467
- const guestPrefix = cfg.cipherGuest;
467
+ // guest 前綴正規化(follow-up ②,t_44239f5f):畸形配置 ''(空字串)會讓
468
+ // startsWith('') 恆真=bound 列誤導 guest 分支回 null(解密面整列滅失)。
469
+ // falsy 一律收斂為 undefined,與加密面「未配置即拒」truthiness 對稱。
470
+ const guestPrefix = cfg.cipherGuest || undefined;
468
471
  const isGuest = guestPrefix !== undefined && cipher.startsWith(guestPrefix);
469
472
  const isBound = cipher.startsWith(cfg.cipherBound);
470
473
  if (!isGuest && !isBound) {