@blamejs/core 0.14.22 → 0.14.25

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.
@@ -309,25 +309,33 @@ function dbStore(opts) {
309
309
  });
310
310
  }
311
311
 
312
- // Derive a per-vault HMAC secret for fingerprint sealing.
313
- // The vault root key is the trust root; without it the secret is
314
- // unrecoverable. Lazy: only derived when fpSealOn is enabled AND the
315
- // vault is ready, so test fixtures that haven't initialized the
316
- // vault still construct a dbStore (the fingerprint then falls back
317
- // to bare sha3-256 with a single audit warning).
312
+ // Derive a per-vault HMAC secret for fingerprint sealing. Seed off the
313
+ // SEALED per-deployment MAC key (vault.getDerivedHashMacKey, sealed at
314
+ // rest under the vault root) NOT getDerivedHashSalt, which sits in
315
+ // PLAINTEXT on disk. With the salt-derived seed an attacker who read
316
+ // the disk could recompute the HMAC key and forge / correlate request
317
+ // fingerprints; the sealed MAC key closes that (the vault root is the
318
+ // trust root, so the secret is unrecoverable without it). Lazy: only
319
+ // derived when fpSealOn is enabled AND the vault is ready, so test
320
+ // fixtures that haven't initialized the vault still construct a
321
+ // dbStore (the fingerprint then falls back to bare sha3-256 with a
322
+ // single audit warning).
318
323
  var fpHmacSecret = null;
319
324
  if (fpSealOn) {
320
325
  try {
321
- // Use vault.aad.buildContextAad as a stable derivation input;
322
- // the derivedHashSalt is per-deployment so the same dbStore
323
- // instance across hosts converges on the same HMAC key.
324
- var fpDeriveInput = "idempotency.fingerprint:" + tableNameRaw + ":" +
325
- vault.getDerivedHashSalt().toString("hex");
326
- fpHmacSecret = bCrypto.kdf(Buffer.from(fpDeriveInput, "utf8"), C.BYTES.bytes(32));
326
+ // The MAC key is per-deployment + sealed, so the same dbStore
327
+ // instance across hosts converges on the same HMAC key while disk
328
+ // access alone cannot recover it. The table name domain-separates
329
+ // the fingerprint secret from other consumers of the MAC key.
330
+ var fpDeriveInput = Buffer.concat([
331
+ vault.getDerivedHashMacKey(),
332
+ Buffer.from("idempotency.fingerprint:" + tableNameRaw, "utf8"),
333
+ ]);
334
+ fpHmacSecret = bCrypto.kdf(fpDeriveInput, C.BYTES.bytes(32));
327
335
  } catch (_fpErr) {
328
336
  _emitAudit("idempotency.fingerprint_seal_skipped_no_vault",
329
337
  { tableName: tableNameRaw,
330
- reason: "vault.getDerivedHashSalt() unavailable; fingerprint falls back to plain sha3-256" },
338
+ reason: "vault.getDerivedHashMacKey() unavailable; fingerprint falls back to plain sha3-256" },
331
339
  "warning");
332
340
  fpHmacSecret = null;
333
341
  }
package/lib/retention.js CHANGED
@@ -274,8 +274,18 @@ function create(opts) {
274
274
  values.push(row._id);
275
275
  var upd2 = db.prepare("UPDATE \"" + table + "\" SET " + setClauses.join(", ") + " WHERE _id = ?");
276
276
  upd2.run.apply(upd2, values);
277
+ // Per-row-key tables (declarePerRowKey): NULLing the sealed columns
278
+ // is not enough — WAL / replica residuals keep the old K_row cells.
279
+ // Destroy the row's wrapped secret so K_row is unrecoverable and the
280
+ // residual ciphertext reads as absent (crypto-shred, GDPR Art. 17).
281
+ // rowId is row._id, the same identity materialize / eraseHard use.
282
+ var perRowKeysDestroyed = 0;
283
+ if (cryptoField.hasPerRowKey(table)) {
284
+ var dr = cryptoField.destroyPerRowKey(table, row._id, db);
285
+ perRowKeysDestroyed = (dr && dr.destroyed) || 0;
286
+ }
277
287
  void erased;
278
- return { erased: 1, sealedFieldCount: sealedFields.length };
288
+ return { erased: 1, sealedFieldCount: sealedFields.length, perRowKeysDestroyed: perRowKeysDestroyed };
279
289
  }
280
290
 
281
291
  function _cascade(rule, rowId, dryRun) {
package/lib/vault-aad.js CHANGED
@@ -304,6 +304,12 @@ module.exports = {
304
304
  isAadSealed: isAadSealed,
305
305
  buildColumnAad: buildColumnAad,
306
306
  buildContextAad: buildContextAad,
307
+ // canonicalizeAad — the length-prefixed, sorted-keys AAD-bytes
308
+ // encoder. Exported (internal) so a sibling primitive that runs its
309
+ // own AEAD (crypto-field's per-row K_row cells) threads byte-identical
310
+ // AAD into encryptPacked/decryptPacked as this module does for its
311
+ // own seal/unseal — one canonical encoder, no drift.
312
+ canonicalizeAad: _canonicalize,
307
313
  AAD_PREFIX: AAD_PREFIX,
308
314
  AAD_VERSION: AAD_VERSION,
309
315
  VaultAadError: VaultAadError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.14.22",
3
+ "version": "0.14.25",
4
4
  "description": "The Node framework that owns its stack.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:6a454186-ef0a-43dd-8780-6900d4f1daf5",
5
+ "serialNumber": "urn:uuid:a667e112-0ef6-4c72-b5b8-839233b6e4a6",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-06-05T17:23:40.587Z",
8
+ "timestamp": "2026-06-06T17:19:53.413Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/core@0.14.22",
22
+ "bom-ref": "@blamejs/core@0.14.25",
23
23
  "type": "application",
24
24
  "name": "blamejs",
25
- "version": "0.14.22",
25
+ "version": "0.14.25",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "The Node framework that owns its stack.",
29
- "purl": "pkg:npm/%40blamejs/core@0.14.22",
29
+ "purl": "pkg:npm/%40blamejs/core@0.14.25",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/core@0.14.22",
57
+ "ref": "@blamejs/core@0.14.25",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]