@blamejs/blamejs-shop 0.4.69 → 0.4.70

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.
Files changed (297) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/admin.js +8 -6
  3. package/lib/asset-manifest.json +1 -1
  4. package/lib/security-middleware.js +65 -23
  5. package/lib/storefront.js +10 -7
  6. package/lib/vendor/MANIFEST.json +319 -267
  7. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  8. package/lib/vendor/blamejs/api-snapshot.json +58 -5
  9. package/lib/vendor/blamejs/examples/wiki/README.md +1 -1
  10. package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +9 -8
  11. package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +10 -9
  12. package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +4 -3
  13. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +33 -17
  14. package/lib/vendor/blamejs/examples/wiki/routes/admin.js +7 -10
  15. package/lib/vendor/blamejs/examples/wiki/server.js +5 -4
  16. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +5 -0
  17. package/lib/vendor/blamejs/lib/a2a-tasks.js +38 -6
  18. package/lib/vendor/blamejs/lib/agent-event-bus.js +13 -0
  19. package/lib/vendor/blamejs/lib/agent-idempotency.js +5 -1
  20. package/lib/vendor/blamejs/lib/agent-snapshot.js +32 -2
  21. package/lib/vendor/blamejs/lib/ai-aedt-bias-audit.js +2 -1
  22. package/lib/vendor/blamejs/lib/ai-content-detect.js +1 -3
  23. package/lib/vendor/blamejs/lib/ai-frontier-protocol.js +1 -1
  24. package/lib/vendor/blamejs/lib/ai-model-manifest.js +1 -1
  25. package/lib/vendor/blamejs/lib/ai-output.js +16 -7
  26. package/lib/vendor/blamejs/lib/api-snapshot.js +4 -1
  27. package/lib/vendor/blamejs/lib/app-shutdown.js +7 -1
  28. package/lib/vendor/blamejs/lib/archive-gz.js +9 -0
  29. package/lib/vendor/blamejs/lib/archive-read.js +9 -7
  30. package/lib/vendor/blamejs/lib/archive-tar-read.js +51 -8
  31. package/lib/vendor/blamejs/lib/archive.js +4 -2
  32. package/lib/vendor/blamejs/lib/asn1-der.js +70 -22
  33. package/lib/vendor/blamejs/lib/atomic-file.js +204 -2
  34. package/lib/vendor/blamejs/lib/audit-chain.js +54 -5
  35. package/lib/vendor/blamejs/lib/audit-daily-review.js +12 -2
  36. package/lib/vendor/blamejs/lib/audit-sign.js +2 -1
  37. package/lib/vendor/blamejs/lib/audit-tools.js +108 -23
  38. package/lib/vendor/blamejs/lib/audit.js +7 -2
  39. package/lib/vendor/blamejs/lib/auth/access-lock.js +2 -2
  40. package/lib/vendor/blamejs/lib/auth/bot-challenge.js +1 -1
  41. package/lib/vendor/blamejs/lib/auth/ciba.js +43 -4
  42. package/lib/vendor/blamejs/lib/auth/dpop.js +6 -1
  43. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +5 -1
  44. package/lib/vendor/blamejs/lib/auth/jwt.js +2 -2
  45. package/lib/vendor/blamejs/lib/auth/lockout.js +18 -2
  46. package/lib/vendor/blamejs/lib/auth/passkey.js +1 -1
  47. package/lib/vendor/blamejs/lib/auth/password.js +1 -1
  48. package/lib/vendor/blamejs/lib/auth/saml.js +33 -13
  49. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +24 -4
  50. package/lib/vendor/blamejs/lib/auth/status-list.js +14 -2
  51. package/lib/vendor/blamejs/lib/auth/step-up.js +9 -1
  52. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +21 -2
  53. package/lib/vendor/blamejs/lib/backup/bundle.js +7 -2
  54. package/lib/vendor/blamejs/lib/backup/crypto.js +23 -8
  55. package/lib/vendor/blamejs/lib/backup/index.js +41 -20
  56. package/lib/vendor/blamejs/lib/backup/manifest.js +7 -1
  57. package/lib/vendor/blamejs/lib/break-glass.js +41 -22
  58. package/lib/vendor/blamejs/lib/cbor.js +34 -11
  59. package/lib/vendor/blamejs/lib/cdn-cache-control.js +7 -3
  60. package/lib/vendor/blamejs/lib/cert.js +5 -3
  61. package/lib/vendor/blamejs/lib/cli.js +5 -1
  62. package/lib/vendor/blamejs/lib/cloud-events.js +3 -2
  63. package/lib/vendor/blamejs/lib/cluster-storage.js +7 -3
  64. package/lib/vendor/blamejs/lib/codepoint-class.js +17 -0
  65. package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -1
  66. package/lib/vendor/blamejs/lib/compliance-sanctions.js +9 -7
  67. package/lib/vendor/blamejs/lib/compliance.js +1 -1
  68. package/lib/vendor/blamejs/lib/config-drift.js +22 -8
  69. package/lib/vendor/blamejs/lib/content-credentials.js +11 -8
  70. package/lib/vendor/blamejs/lib/content-digest.js +11 -4
  71. package/lib/vendor/blamejs/lib/cookies.js +10 -2
  72. package/lib/vendor/blamejs/lib/cose.js +20 -0
  73. package/lib/vendor/blamejs/lib/crdt.js +2 -1
  74. package/lib/vendor/blamejs/lib/crypto-field.js +29 -23
  75. package/lib/vendor/blamejs/lib/crypto.js +18 -4
  76. package/lib/vendor/blamejs/lib/csp.js +4 -0
  77. package/lib/vendor/blamejs/lib/daemon.js +4 -1
  78. package/lib/vendor/blamejs/lib/data-act.js +27 -4
  79. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +14 -6
  80. package/lib/vendor/blamejs/lib/db-query.js +69 -9
  81. package/lib/vendor/blamejs/lib/db.js +32 -15
  82. package/lib/vendor/blamejs/lib/dora.js +43 -13
  83. package/lib/vendor/blamejs/lib/dr-runbook.js +1 -1
  84. package/lib/vendor/blamejs/lib/dsa.js +2 -1
  85. package/lib/vendor/blamejs/lib/dsr.js +22 -8
  86. package/lib/vendor/blamejs/lib/early-hints.js +19 -0
  87. package/lib/vendor/blamejs/lib/eat.js +5 -1
  88. package/lib/vendor/blamejs/lib/external-db.js +60 -4
  89. package/lib/vendor/blamejs/lib/fda-21cfr11.js +30 -5
  90. package/lib/vendor/blamejs/lib/flag-providers.js +6 -2
  91. package/lib/vendor/blamejs/lib/forms.js +1 -1
  92. package/lib/vendor/blamejs/lib/gate-contract.js +46 -5
  93. package/lib/vendor/blamejs/lib/gdpr-ropa.js +18 -9
  94. package/lib/vendor/blamejs/lib/graphql-federation.js +17 -4
  95. package/lib/vendor/blamejs/lib/guard-all.js +2 -2
  96. package/lib/vendor/blamejs/lib/guard-dsn.js +1 -1
  97. package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
  98. package/lib/vendor/blamejs/lib/guard-html.js +9 -11
  99. package/lib/vendor/blamejs/lib/guard-imap-command.js +1 -1
  100. package/lib/vendor/blamejs/lib/guard-jmap.js +1 -1
  101. package/lib/vendor/blamejs/lib/guard-json.js +14 -6
  102. package/lib/vendor/blamejs/lib/guard-mail-move.js +1 -1
  103. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +1 -1
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +1 -1
  105. package/lib/vendor/blamejs/lib/guard-smtp-command.js +1 -1
  106. package/lib/vendor/blamejs/lib/guard-svg.js +8 -9
  107. package/lib/vendor/blamejs/lib/html-balance.js +7 -3
  108. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +33 -12
  109. package/lib/vendor/blamejs/lib/http-client.js +225 -53
  110. package/lib/vendor/blamejs/lib/iab-tcf.js +3 -2
  111. package/lib/vendor/blamejs/lib/importmap-integrity.js +41 -1
  112. package/lib/vendor/blamejs/lib/incident-report.js +9 -6
  113. package/lib/vendor/blamejs/lib/json-patch.js +1 -1
  114. package/lib/vendor/blamejs/lib/json-path.js +24 -3
  115. package/lib/vendor/blamejs/lib/jtd.js +2 -2
  116. package/lib/vendor/blamejs/lib/legal-hold.js +24 -8
  117. package/lib/vendor/blamejs/lib/log.js +2 -2
  118. package/lib/vendor/blamejs/lib/mail-agent.js +2 -2
  119. package/lib/vendor/blamejs/lib/mail-arf.js +1 -1
  120. package/lib/vendor/blamejs/lib/mail-auth.js +3 -3
  121. package/lib/vendor/blamejs/lib/mail-bimi.js +16 -16
  122. package/lib/vendor/blamejs/lib/mail-bounce.js +3 -3
  123. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +71 -6
  124. package/lib/vendor/blamejs/lib/mail-deploy.js +9 -5
  125. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -4
  126. package/lib/vendor/blamejs/lib/mail-helo.js +2 -4
  127. package/lib/vendor/blamejs/lib/mail-journal.js +11 -8
  128. package/lib/vendor/blamejs/lib/mail-mdn.js +8 -4
  129. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -4
  130. package/lib/vendor/blamejs/lib/mail-scan.js +3 -5
  131. package/lib/vendor/blamejs/lib/mail-server-jmap.js +4 -1
  132. package/lib/vendor/blamejs/lib/mail-server-registry.js +1 -1
  133. package/lib/vendor/blamejs/lib/mail-server-tls.js +9 -2
  134. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -4
  135. package/lib/vendor/blamejs/lib/mail-store-fts.js +1 -1
  136. package/lib/vendor/blamejs/lib/mail.js +22 -2
  137. package/lib/vendor/blamejs/lib/markup-tokenizer.js +24 -0
  138. package/lib/vendor/blamejs/lib/mcp.js +6 -4
  139. package/lib/vendor/blamejs/lib/mdoc.js +26 -3
  140. package/lib/vendor/blamejs/lib/metrics.js +14 -3
  141. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +2 -2
  142. package/lib/vendor/blamejs/lib/middleware/body-parser.js +10 -4
  143. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +26 -18
  144. package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +5 -1
  145. package/lib/vendor/blamejs/lib/middleware/compression.js +9 -0
  146. package/lib/vendor/blamejs/lib/middleware/cors.js +32 -23
  147. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +60 -21
  148. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -4
  149. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +28 -4
  150. package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +61 -30
  151. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +25 -16
  152. package/lib/vendor/blamejs/lib/middleware/scim-server.js +2 -1
  153. package/lib/vendor/blamejs/lib/middleware/security-headers.js +24 -6
  154. package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +6 -3
  155. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +2 -2
  156. package/lib/vendor/blamejs/lib/money.js +1 -1
  157. package/lib/vendor/blamejs/lib/mtls-ca.js +10 -6
  158. package/lib/vendor/blamejs/lib/network-dns-resolver.js +1 -1
  159. package/lib/vendor/blamejs/lib/network-dns.js +9 -2
  160. package/lib/vendor/blamejs/lib/network-dnssec.js +2 -1
  161. package/lib/vendor/blamejs/lib/network-smtp-policy.js +23 -5
  162. package/lib/vendor/blamejs/lib/network-tls.js +27 -5
  163. package/lib/vendor/blamejs/lib/network-tsig.js +2 -2
  164. package/lib/vendor/blamejs/lib/nis2-report.js +1 -1
  165. package/lib/vendor/blamejs/lib/nist-crosswalk.js +1 -1
  166. package/lib/vendor/blamejs/lib/ntp-check.js +28 -0
  167. package/lib/vendor/blamejs/lib/numeric-bounds.js +9 -0
  168. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +1 -2
  169. package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +4 -2
  170. package/lib/vendor/blamejs/lib/object-store/gcs.js +6 -4
  171. package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -2
  172. package/lib/vendor/blamejs/lib/object-store/http-request.js +30 -1
  173. package/lib/vendor/blamejs/lib/object-store/local.js +37 -17
  174. package/lib/vendor/blamejs/lib/object-store/sigv4.js +1 -2
  175. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +20 -4
  176. package/lib/vendor/blamejs/lib/outbox.js +11 -4
  177. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +1 -1
  178. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +21 -3
  179. package/lib/vendor/blamejs/lib/queue-local.js +10 -3
  180. package/lib/vendor/blamejs/lib/redact.js +7 -3
  181. package/lib/vendor/blamejs/lib/request-helpers.js +201 -23
  182. package/lib/vendor/blamejs/lib/resource-access-lock.js +3 -3
  183. package/lib/vendor/blamejs/lib/restore-bundle.js +46 -18
  184. package/lib/vendor/blamejs/lib/restore-rollback.js +10 -4
  185. package/lib/vendor/blamejs/lib/restore.js +19 -0
  186. package/lib/vendor/blamejs/lib/retention.js +20 -4
  187. package/lib/vendor/blamejs/lib/router.js +17 -4
  188. package/lib/vendor/blamejs/lib/safe-ical.js +2 -2
  189. package/lib/vendor/blamejs/lib/safe-icap.js +1 -1
  190. package/lib/vendor/blamejs/lib/safe-json.js +44 -0
  191. package/lib/vendor/blamejs/lib/safe-sieve.js +1 -1
  192. package/lib/vendor/blamejs/lib/safe-vcard.js +1 -1
  193. package/lib/vendor/blamejs/lib/sandbox-worker.js +6 -0
  194. package/lib/vendor/blamejs/lib/sandbox.js +1 -1
  195. package/lib/vendor/blamejs/lib/scheduler.js +17 -1
  196. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +16 -0
  197. package/lib/vendor/blamejs/lib/session.js +27 -3
  198. package/lib/vendor/blamejs/lib/sql.js +3 -3
  199. package/lib/vendor/blamejs/lib/static.js +65 -13
  200. package/lib/vendor/blamejs/lib/template.js +7 -5
  201. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -19
  202. package/lib/vendor/blamejs/lib/tsa.js +5 -2
  203. package/lib/vendor/blamejs/lib/vault/index.js +5 -0
  204. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +22 -26
  205. package/lib/vendor/blamejs/lib/vault/passphrase-source.js +8 -3
  206. package/lib/vendor/blamejs/lib/vault/rotate.js +13 -18
  207. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +4 -1
  208. package/lib/vendor/blamejs/lib/vc.js +1 -1
  209. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +10 -10
  210. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +23 -10
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5498 -5494
  212. package/lib/vendor/blamejs/lib/webhook.js +16 -1
  213. package/lib/vendor/blamejs/lib/websocket.js +1 -1
  214. package/lib/vendor/blamejs/lib/worm.js +1 -1
  215. package/lib/vendor/blamejs/lib/ws-client.js +57 -46
  216. package/lib/vendor/blamejs/lib/x509-chain.js +44 -0
  217. package/lib/vendor/blamejs/package.json +1 -1
  218. package/lib/vendor/blamejs/release-notes/v0.15.14.json +122 -0
  219. package/lib/vendor/blamejs/scripts/check-vendor-currency.js +119 -4
  220. package/lib/vendor/blamejs/test/00-primitives.js +5 -1
  221. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +18 -4
  222. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +42 -0
  223. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +36 -0
  224. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  225. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +47 -0
  226. package/lib/vendor/blamejs/test/layer-0-primitives/archive-gz.test.js +24 -0
  227. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-hardening.test.js +160 -0
  228. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +45 -0
  229. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +30 -0
  230. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-open-nofollow.test.js +79 -0
  231. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-excl.test.js +132 -0
  232. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-stream.test.js +181 -0
  233. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-corrupted-anchor.test.js +65 -0
  234. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-incremental-verify.test.js +83 -0
  235. package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +48 -1
  236. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +13 -3
  237. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +122 -0
  238. package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +37 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +5 -3
  240. package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +21 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +73 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +17 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +62 -3
  244. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +12 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-storage.test.js +40 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +146 -5
  247. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +14 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/compression-range.test.js +115 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +17 -5
  250. package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +27 -5
  251. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +83 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +58 -0
  253. package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +30 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +74 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +20 -6
  256. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-alg-kty.test.js +64 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +32 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +43 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +30 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +33 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +34 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +12 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +72 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-throttle-transform.test.js +88 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +25 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +28 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +20 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/mail-header-injection.test.js +58 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +63 -9
  270. package/lib/vendor/blamejs/test/layer-0-primitives/mdoc.test.js +41 -14
  271. package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +61 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/object-store-range-header.test.js +51 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +35 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/output-header-hardening.test.js +102 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/parser-verify-hardening.test.js +191 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/proto-shadow-allowlist.test.js +120 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +75 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +128 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/restore-blob-remap.test.js +128 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/retention-sweep-termination.test.js +104 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/router-body-validation.test.js +98 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json-stringify-for-script.test.js +43 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +48 -5
  284. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +23 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +54 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +24 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +42 -1
  288. package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +7 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/template-escape-html.test.js +43 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +15 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/vault-default-store.test.js +48 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/vendor-currency-classify.test.js +77 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +50 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +22 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/x509-chain-ca-enforcement.test.js +149 -0
  296. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +34 -0
  297. package/package.json +1 -1
@@ -31,6 +31,7 @@
31
31
  var nodeCrypto = require("node:crypto");
32
32
  var C = require("./constants");
33
33
  var bCrypto = require("./crypto");
34
+ var x509Chain = require("./x509-chain");
34
35
  var canonicalJson = require("./canonical-json");
35
36
  var safeJson = require("./safe-json");
36
37
  var validateOpts = require("./validate-opts");
@@ -1103,7 +1104,7 @@ function attachIdentityAssertion(opts) {
1103
1104
  validateOpts.requireObject(opts, "contentCredentials.attachIdentityAssertion", ContentCredentialsError);
1104
1105
  validateOpts(opts, ["binding", "subject", "referencedAssertions", "privateKeyPem", "audit"],
1105
1106
  "contentCredentials.attachIdentityAssertion");
1106
- if (typeof opts.binding !== "string" || !IDENTITY_BINDINGS[opts.binding]) {
1107
+ if (typeof opts.binding !== "string" || !Object.prototype.hasOwnProperty.call(IDENTITY_BINDINGS, opts.binding)) {
1107
1108
  throw ContentCredentialsError.factory("content-credentials/bad-identity-binding",
1108
1109
  "attachIdentityAssertion: binding must be one of " + Object.keys(IDENTITY_BINDINGS).join(" / "));
1109
1110
  }
@@ -1217,7 +1218,7 @@ function verifyIdentityAssertion(assertion, publicKeyPem, opts) {
1217
1218
  return _fail("public-key-required");
1218
1219
  }
1219
1220
  var sp = assertion.signer_payload;
1220
- if (!sp || typeof sp !== "object" || typeof sp.binding !== "string" || !IDENTITY_BINDINGS[sp.binding] ||
1221
+ if (!sp || typeof sp !== "object" || typeof sp.binding !== "string" || !Object.prototype.hasOwnProperty.call(IDENTITY_BINDINGS, sp.binding) ||
1221
1222
  !Array.isArray(sp.referenced_assertions)) {
1222
1223
  return _fail("signer-payload-shape");
1223
1224
  }
@@ -1334,9 +1335,10 @@ function _verifyIdentityX509Chain(certChainPem, trustAnchorsPem) {
1334
1335
  // only direct-root / self-signed leaves.
1335
1336
  for (var li = 0; li < certs.length - 1; li += 1) {
1336
1337
  var child = certs[li], parent = certs[li + 1];
1337
- var linked = false;
1338
- try { linked = child.checkIssued(parent) && child.verify(parent.publicKey); }
1339
- catch (_eLink) { linked = false; }
1338
+ // issuerValidlyIssued enforces basicConstraints cA:TRUE on the parent in
1339
+ // addition to the issuance + signature linkage — a non-CA cert cannot be
1340
+ // an intermediate issuer (basicConstraints bypass, CVE-2002-0862 class).
1341
+ var linked = x509Chain.issuerValidlyIssued(parent, child);
1340
1342
  if (!linked) { return { ok: false, reason: "broken-chain" }; }
1341
1343
  }
1342
1344
  // The top of the presented chain must chain to (or BE) a trust anchor.
@@ -1347,8 +1349,9 @@ function _verifyIdentityX509Chain(certChainPem, trustAnchorsPem) {
1347
1349
  if (top.fingerprint256 === anchor.fingerprint256) {
1348
1350
  chained = true; // top of the chain IS the anchor (root-in-chain or self-signed leaf == anchor)
1349
1351
  } else {
1350
- try { chained = top.checkIssued(anchor) && top.verify(anchor.publicKey); }
1351
- catch (_eChk) { chained = false; }
1352
+ // issuerValidlyIssued enforces basicConstraints cA:TRUE on the anchor
1353
+ // in addition to issuance + signature (basicConstraints bypass class).
1354
+ chained = x509Chain.issuerValidlyIssued(anchor, top);
1352
1355
  }
1353
1356
  if (chained) {
1354
1357
  if (now < anchor.validFromDate.getTime() || now > anchor.validToDate.getTime()) {
@@ -1427,7 +1430,7 @@ function cacImplicitLabel(opts) {
1427
1430
  throw new ContentCredentialsError("cac-implicit-label/bad-content-id",
1428
1431
  "cacImplicitLabel: contentId must match [A-Za-z0-9._:/-]");
1429
1432
  }
1430
- if (typeof opts.contentKind !== "string" || !CAC_KIND_ENUM[opts.contentKind]) {
1433
+ if (typeof opts.contentKind !== "string" || !Object.prototype.hasOwnProperty.call(CAC_KIND_ENUM, opts.contentKind)) {
1431
1434
  throw new ContentCredentialsError("cac-implicit-label/bad-content-kind",
1432
1435
  "cacImplicitLabel: contentKind must be one of " +
1433
1436
  Object.keys(CAC_KIND_ENUM).join("/"));
@@ -99,9 +99,12 @@ function create(body, opts) {
99
99
  if (!Array.isArray(algos) || algos.length === 0) throw new ContentDigestError("content-digest/bad-arg", "contentDigest.create: opts.algorithms must be a non-empty array");
100
100
  var members = algos.map(function (a) {
101
101
  var name = String(a).toLowerCase();
102
- var nodeAlg = ACTIVE[name];
102
+ // hasOwnProperty: the algorithm name is operator/caller input; a bracket
103
+ // lookup lets "constructor"/"toString" inherit a truthy value off the
104
+ // prototype and pass the support check (proto shadowing).
105
+ var nodeAlg = Object.prototype.hasOwnProperty.call(ACTIVE, name) ? ACTIVE[name] : undefined;
103
106
  if (!nodeAlg) {
104
- if (DEPRECATED[name]) throw new ContentDigestError("content-digest/insecure-algorithm", "contentDigest.create: '" + name + "' is a deprecated/insecure digest algorithm (RFC 9530 §6); use sha-256 or sha-512");
107
+ if (Object.prototype.hasOwnProperty.call(DEPRECATED, name)) throw new ContentDigestError("content-digest/insecure-algorithm", "contentDigest.create: '" + name + "' is a deprecated/insecure digest algorithm (RFC 9530 §6); use sha-256 or sha-512");
105
108
  throw new ContentDigestError("content-digest/unsupported-algorithm", "contentDigest.create: unsupported digest algorithm '" + name + "'");
106
109
  }
107
110
  var digest = nodeCrypto.createHash(nodeAlg).update(bytes).digest("base64");
@@ -154,8 +157,12 @@ function verify(fieldValue, body, opts) {
154
157
  var kvp = structuredFields.parseKeyValuePiece(m);
155
158
  var name = kvp.key;
156
159
  var raw = kvp.value.trim();
160
+ // hasOwnProperty: `name` is the algorithm token from the untrusted inbound
161
+ // Content-Digest header; a bracket lookup lets "constructor"/"__proto__"
162
+ // inherit a truthy value off the prototype and reach createHash (proto
163
+ // shadowing).
164
+ if (!Object.prototype.hasOwnProperty.call(ACTIVE, name)) continue; // ignore legacy / unknown entries
157
165
  var nodeAlg = ACTIVE[name];
158
- if (!nodeAlg) continue; // ignore legacy / unknown entries
159
166
  if (raw.length < 2 || raw.charAt(0) !== ":" || raw.charAt(raw.length - 1) !== ":") {
160
167
  throw new ContentDigestError("content-digest/bad-field", "contentDigest.verify: '" + name + "' value is not an RFC 8941 byte sequence (:base64:)");
161
168
  }
@@ -172,7 +179,7 @@ function verify(fieldValue, body, opts) {
172
179
  if (!Array.isArray(opts.required)) throw new ContentDigestError("content-digest/bad-arg", "contentDigest.verify: opts.required must be an array");
173
180
  for (var r = 0; r < opts.required.length; r++) {
174
181
  var req = String(opts.required[r]).toLowerCase();
175
- if (!ACTIVE[req]) throw new ContentDigestError("content-digest/unsupported-algorithm", "contentDigest.verify: required algorithm '" + req + "' is not a modern digest");
182
+ if (!Object.prototype.hasOwnProperty.call(ACTIVE, req)) throw new ContentDigestError("content-digest/unsupported-algorithm", "contentDigest.verify: required algorithm '" + req + "' is not a modern digest");
176
183
  if (!seen[req]) throw new ContentDigestError("content-digest/missing-algorithm", "contentDigest.verify: required digest '" + req + "' is not present");
177
184
  }
178
185
  }
@@ -96,7 +96,11 @@ function _validateValue(value) {
96
96
  // Length cap before the regex test (defense in depth — the regex
97
97
  // here is a simple character class, but the same discipline that
98
98
  // bounds longer regexes elsewhere applies).
99
- if (value.length > MAX_VALUE_LENGTH || FORBIDDEN_VALUE_RE.test(value)) {
99
+ // Byte length, not value.length (UTF-16 code units): the cap bounds the
100
+ // on-the-wire Set-Cookie size, and a multibyte value is 2-4x larger in bytes
101
+ // than chars, so a char-count check under-enforces and a 4096-char value can
102
+ // emit a ~12 KiB+ header.
103
+ if (Buffer.byteLength(value, "utf8") > MAX_VALUE_LENGTH || FORBIDDEN_VALUE_RE.test(value)) {
100
104
  throw new CookieError("cookies/invalid-value",
101
105
  "cookie value is too long or contains forbidden control character (CRLF/NUL/;/,)");
102
106
  }
@@ -108,7 +112,11 @@ function _validateValue(value) {
108
112
  // header — never trust unscrubbed values reach the wire.
109
113
  function _scrubAttr(s) {
110
114
  if (typeof s !== "string") return s;
111
- return s.replace(/[\r\n\0]/g, ""); // allow:duplicate-regex CR/LF/NUL header-injection rejection appears in cookies / mail / security-headers; each is the boundary primitive for its domain
115
+ // `;` joins Set-Cookie attributes, so an unscrubbed `;` in Path/SameSite is
116
+ // attribute injection (e.g. Path=/x; HttpOnly). Domain is regex-validated
117
+ // upstream; Path/SameSite only flow through here, so strip `;` alongside the
118
+ // CR/LF/NUL header-injection set.
119
+ return s.replace(/[\r\n\0;]/g, ""); // allow:duplicate-regex — CR/LF/NUL(+;) header-injection rejection appears in cookies / mail / security-headers; each is the boundary primitive for its domain
112
120
 
113
121
  }
114
122
 
@@ -110,6 +110,24 @@ function _algParamsFor(algId) {
110
110
  }
111
111
  }
112
112
 
113
+ // RFC 9053 §2 binds each ECDSA alg to ONE curve. node:crypto will happily
114
+ // verify a sha512 (ES512-shape) signature against a P-256 key as
115
+ // self-consistent, so without this check a COSE_Sign1 declaring ES512 but
116
+ // carrying a P-256 key passes when ES512 is allowlisted — an alg/curve
117
+ // confusion (the COSE sibling of jwt-external._assertAlgKtyMatch). EdDSA /
118
+ // ML-DSA carry their parameters in the KeyObject and need no binding.
119
+ var _ES_ALG_CURVE = { ES256: "prime256v1", ES384: "secp384r1", ES512: "secp521r1" };
120
+ function _assertEcAlgCurve(algName, key) {
121
+ var want = _ES_ALG_CURVE[algName];
122
+ if (want === undefined) return; // not an ECDSA alg — nothing to bind
123
+ var got = (key && key.asymmetricKeyDetails && key.asymmetricKeyDetails.namedCurve) || null;
124
+ if (key.asymmetricKeyType !== "ec" || got !== want) {
125
+ throw new CoseError("cose/alg-curve-mismatch",
126
+ "cose: alg '" + algName + "' requires an EC key on " + want +
127
+ ", got " + (key.asymmetricKeyType === "ec" ? got : key.asymmetricKeyType));
128
+ }
129
+ }
130
+
113
131
  function _bstr(x) {
114
132
  return safeBuffer.toBuffer(x, {
115
133
  errorFactory: function (code, msg) { return new CoseError(code, msg); },
@@ -169,6 +187,7 @@ async function sign(payload, opts) {
169
187
  var algId = ALG_NAME_TO_ID[opts.alg];
170
188
  var params = _algParamsFor(algId);
171
189
  var key = _toKeyObject(opts.privateKey, "private");
190
+ _assertEcAlgCurve(opts.alg, key); // RFC 9053 alg↔curve binding — refuse e.g. ES512 over a P-256 key
172
191
 
173
192
  var protMap = new Map();
174
193
  protMap.set(HDR_ALG, algId);
@@ -352,6 +371,7 @@ async function verify(coseSign1, opts) {
352
371
  var key = opts.publicKey
353
372
  ? _toKeyObject(opts.publicKey, "public")
354
373
  : _toKeyObject(opts.keyResolver(protMap, unprotected), "public");
374
+ _assertEcAlgCurve(algName, key); // RFC 9053 alg↔curve binding
355
375
 
356
376
  var externalAad = opts.externalAad == null ? Buffer.alloc(0) : _bstr(opts.externalAad);
357
377
  var toBeSigned = _toBeSigned(protectedBstr, externalAad, payload);
@@ -41,6 +41,7 @@
41
41
 
42
42
  var bCrypto = require("./crypto");
43
43
  var safeJson = require("./safe-json");
44
+ var numericBounds = require("./numeric-bounds");
44
45
  var { defineClass } = require("./framework-error");
45
46
 
46
47
  var CrdtError = defineClass("CrdtError", { alwaysPermanent: true });
@@ -52,7 +53,7 @@ function _replicaId(opts) {
52
53
  return id;
53
54
  }
54
55
  function _posInt(n, label) {
55
- if (typeof n !== "number" || !isFinite(n) || n < 0 || Math.floor(n) !== n) throw new CrdtError("crdt/bad-value", "crdt: " + label + " must be a non-negative integer");
56
+ if (!numericBounds.isNonNegativeFiniteInt(n)) throw new CrdtError("crdt/bad-value", "crdt: " + label + " must be a non-negative integer");
56
57
  return n;
57
58
  }
58
59
  function _maxMerge(a, b) {
@@ -62,7 +62,6 @@ var vaultAad = require("./vault-aad");
62
62
  var validateOpts = require("./validate-opts");
63
63
  var numericBounds = require("./numeric-bounds");
64
64
  var safeJson = require("./safe-json");
65
- var frameworkSchema = require("./framework-schema");
66
65
  var sql = require("./sql");
67
66
  var { defineClass } = require("./framework-error");
68
67
  var { sha3Hash, kdf, generateBytes, encryptPacked, decryptPacked, generateToken } = require("./crypto");
@@ -226,14 +225,19 @@ var PER_ROW_KEYS_TABLE = "_blamejs_per_row_keys"; // allow:hand-rolled-sql
226
225
  var PER_ROW_KEYS_COLUMN = "wrappedKey";
227
226
  var PER_ROW_KEYS_SCHEMA_VERSION = "1";
228
227
 
229
- // The per-row-key registry is read/written against the LOCAL db() / dbHandle
230
- // handle directly (not clusterStorage), so SQL composed for it uses the
231
- // RESOLVED name (prefix-aware via frameworkSchema.tableName) and quoteName so
232
- // b.sql emits the quoted identifier the single-node path expects the same
233
- // shape db-query.js's _sqlOpts and db.js's own local-handle b.sql calls use.
228
+ // The per-row-key registry ALWAYS lives in the LOCAL sqlite reconcile creates
229
+ // it under its RAW schema name, and per-row keys are never dispatched to an
230
+ // external backend (see _kRowOnce's db() fallback). It is read/written against
231
+ // the local db() / dbHandle directly, NOT through clusterStorage, so it must use
232
+ // the RAW table name. frameworkSchema.tableName() resolves to the cluster-mode
233
+ // EXTERNAL prefixed name (the prefix applies only to the external backend, via
234
+ // resolveTables — local DDL stays raw); under a custom tablePrefix that names a
235
+ // table that does not exist locally, which SILENTLY breaks crypto-shred:
236
+ // destroyPerRowKey deletes 0 rows and sealed cells stay decryptable after
237
+ // eraseHard. quoteName so b.sql emits the quoted identifier the local path expects.
234
238
  var _PER_ROW_SQL_OPTS = { dialect: "sqlite", quoteName: true };
235
239
  function _perRowKeysTableName() {
236
- return frameworkSchema.tableName(PER_ROW_KEYS_TABLE);
240
+ return PER_ROW_KEYS_TABLE;
237
241
  }
238
242
 
239
243
  // Build the canonical AAD parts for a row-secret wrap in
@@ -1271,19 +1275,19 @@ function unsealRow(table, row, actor, dbHandle) {
1271
1275
  unsealed = out[field];
1272
1276
  }
1273
1277
  } catch (e) {
1274
- // A DB-write attacker who can write `vault:<crafted>` /
1275
- // `vault.aad:<crafted>` payloads to sealed columns can force
1276
- // KEM decapsulation / AEAD verify on attacker-controlled
1277
- // bytes via this read path. Surface the failure as a chain
1278
- // row so operators alert on burst patterns; null the field
1279
- // so downstream code sees "no value" instead of crashing the
1280
- // request. AAD-shape failures additionally indicate cross-
1281
- // row copy attempts the audit metadata flags the shape so
1282
- // operators can write alert rules.
1278
+ // A crypto-shredded (or never-materialized) per-row key is an EXPECTED
1279
+ // absence, not a decryption-oracle attack: the wrapped secret is gone,
1280
+ // so there is no oracle to brute-force. Reading such a row must read as
1281
+ // "no value" WITHOUT counting against the rate cap — otherwise a bulk
1282
+ // read over a table with many erased rows (GDPR eraseHard) trips the
1283
+ // cap and DoS's the live rows (self-DoS, CWE-307 mis-applied). It is
1284
+ // audited under a distinct, non-failure action so operators don't alert
1285
+ // on routine post-erasure reads as forged-ciphertext bursts.
1286
+ var _shredded = e && e.code === "crypto-field/row-key-unavailable";
1283
1287
  try {
1284
1288
  audit().safeEmit({
1285
- action: "system.crypto.unseal_failed",
1286
- outcome: "failure",
1289
+ action: _shredded ? "system.crypto.shredded_read" : "system.crypto.unseal_failed",
1290
+ outcome: _shredded ? "success" : "failure",
1287
1291
  metadata: {
1288
1292
  table: table,
1289
1293
  field: field,
@@ -1293,11 +1297,13 @@ function unsealRow(table, row, actor, dbHandle) {
1293
1297
  },
1294
1298
  });
1295
1299
  } catch (_e) { /* drop-silent */ }
1296
- // Default-on rate cap: account this failure against the (actor,
1297
- // table, column) tuple. When it trips the threshold, arm the
1298
- // cooldown + emit the distinct rate-exceeded audit once on the
1299
- // transition. No-op when the cap is disabled.
1300
- if (_rateNoteFailure(capActor, table, field)) {
1300
+ // Default-on rate cap: account a genuine decryption / AEAD-verify /
1301
+ // AAD-downgrade failure (a possible forged-ciphertext attack) against
1302
+ // the (actor, table, column) tuple. A shredded-key read is exempt (see
1303
+ // above). When the cap trips the threshold, arm the cooldown + emit the
1304
+ // distinct rate-exceeded audit once on the transition. No-op when the
1305
+ // cap is disabled.
1306
+ if (!_shredded && _rateNoteFailure(capActor, table, field)) {
1301
1307
  _emitRateAudit({
1302
1308
  table: table, field: field, actor: capActor, shape: shape,
1303
1309
  threshold: _rateCap.threshold, windowMs: _rateCap.windowMs, cooldownMs: _rateCap.cooldownMs,
@@ -963,7 +963,7 @@ var SRI_ALGORITHMS = { "sha256": "sha256", "sha384": "sha384", "sha512": "sha512
963
963
  function sri(content, opts) {
964
964
  opts = opts || {};
965
965
  var algorithm = (opts.algorithm || "sha384").toLowerCase();
966
- if (!SRI_ALGORITHMS[algorithm]) {
966
+ if (!Object.prototype.hasOwnProperty.call(SRI_ALGORITHMS, algorithm)) {
967
967
  throw new Error("crypto.sri: unsupported algorithm '" + algorithm +
968
968
  "' (W3C SRI 1.0 §3.2 supports sha256/sha384/sha512)");
969
969
  }
@@ -1356,7 +1356,21 @@ function decrypt(ciphertext, privateKeys, opts) {
1356
1356
  opts && opts.raw === true ? { raw: true } : undefined);
1357
1357
  }
1358
1358
 
1359
+ // Bounds-checked 2-byte length read — a bare _envU16(packed, pos) on a
1360
+ // truncated envelope throws a raw Node RangeError that escapes the documented
1361
+ // "Invalid envelope: ..." error contract (untrusted ciphertext must fail with
1362
+ // the typed envelope error, not a stack-trace-leaking RangeError).
1363
+ function _envU16(buf, at) {
1364
+ if (at + 2 > buf.length) {
1365
+ throw new Error("Invalid envelope: truncated (expected a 2-byte length at offset " + at + ")");
1366
+ }
1367
+ return buf.readUInt16BE(at);
1368
+ }
1369
+
1359
1370
  function decryptEnvelope(packed, privateKeys, internalOpts) {
1371
+ if (!Buffer.isBuffer(packed) || packed.length < 4) {
1372
+ throw new Error("Invalid envelope: too short (need at least the 4-byte suite header)");
1373
+ }
1360
1374
  var kemId = packed[1], cipherId = packed[2], kdfId = packed[3], pos = 4;
1361
1375
 
1362
1376
  // The legacy 0xE1 envelope predates the FixedInfo / suite-binding
@@ -1372,7 +1386,7 @@ function decryptEnvelope(packed, privateKeys, internalOpts) {
1372
1386
  throw new Error("Invalid envelope: unsupported KDF (only SHAKE256 supported)");
1373
1387
  }
1374
1388
 
1375
- var kemCtLen = packed.readUInt16BE(pos); pos += 2;
1389
+ var kemCtLen = _envU16(packed, pos); pos += 2;
1376
1390
  var kemCt = packed.subarray(pos, pos + kemCtLen); pos += kemCtLen;
1377
1391
 
1378
1392
  var mlkemPriv = nodeCrypto.createPrivateKey(
@@ -1383,7 +1397,7 @@ function decryptEnvelope(packed, privateKeys, internalOpts) {
1383
1397
  var fixedInfo = omitFixedInfo ? Buffer.alloc(0) : _suiteFixedInfo(kemId, cipherId, kdfId);
1384
1398
 
1385
1399
  if (kemId === C.KEM_IDS.ML_KEM_1024_P384) {
1386
- var ecEphLen = packed.readUInt16BE(pos); pos += 2;
1400
+ var ecEphLen = _envU16(packed, pos); pos += 2;
1387
1401
  var ecEphDer = packed.subarray(pos, pos + ecEphLen); pos += ecEphLen;
1388
1402
  var ecPrivPem = typeof privateKeys === "string" ? null : privateKeys.ecPrivateKey;
1389
1403
  if (!ecPrivPem) throw new Error("Hybrid KEM requires EC private key");
@@ -1400,7 +1414,7 @@ function decryptEnvelope(packed, privateKeys, internalOpts) {
1400
1414
  // the correct keypair via privateKeys when the envelope was sealed
1401
1415
  // with this algorithm. Same length-prefixed shape as the P-384
1402
1416
  // hybrid: 2-byte ec-eph-len + DER X25519 pubkey + nonce + ct.
1403
- var x25519EphLen = packed.readUInt16BE(pos); pos += 2;
1417
+ var x25519EphLen = _envU16(packed, pos); pos += 2;
1404
1418
  var x25519EphDer = packed.subarray(pos, pos + x25519EphLen); pos += x25519EphLen;
1405
1419
  var x25519PrivPem = typeof privateKeys === "string" ? null : privateKeys.x25519PrivateKey;
1406
1420
  if (!x25519PrivPem) throw new Error("ML-KEM-768 + X25519 hybrid envelope requires x25519PrivateKey");
@@ -416,6 +416,10 @@ function mergeDirectives(base, additions, opts) {
416
416
  ? directives[name].slice()
417
417
  : (directives["default-src"] ? directives["default-src"].slice() : ["'self'"]);
418
418
  var added = additions[name];
419
+ // A directive value of 'none' MUST stand alone (CSP3 §2.3.1) — appending a
420
+ // host to it emits the malformed "'none' https://x". When merging real
421
+ // sources in, the added sources supersede 'none', so drop it first.
422
+ if (added.length && existing.length === 1 && existing[0] === "'none'") existing = [];
419
423
  for (var si = 0; si < added.length; si += 1) {
420
424
  if (existing.indexOf(added[si]) === -1) existing.push(added[si]);
421
425
  }
@@ -73,7 +73,10 @@ function _isLivePid(pid) {
73
73
 
74
74
  function _readPidFile(pidFile) {
75
75
  try {
76
- var raw = nodeFs.readFileSync(pidFile, "utf8");
76
+ // Same fd-safe + capped + symlink-refusing read as app-shutdown's lockfile
77
+ // reader (one shape): a PID file is never a legit symlink mount, so
78
+ // refuseSymlink is safe; any throw → null ("nothing live there").
79
+ var raw = atomicFile.fdSafeReadSync(pidFile, { maxBytes: C.BYTES.kib(1), refuseSymlink: true, encoding: "utf8" });
77
80
  var pid = parseInt(String(raw).trim(), 10);
78
81
  return isFinite(pid) && pid > 0 ? pid : null;
79
82
  } catch (_e) { return null; }
@@ -89,6 +89,32 @@ var DESIGNATED_GATEKEEPERS = Object.freeze([
89
89
  "booking",
90
90
  ]);
91
91
 
92
+ // Is `recipient` a designated DMA gatekeeper? Match the gatekeeper token as a
93
+ // DNS LABEL of the recipient's host authority — any position, including the
94
+ // FINAL label. A substring `indexOf(g + ".")` test missed a gatekeeper that is
95
+ // the last label (e.g. "blog.google" / "drive.google" on the real ".google"
96
+ // TLD, or "data.amazon"), letting an Art 32 §1 third-party share through — and
97
+ // also false-flagged a non-gatekeeper whose name merely contained the token
98
+ // ("notgoogle.com"). Label matching closes the bypass and drops the false
99
+ // positive. A bare name ("Google") still matches exactly. URL / userinfo / port
100
+ // forms are normalized to the host authority first.
101
+ function _isGatekeeperRecipient(recipient) {
102
+ var s = String(recipient).toLowerCase().trim();
103
+ var scheme = s.indexOf("://");
104
+ if (scheme !== -1) s = s.slice(scheme + 3);
105
+ s = s.split("/")[0].split("?")[0].split("#")[0]; // drop path / query / fragment
106
+ var at = s.lastIndexOf("@");
107
+ if (at !== -1) s = s.slice(at + 1); // drop userinfo
108
+ s = s.split(":")[0]; // drop port
109
+ if (s.length === 0) return false;
110
+ var labels = s.split(".");
111
+ return DESIGNATED_GATEKEEPERS.some(function (g) {
112
+ if (s === g) return true;
113
+ for (var i = 0; i < labels.length; i++) { if (labels[i] === g) return true; }
114
+ return false;
115
+ });
116
+ }
117
+
92
118
  /**
93
119
  * @primitive b.dataAct.declareProduct
94
120
  * @signature b.dataAct.declareProduct(opts)
@@ -229,10 +255,7 @@ function shareWithThirdParty(opts) {
229
255
  acceptGatekeeper: "optional-plain-object",
230
256
  }, "dataAct.shareWithThirdParty", DataActError, "dataact/bad-opts");
231
257
 
232
- var recipientLower = opts.recipient.toLowerCase();
233
- var isGatekeeper = DESIGNATED_GATEKEEPERS.some(function (g) {
234
- return recipientLower === g || recipientLower.indexOf(g + ".") !== -1;
235
- });
258
+ var isGatekeeper = _isGatekeeperRecipient(opts.recipient);
236
259
  if (isGatekeeper) {
237
260
  if (!opts.acceptGatekeeper || typeof opts.acceptGatekeeper !== "object" ||
238
261
  typeof opts.acceptGatekeeper.reason !== "string" ||
@@ -172,8 +172,11 @@ function fileLifecycle(opts) {
172
172
  : nodePath.join(opts.dataDir, frameworkFiles.fileName("dbKeyEnc"));
173
173
  var flushIntervalMs = opts.flushIntervalMs || DEFAULT_FLUSH_INTERVAL_MS;
174
174
  var tmpDir = _resolveTmpDir(opts.tmpDir, opts.allowDiskFallback === true);
175
- if (!nodeFs.existsSync(tmpDir)) nodeFs.mkdirSync(tmpDir, { recursive: true });
176
- if (!nodeFs.existsSync(opts.dataDir)) nodeFs.mkdirSync(opts.dataDir, { recursive: true });
175
+ // 0o700 these hold the DB encryption tmpfs scratch + the data dir
176
+ // (db.key.enc, the decrypted DB while open); a default-mode mkdir leaves
177
+ // them group/other-traversable.
178
+ if (!nodeFs.existsSync(tmpDir)) nodeFs.mkdirSync(tmpDir, { recursive: true, mode: 0o700 });
179
+ if (!nodeFs.existsSync(opts.dataDir)) nodeFs.mkdirSync(opts.dataDir, { recursive: true, mode: 0o700 });
177
180
 
178
181
  var dbPath = null;
179
182
  var encKey = null;
@@ -183,7 +186,9 @@ function fileLifecycle(opts) {
183
186
  function _loadOrGenerateKey() {
184
187
  if (encKey) return encKey;
185
188
  if (nodeFs.existsSync(keyPath)) {
186
- var sealedKey = nodeFs.readFileSync(keyPath, "utf8");
189
+ // Cap + fd-bound. NO refuseSymlink: dbKeyPath may be an operator-absolute
190
+ // KMS-fronted volume that legitimately symlinks the sealed key.
191
+ var sealedKey = atomicFile.fdSafeReadSync(keyPath, { maxBytes: C.BYTES.kib(64), encoding: "utf8" });
187
192
  var keyB64;
188
193
  try { keyB64 = opts.vault.unseal(sealedKey); }
189
194
  catch (e) {
@@ -212,7 +217,10 @@ function fileLifecycle(opts) {
212
217
  dbPath = nodePath.join(tmpDir, "blamejs-fl-" + label + "-" +
213
218
  generateToken(TMP_NAME_BYTES) + ".db");
214
219
  if (nodeFs.existsSync(encPath)) {
215
- var packed = nodeFs.readFileSync(encPath);
220
+ // Cap + fd-bound (deployment-tunable ceiling). NO refuseSymlink: the data
221
+ // dir may be a symlink-mounted volume (k8s PVC). db.enc is AEAD-checked
222
+ // downstream, so the cap is the OOM-before-cap defense.
223
+ var packed = atomicFile.fdSafeReadSync(encPath, { maxBytes: (opts.maxDbBytes) || C.BYTES.gib(2) });
216
224
  if (packed.length < 26) { // minimum envelope length
217
225
  throw new DbFileLifecycleError("db-file-lifecycle/short-envelope",
218
226
  "fileLifecycle: " + encPath + " too short to be a valid envelope (" + packed.length + " bytes)");
@@ -248,7 +256,7 @@ function fileLifecycle(opts) {
248
256
  catch (_e) { /* best-effort — operators on read-only handles or pre-init still flush */ }
249
257
  }
250
258
  if (!nodeFs.existsSync(dbPath)) return null;
251
- var plain = nodeFs.readFileSync(dbPath);
259
+ var plain = atomicFile.fdSafeReadSync(dbPath, { maxBytes: (opts.maxDbBytes) || C.BYTES.gib(2) });
252
260
  var packed = encryptPacked(plain, encKey, _aad(opts.dataDir, label));
253
261
  atomicFile.writeSync(encPath, packed);
254
262
  _emitAudit("flushed", "success", { label: label, bytes: plain.length });
@@ -269,7 +277,7 @@ function fileLifecycle(opts) {
269
277
  throw new DbFileLifecycleError("db-file-lifecycle/no-source",
270
278
  "fileLifecycle.snapshot: " + dbPath + " is missing");
271
279
  }
272
- var plain = nodeFs.readFileSync(dbPath);
280
+ var plain = atomicFile.fdSafeReadSync(dbPath, { maxBytes: (opts.maxDbBytes) || C.BYTES.gib(2) });
273
281
  return encryptPacked(plain, encKey, _aad(opts.dataDir, label));
274
282
  }
275
283
 
@@ -1378,12 +1378,62 @@ function _unquoteIdent(s) {
1378
1378
  return s;
1379
1379
  }
1380
1380
 
1381
+ // Strip LEADING SQL comments + whitespace so the ^-anchored write-detection
1382
+ // regexes see the real statement head. Without this, a residency write smuggled
1383
+ // behind a leading "/* x */" or "-- x\n" comment is NOT recognized as a write →
1384
+ // the residency gate is skipped entirely (a cross-border-write BYPASS). The
1385
+ // executed SQL is unchanged; this normalized copy is only for the gate's parse.
1386
+ // Each replace is ^-anchored single-pass; the loop terminates when nothing more
1387
+ // is stripped (an unterminated /* leaves the head intact → write still detected
1388
+ // or fails closed downstream).
1389
+ function _stripLeadingSqlComments(sql) {
1390
+ var s = String(sql), prev;
1391
+ do {
1392
+ prev = s;
1393
+ s = s.replace(/^\s+/, ""); // allow:regex-no-length-cap — anchored, single leading run
1394
+ s = s.replace(/^--[^\n]*\r?\n?/, ""); // allow:regex-no-length-cap — anchored leading line comment
1395
+ s = s.replace(/^\/\*[\s\S]*?\*\//, ""); // allow:regex-no-length-cap — anchored leading block comment (lazy, single scan)
1396
+ } while (s !== prev);
1397
+ return s;
1398
+ }
1399
+
1400
+ // Non-anchored write-target scan for the writable-CTE / EXPLAIN-prefixed case.
1401
+ // A SQLite `WITH c AS (...) INSERT INTO residents ...` / `WITH ... UPDATE residents
1402
+ // SET ...` is a real write, but its effective verb is hidden behind the prefix so
1403
+ // the ^-anchored _RAW_WRITE_KEYWORD_RE misses it. This matches every INSERT/REPLACE
1404
+ // INTO, MERGE INTO, and UPDATE ... SET target token anywhere in the statement and
1405
+ // returns the first that names a residency table — so such a write still ENGAGES
1406
+ // the residency gate (_assertRawWriteResidency then fails CLOSED: the ^-anchored
1407
+ // body parsers can't read a CTE body, so it throws row-residency-raw-unparseable
1408
+ // directing the operator to b.db.from().insertOne/.updateOne). DELETE moves no
1409
+ // residency value across a border, so it is not a residency write. Linear scan.
1410
+ var _CTE_WRITE_TARGET_RE = /(?:\b(?:INSERT|REPLACE)\s+(?:OR\s+[A-Za-z]+\s+)?INTO|\bMERGE\s+INTO)\s+(?:[\x22\x27\x60]?[A-Za-z_]\w*[\x22\x27\x60]?\s*\.\s*){0,3}[\x22\x27\x60]?([A-Za-z_]\w*)[\x22\x27\x60]?|\bUPDATE\s+(?:[\x22\x27\x60]?[A-Za-z_]\w*[\x22\x27\x60]?\s*\.\s*){0,3}[\x22\x27\x60]?([A-Za-z_]\w*)[\x22\x27\x60]?\s+SET\b/ig; // allow:regex-no-length-cap — alternation, no nested quantifiers; linear
1411
+ function _firstResidencyWriteTarget(s) {
1412
+ _CTE_WRITE_TARGET_RE.lastIndex = 0;
1413
+ var m;
1414
+ while ((m = _CTE_WRITE_TARGET_RE.exec(s)) !== null) { // allow:regex-no-length-cap
1415
+ var t = _unquoteIdent(m[1] || m[2]);
1416
+ if (t && (cryptoField.getPerRowResidency(t) || cryptoField.getColumnResidency(t))) return t;
1417
+ }
1418
+ return null;
1419
+ }
1420
+
1381
1421
  function _rawWriteTable(sql) {
1382
- // Both regexes are ^-anchored (leading write keyword + table head): they scan
1383
- // only the statement head, so they are constant-time regardless of SQL length.
1384
- if (typeof sql !== "string" || !_RAW_WRITE_KEYWORD_RE.test(sql)) return null; // allow:regex-no-length-cap
1385
- var m = _RAW_TABLE_RE.exec(sql); // allow:regex-no-length-cap
1386
- return m ? _unquoteIdent(m[1] || m[2]) : null;
1422
+ // The ^-anchored regexes scan only the statement head (constant-time). Strip
1423
+ // leading comments first so a commented-out head can't hide the write.
1424
+ if (typeof sql !== "string") return null;
1425
+ var s = _stripLeadingSqlComments(sql);
1426
+ if (_RAW_WRITE_KEYWORD_RE.test(s)) { // allow:regex-no-length-cap
1427
+ var m = _RAW_TABLE_RE.exec(s); // allow:regex-no-length-cap
1428
+ return m ? _unquoteIdent(m[1] || m[2]) : null;
1429
+ }
1430
+ // Writable-CTE / EXPLAIN-prefixed write: the effective write verb is hidden
1431
+ // behind the prefix the ^-anchored test misses. If it writes a residency table,
1432
+ // return it so the gate engages and then fails closed on the unparseable body.
1433
+ if (/^\s*(?:WITH|EXPLAIN)\b/i.test(s)) { // allow:regex-no-length-cap
1434
+ return _firstResidencyWriteTarget(s);
1435
+ }
1436
+ return null;
1387
1437
  }
1388
1438
 
1389
1439
  // Cheap prepare-time pre-check so only writes to a residency table get wrapped.
@@ -1463,17 +1513,23 @@ function _assertRawWriteResidency(sql, boundParams) {
1463
1513
  if (!cryptoField.getPerRowResidency(table) && !cryptoField.getColumnResidency(table)) return;
1464
1514
  boundParams = _flattenRunParams(boundParams);
1465
1515
 
1516
+ // Parse the comment-stripped head: a leading "/* x */" / "-- x" comment must
1517
+ // not hide the INSERT/UPDATE body from the ^-anchored regexes below (that would
1518
+ // let a residency-restricted write through the gate). The executed SQL is
1519
+ // unchanged; this normalized copy is only for residency parsing.
1520
+ var norm = _stripLeadingSqlComments(sql);
1521
+
1466
1522
  // The INSERT/UPDATE body regexes below scan with [\s\S]+; bound the input
1467
1523
  // first and fail CLOSED on an over-long statement - a residency write the
1468
1524
  // framework cannot safely parse must be refused, never let past the gate.
1469
- if (sql.length > 100000) {
1525
+ if (norm.length > 100000) {
1470
1526
  throw new DbQueryError("db-query/row-residency-raw-unparseable",
1471
1527
  "raw write to residency table '" + table + "' exceeds the parse limit (" +
1472
- sql.length + " chars) - use b.db.from(\"" + table + "\") so residency is validated", true);
1528
+ norm.length + " chars) - use b.db.from(\"" + table + "\") so residency is validated", true);
1473
1529
  }
1474
1530
 
1475
- var mi = _RAW_INSERT_RE.exec(sql); // allow:regex-no-length-cap — input length-capped above
1476
- var mu = mi ? null : _RAW_UPDATE_RE.exec(sql); // allow:regex-no-length-cap — input length-capped above
1531
+ var mi = _RAW_INSERT_RE.exec(norm); // allow:regex-no-length-cap — input length-capped above
1532
+ var mu = mi ? null : _RAW_UPDATE_RE.exec(norm); // allow:regex-no-length-cap — input length-capped above
1477
1533
  if (!mi && !mu) {
1478
1534
  throw new DbQueryError("db-query/row-residency-raw-unparseable",
1479
1535
  "raw write to residency table '" + table + "' cannot be parsed to validate its " +
@@ -1509,4 +1565,8 @@ module.exports = {
1509
1565
  Query: Query,
1510
1566
  _isRawWriteToResidencyTable: _isRawWriteToResidencyTable,
1511
1567
  _assertRawWriteResidency: _assertRawWriteResidency,
1568
+ // Shared leading-comment stripper so db.js's storage-low write-gate sees the
1569
+ // real statement head (a `/* x */ INSERT` / WITH-prefixed write must not slip
1570
+ // the ENOSPC gate the way it slipped the residency gate).
1571
+ _stripLeadingSqlComments: _stripLeadingSqlComments,
1512
1572
  };