@blamejs/blamejs-shop 0.4.68 → 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 (298) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/admin.js +8 -6
  3. package/lib/asset-manifest.json +1 -1
  4. package/lib/giftcards.js +29 -5
  5. package/lib/security-middleware.js +65 -23
  6. package/lib/storefront.js +10 -7
  7. package/lib/vendor/MANIFEST.json +319 -267
  8. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  9. package/lib/vendor/blamejs/api-snapshot.json +58 -5
  10. package/lib/vendor/blamejs/examples/wiki/README.md +1 -1
  11. package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +9 -8
  12. package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +10 -9
  13. package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +4 -3
  14. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +33 -17
  15. package/lib/vendor/blamejs/examples/wiki/routes/admin.js +7 -10
  16. package/lib/vendor/blamejs/examples/wiki/server.js +5 -4
  17. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +5 -0
  18. package/lib/vendor/blamejs/lib/a2a-tasks.js +38 -6
  19. package/lib/vendor/blamejs/lib/agent-event-bus.js +13 -0
  20. package/lib/vendor/blamejs/lib/agent-idempotency.js +5 -1
  21. package/lib/vendor/blamejs/lib/agent-snapshot.js +32 -2
  22. package/lib/vendor/blamejs/lib/ai-aedt-bias-audit.js +2 -1
  23. package/lib/vendor/blamejs/lib/ai-content-detect.js +1 -3
  24. package/lib/vendor/blamejs/lib/ai-frontier-protocol.js +1 -1
  25. package/lib/vendor/blamejs/lib/ai-model-manifest.js +1 -1
  26. package/lib/vendor/blamejs/lib/ai-output.js +16 -7
  27. package/lib/vendor/blamejs/lib/api-snapshot.js +4 -1
  28. package/lib/vendor/blamejs/lib/app-shutdown.js +7 -1
  29. package/lib/vendor/blamejs/lib/archive-gz.js +9 -0
  30. package/lib/vendor/blamejs/lib/archive-read.js +9 -7
  31. package/lib/vendor/blamejs/lib/archive-tar-read.js +51 -8
  32. package/lib/vendor/blamejs/lib/archive.js +4 -2
  33. package/lib/vendor/blamejs/lib/asn1-der.js +70 -22
  34. package/lib/vendor/blamejs/lib/atomic-file.js +204 -2
  35. package/lib/vendor/blamejs/lib/audit-chain.js +54 -5
  36. package/lib/vendor/blamejs/lib/audit-daily-review.js +12 -2
  37. package/lib/vendor/blamejs/lib/audit-sign.js +2 -1
  38. package/lib/vendor/blamejs/lib/audit-tools.js +108 -23
  39. package/lib/vendor/blamejs/lib/audit.js +7 -2
  40. package/lib/vendor/blamejs/lib/auth/access-lock.js +2 -2
  41. package/lib/vendor/blamejs/lib/auth/bot-challenge.js +1 -1
  42. package/lib/vendor/blamejs/lib/auth/ciba.js +43 -4
  43. package/lib/vendor/blamejs/lib/auth/dpop.js +6 -1
  44. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +5 -1
  45. package/lib/vendor/blamejs/lib/auth/jwt.js +2 -2
  46. package/lib/vendor/blamejs/lib/auth/lockout.js +18 -2
  47. package/lib/vendor/blamejs/lib/auth/passkey.js +1 -1
  48. package/lib/vendor/blamejs/lib/auth/password.js +1 -1
  49. package/lib/vendor/blamejs/lib/auth/saml.js +33 -13
  50. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +24 -4
  51. package/lib/vendor/blamejs/lib/auth/status-list.js +14 -2
  52. package/lib/vendor/blamejs/lib/auth/step-up.js +9 -1
  53. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +21 -2
  54. package/lib/vendor/blamejs/lib/backup/bundle.js +7 -2
  55. package/lib/vendor/blamejs/lib/backup/crypto.js +23 -8
  56. package/lib/vendor/blamejs/lib/backup/index.js +41 -20
  57. package/lib/vendor/blamejs/lib/backup/manifest.js +7 -1
  58. package/lib/vendor/blamejs/lib/break-glass.js +41 -22
  59. package/lib/vendor/blamejs/lib/cbor.js +34 -11
  60. package/lib/vendor/blamejs/lib/cdn-cache-control.js +7 -3
  61. package/lib/vendor/blamejs/lib/cert.js +5 -3
  62. package/lib/vendor/blamejs/lib/cli.js +5 -1
  63. package/lib/vendor/blamejs/lib/cloud-events.js +3 -2
  64. package/lib/vendor/blamejs/lib/cluster-storage.js +7 -3
  65. package/lib/vendor/blamejs/lib/codepoint-class.js +17 -0
  66. package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -1
  67. package/lib/vendor/blamejs/lib/compliance-sanctions.js +9 -7
  68. package/lib/vendor/blamejs/lib/compliance.js +1 -1
  69. package/lib/vendor/blamejs/lib/config-drift.js +22 -8
  70. package/lib/vendor/blamejs/lib/content-credentials.js +11 -8
  71. package/lib/vendor/blamejs/lib/content-digest.js +11 -4
  72. package/lib/vendor/blamejs/lib/cookies.js +10 -2
  73. package/lib/vendor/blamejs/lib/cose.js +20 -0
  74. package/lib/vendor/blamejs/lib/crdt.js +2 -1
  75. package/lib/vendor/blamejs/lib/crypto-field.js +29 -23
  76. package/lib/vendor/blamejs/lib/crypto.js +18 -4
  77. package/lib/vendor/blamejs/lib/csp.js +4 -0
  78. package/lib/vendor/blamejs/lib/daemon.js +4 -1
  79. package/lib/vendor/blamejs/lib/data-act.js +27 -4
  80. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +14 -6
  81. package/lib/vendor/blamejs/lib/db-query.js +69 -9
  82. package/lib/vendor/blamejs/lib/db.js +32 -15
  83. package/lib/vendor/blamejs/lib/dora.js +43 -13
  84. package/lib/vendor/blamejs/lib/dr-runbook.js +1 -1
  85. package/lib/vendor/blamejs/lib/dsa.js +2 -1
  86. package/lib/vendor/blamejs/lib/dsr.js +22 -8
  87. package/lib/vendor/blamejs/lib/early-hints.js +19 -0
  88. package/lib/vendor/blamejs/lib/eat.js +5 -1
  89. package/lib/vendor/blamejs/lib/external-db.js +60 -4
  90. package/lib/vendor/blamejs/lib/fda-21cfr11.js +30 -5
  91. package/lib/vendor/blamejs/lib/flag-providers.js +6 -2
  92. package/lib/vendor/blamejs/lib/forms.js +1 -1
  93. package/lib/vendor/blamejs/lib/gate-contract.js +46 -5
  94. package/lib/vendor/blamejs/lib/gdpr-ropa.js +18 -9
  95. package/lib/vendor/blamejs/lib/graphql-federation.js +17 -4
  96. package/lib/vendor/blamejs/lib/guard-all.js +2 -2
  97. package/lib/vendor/blamejs/lib/guard-dsn.js +1 -1
  98. package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
  99. package/lib/vendor/blamejs/lib/guard-html.js +9 -11
  100. package/lib/vendor/blamejs/lib/guard-imap-command.js +1 -1
  101. package/lib/vendor/blamejs/lib/guard-jmap.js +1 -1
  102. package/lib/vendor/blamejs/lib/guard-json.js +14 -6
  103. package/lib/vendor/blamejs/lib/guard-mail-move.js +1 -1
  104. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +1 -1
  105. package/lib/vendor/blamejs/lib/guard-pop3-command.js +1 -1
  106. package/lib/vendor/blamejs/lib/guard-smtp-command.js +1 -1
  107. package/lib/vendor/blamejs/lib/guard-svg.js +8 -9
  108. package/lib/vendor/blamejs/lib/html-balance.js +7 -3
  109. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +33 -12
  110. package/lib/vendor/blamejs/lib/http-client.js +225 -53
  111. package/lib/vendor/blamejs/lib/iab-tcf.js +3 -2
  112. package/lib/vendor/blamejs/lib/importmap-integrity.js +41 -1
  113. package/lib/vendor/blamejs/lib/incident-report.js +9 -6
  114. package/lib/vendor/blamejs/lib/json-patch.js +1 -1
  115. package/lib/vendor/blamejs/lib/json-path.js +24 -3
  116. package/lib/vendor/blamejs/lib/jtd.js +2 -2
  117. package/lib/vendor/blamejs/lib/legal-hold.js +24 -8
  118. package/lib/vendor/blamejs/lib/log.js +2 -2
  119. package/lib/vendor/blamejs/lib/mail-agent.js +2 -2
  120. package/lib/vendor/blamejs/lib/mail-arf.js +1 -1
  121. package/lib/vendor/blamejs/lib/mail-auth.js +3 -3
  122. package/lib/vendor/blamejs/lib/mail-bimi.js +16 -16
  123. package/lib/vendor/blamejs/lib/mail-bounce.js +3 -3
  124. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +71 -6
  125. package/lib/vendor/blamejs/lib/mail-deploy.js +9 -5
  126. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -4
  127. package/lib/vendor/blamejs/lib/mail-helo.js +2 -4
  128. package/lib/vendor/blamejs/lib/mail-journal.js +11 -8
  129. package/lib/vendor/blamejs/lib/mail-mdn.js +8 -4
  130. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -4
  131. package/lib/vendor/blamejs/lib/mail-scan.js +3 -5
  132. package/lib/vendor/blamejs/lib/mail-server-jmap.js +4 -1
  133. package/lib/vendor/blamejs/lib/mail-server-registry.js +1 -1
  134. package/lib/vendor/blamejs/lib/mail-server-tls.js +9 -2
  135. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -4
  136. package/lib/vendor/blamejs/lib/mail-store-fts.js +1 -1
  137. package/lib/vendor/blamejs/lib/mail.js +22 -2
  138. package/lib/vendor/blamejs/lib/markup-tokenizer.js +24 -0
  139. package/lib/vendor/blamejs/lib/mcp.js +6 -4
  140. package/lib/vendor/blamejs/lib/mdoc.js +26 -3
  141. package/lib/vendor/blamejs/lib/metrics.js +14 -3
  142. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +2 -2
  143. package/lib/vendor/blamejs/lib/middleware/body-parser.js +10 -4
  144. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +26 -18
  145. package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +5 -1
  146. package/lib/vendor/blamejs/lib/middleware/compression.js +9 -0
  147. package/lib/vendor/blamejs/lib/middleware/cors.js +32 -23
  148. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +60 -21
  149. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -4
  150. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +28 -4
  151. package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +61 -30
  152. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +25 -16
  153. package/lib/vendor/blamejs/lib/middleware/scim-server.js +2 -1
  154. package/lib/vendor/blamejs/lib/middleware/security-headers.js +24 -6
  155. package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +6 -3
  156. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +2 -2
  157. package/lib/vendor/blamejs/lib/money.js +1 -1
  158. package/lib/vendor/blamejs/lib/mtls-ca.js +10 -6
  159. package/lib/vendor/blamejs/lib/network-dns-resolver.js +1 -1
  160. package/lib/vendor/blamejs/lib/network-dns.js +9 -2
  161. package/lib/vendor/blamejs/lib/network-dnssec.js +2 -1
  162. package/lib/vendor/blamejs/lib/network-smtp-policy.js +23 -5
  163. package/lib/vendor/blamejs/lib/network-tls.js +27 -5
  164. package/lib/vendor/blamejs/lib/network-tsig.js +2 -2
  165. package/lib/vendor/blamejs/lib/nis2-report.js +1 -1
  166. package/lib/vendor/blamejs/lib/nist-crosswalk.js +1 -1
  167. package/lib/vendor/blamejs/lib/ntp-check.js +28 -0
  168. package/lib/vendor/blamejs/lib/numeric-bounds.js +9 -0
  169. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +1 -2
  170. package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +4 -2
  171. package/lib/vendor/blamejs/lib/object-store/gcs.js +6 -4
  172. package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -2
  173. package/lib/vendor/blamejs/lib/object-store/http-request.js +30 -1
  174. package/lib/vendor/blamejs/lib/object-store/local.js +37 -17
  175. package/lib/vendor/blamejs/lib/object-store/sigv4.js +1 -2
  176. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +20 -4
  177. package/lib/vendor/blamejs/lib/outbox.js +11 -4
  178. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +1 -1
  179. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +21 -3
  180. package/lib/vendor/blamejs/lib/queue-local.js +10 -3
  181. package/lib/vendor/blamejs/lib/redact.js +7 -3
  182. package/lib/vendor/blamejs/lib/request-helpers.js +201 -23
  183. package/lib/vendor/blamejs/lib/resource-access-lock.js +3 -3
  184. package/lib/vendor/blamejs/lib/restore-bundle.js +46 -18
  185. package/lib/vendor/blamejs/lib/restore-rollback.js +10 -4
  186. package/lib/vendor/blamejs/lib/restore.js +19 -0
  187. package/lib/vendor/blamejs/lib/retention.js +20 -4
  188. package/lib/vendor/blamejs/lib/router.js +17 -4
  189. package/lib/vendor/blamejs/lib/safe-ical.js +2 -2
  190. package/lib/vendor/blamejs/lib/safe-icap.js +1 -1
  191. package/lib/vendor/blamejs/lib/safe-json.js +44 -0
  192. package/lib/vendor/blamejs/lib/safe-sieve.js +1 -1
  193. package/lib/vendor/blamejs/lib/safe-vcard.js +1 -1
  194. package/lib/vendor/blamejs/lib/sandbox-worker.js +6 -0
  195. package/lib/vendor/blamejs/lib/sandbox.js +1 -1
  196. package/lib/vendor/blamejs/lib/scheduler.js +17 -1
  197. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +16 -0
  198. package/lib/vendor/blamejs/lib/session.js +27 -3
  199. package/lib/vendor/blamejs/lib/sql.js +3 -3
  200. package/lib/vendor/blamejs/lib/static.js +65 -13
  201. package/lib/vendor/blamejs/lib/template.js +7 -5
  202. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -19
  203. package/lib/vendor/blamejs/lib/tsa.js +5 -2
  204. package/lib/vendor/blamejs/lib/vault/index.js +5 -0
  205. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +22 -26
  206. package/lib/vendor/blamejs/lib/vault/passphrase-source.js +8 -3
  207. package/lib/vendor/blamejs/lib/vault/rotate.js +13 -18
  208. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +4 -1
  209. package/lib/vendor/blamejs/lib/vc.js +1 -1
  210. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +10 -10
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +23 -10
  212. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5498 -5494
  213. package/lib/vendor/blamejs/lib/webhook.js +16 -1
  214. package/lib/vendor/blamejs/lib/websocket.js +1 -1
  215. package/lib/vendor/blamejs/lib/worm.js +1 -1
  216. package/lib/vendor/blamejs/lib/ws-client.js +57 -46
  217. package/lib/vendor/blamejs/lib/x509-chain.js +44 -0
  218. package/lib/vendor/blamejs/package.json +1 -1
  219. package/lib/vendor/blamejs/release-notes/v0.15.14.json +122 -0
  220. package/lib/vendor/blamejs/scripts/check-vendor-currency.js +119 -4
  221. package/lib/vendor/blamejs/test/00-primitives.js +5 -1
  222. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +18 -4
  223. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +42 -0
  224. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +36 -0
  225. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  226. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +47 -0
  227. package/lib/vendor/blamejs/test/layer-0-primitives/archive-gz.test.js +24 -0
  228. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-hardening.test.js +160 -0
  229. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +45 -0
  230. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +30 -0
  231. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-open-nofollow.test.js +79 -0
  232. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-excl.test.js +132 -0
  233. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-stream.test.js +181 -0
  234. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-corrupted-anchor.test.js +65 -0
  235. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-incremental-verify.test.js +83 -0
  236. package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +48 -1
  237. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +13 -3
  238. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +122 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +37 -0
  240. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +5 -3
  241. package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +21 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +73 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +17 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +62 -3
  245. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +12 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-storage.test.js +40 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +146 -5
  248. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +14 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/compression-range.test.js +115 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +17 -5
  251. package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +27 -5
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +83 -0
  253. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +58 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +30 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +74 -0
  256. package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +20 -6
  257. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-alg-kty.test.js +64 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +32 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +43 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +30 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +33 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +34 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +12 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +72 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-throttle-transform.test.js +88 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +25 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +28 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +20 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/mail-header-injection.test.js +58 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +63 -9
  271. package/lib/vendor/blamejs/test/layer-0-primitives/mdoc.test.js +41 -14
  272. package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +61 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/object-store-range-header.test.js +51 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +35 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/output-header-hardening.test.js +102 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/parser-verify-hardening.test.js +191 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/proto-shadow-allowlist.test.js +120 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +75 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +128 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/restore-blob-remap.test.js +128 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/retention-sweep-termination.test.js +104 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/router-body-validation.test.js +98 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json-stringify-for-script.test.js +43 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +48 -5
  285. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +23 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +54 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +24 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +42 -1
  289. package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +7 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/template-escape-html.test.js +43 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +15 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/vault-default-store.test.js +48 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/vendor-currency-classify.test.js +77 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +50 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +22 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/x509-chain-ca-enforcement.test.js +149 -0
  297. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +34 -0
  298. package/package.json +1 -1
@@ -117,7 +117,7 @@ function _normalizeLevel(level) {
117
117
  return level;
118
118
  }
119
119
  if (typeof level === "string") {
120
- if (LEVELS[level] === undefined) {
120
+ if (!Object.prototype.hasOwnProperty.call(LEVELS, level)) {
121
121
  throw new LogError("log/bad-level",
122
122
  "level must be one of " + LEVEL_NAMES.join(", "));
123
123
  }
@@ -587,7 +587,7 @@ function _escapeC0Controls(s) {
587
587
  function _bootMinLevel() {
588
588
  // allow:raw-process-env — see header comment above
589
589
  var raw = process.env.BLAMEJS_BOOT_LOG_LEVEL || process.env.LOG_LEVEL || "info";
590
- return LEVELS[raw] != null ? LEVELS[raw] : LEVELS.info;
590
+ return Object.prototype.hasOwnProperty.call(LEVELS, raw) ? LEVELS[raw] : LEVELS.info;
591
591
  }
592
592
 
593
593
  /**
@@ -353,7 +353,7 @@ async function _dispatchOrLocal(ctx, method, args, localFn) {
353
353
  var mode = ctx.dispatch.mode;
354
354
  if (mode === "local") return localFn(ctx, args);
355
355
  if (mode === "auto") {
356
- if (HEAVY_METHODS[method] && ctx.dispatch.queue) return _enqueueMethod(ctx, method, args);
356
+ if (Object.prototype.hasOwnProperty.call(HEAVY_METHODS, method) && ctx.dispatch.queue) return _enqueueMethod(ctx, method, args);
357
357
  return localFn(ctx, args);
358
358
  }
359
359
  // mode === "queue" — explicit queue dispatch.
@@ -362,7 +362,7 @@ async function _dispatchOrLocal(ctx, method, args, localFn) {
362
362
  "agent." + method + ": dispatch.mode='queue' requires opts.dispatch.queue");
363
363
  }
364
364
  // Sync-result methods refuse until orchestrator's result-bus lands.
365
- if (!HEAVY_METHODS[method]) {
365
+ if (!Object.prototype.hasOwnProperty.call(HEAVY_METHODS, method)) {
366
366
  throw new MailAgentError("mail-agent/queue-result-bus-deferred",
367
367
  "agent." + method + ": queue mode for sync-result methods wires at v0.9.21 " +
368
368
  "(b.agent.orchestrator). Use mode='local' or mode='auto' until then.");
@@ -274,7 +274,7 @@ function parse(rawMessage, opts) {
274
274
  // Surface non-normalized fields under extraFields for operator
275
275
  // visibility (X-* tags ESPs add for routing diagnostics, etc.).
276
276
  Object.keys(fieldMap).forEach(function (k) {
277
- if (!KNOWN_FIELDS[k]) extraFields[k] = fieldMap[k];
277
+ if (!Object.prototype.hasOwnProperty.call(KNOWN_FIELDS, k)) extraFields[k] = fieldMap[k];
278
278
  });
279
279
 
280
280
  var event = {
@@ -1122,7 +1122,7 @@ function _parseDmarcRecord(text) {
1122
1122
  else if (key === "aspf") policy.aspf = val.toLowerCase();
1123
1123
  else if (key === "np") {
1124
1124
  var npVal = val.toLowerCase();
1125
- if (!DMARCBIS_VALID_NP[npVal]) {
1125
+ if (!Object.prototype.hasOwnProperty.call(DMARCBIS_VALID_NP, npVal)) {
1126
1126
  throw new MailAuthError("mail-auth/dmarcbis-bad-tag",
1127
1127
  "DMARC np= must be one of none|quarantine|reject, got " + JSON.stringify(val));
1128
1128
  }
@@ -1130,7 +1130,7 @@ function _parseDmarcRecord(text) {
1130
1130
  }
1131
1131
  else if (key === "psd") {
1132
1132
  var psdVal = val.toLowerCase();
1133
- if (!DMARCBIS_VALID_PSD[psdVal]) {
1133
+ if (!Object.prototype.hasOwnProperty.call(DMARCBIS_VALID_PSD, psdVal)) {
1134
1134
  throw new MailAuthError("mail-auth/dmarcbis-bad-tag",
1135
1135
  "DMARC psd= must be one of y|n|u, got " + JSON.stringify(val));
1136
1136
  }
@@ -2017,7 +2017,7 @@ function authResultsEmit(opts) {
2017
2017
  }
2018
2018
  var method = String(r.method || "").toLowerCase();
2019
2019
  var result = String(r.result || "").toLowerCase();
2020
- if (!AR_VALID_METHODS[method]) {
2020
+ if (!Object.prototype.hasOwnProperty.call(AR_VALID_METHODS, method)) {
2021
2021
  throw new MailAuthError("mail-auth/ar-bad-method",
2022
2022
  "authResults.emit: unknown method '" + r.method + "'");
2023
2023
  }
@@ -57,6 +57,7 @@ var lazyRequire = require("./lazy-require");
57
57
  var networkDnsResolver = lazyRequire(function () { return require("./network-dns-resolver"); });
58
58
  var safeBuffer = require("./safe-buffer");
59
59
  var markupTokenizer = require("./markup-tokenizer");
60
+ var x509Chain = require("./x509-chain");
60
61
  var structuredFields = require("./structured-fields");
61
62
  var safeUrl = require("./safe-url");
62
63
  var validateOpts = require("./validate-opts");
@@ -399,7 +400,7 @@ function validateTinyPsSvg(svgBytes) {
399
400
  }
400
401
  // Any element name starting with "animate" is animation (covers
401
402
  // future SMIL extensions not in the static list above).
402
- if (name.indexOf("animate") === 0 && !TINY_PS_FORBIDDEN_TAGS[name]) {
403
+ if (name.indexOf("animate") === 0 && !Object.prototype.hasOwnProperty.call(TINY_PS_FORBIDDEN_TAGS, name)) {
403
404
  _vio("element-forbidden",
404
405
  "<" + name + "> animation element is forbidden in Tiny-PS");
405
406
  }
@@ -492,10 +493,14 @@ function _tokenizeTinyPsSvg(s) {
492
493
  if (lt > pos) tokens.push({ type: "text", raw: s.slice(pos, lt) });
493
494
 
494
495
  if (s.startsWith("<!--", lt)) {
495
- var endC = s.indexOf("-->", lt + 4);
496
+ // WHATWG comment end ("--!>" + abrupt "<!-->" / "<!--->"), matching a
497
+ // browser parsing inline SVG — so an element smuggled past an early
498
+ // terminator can't slip the Tiny-PS validation (mXSS differential).
499
+ // Fails closed on an unterminated comment.
500
+ var endC = markupTokenizer.htmlCommentEnd(s, lt);
496
501
  if (endC === -1) throw new Error("unterminated comment"); // allow:bare-error-throw — caught by outer try/catch and re-thrown as MailBimiError("bimi/svg-tiny-ps-violation")
497
- tokens.push({ type: "comment", raw: s.slice(lt, endC + 3) });
498
- pos = endC + 3;
502
+ tokens.push({ type: "comment", raw: s.slice(lt, endC) });
503
+ pos = endC;
499
504
  continue;
500
505
  }
501
506
  if (s.startsWith("<![CDATA[", lt)) {
@@ -823,11 +828,10 @@ function _verifyCertChain(leaf, intermediates, anchors) {
823
828
 
824
829
  for (var ai = 0; ai < anchors.length; ai += 1) {
825
830
  var anchor = anchors[ai];
826
- if (current.checkIssued(anchor)) {
827
- try {
828
- if (current.verify(anchor.publicKey)) return { ok: true };
829
- } catch (_e) { /* fall through to next anchor */ }
830
- }
831
+ // issuerValidlyIssued enforces basicConstraints cA:TRUE on the anchor
832
+ // in addition to the issuance + signature checks, so a non-CA cert
833
+ // cannot mint a VMC (basicConstraints bypass, CVE-2002-0862 class).
834
+ if (x509Chain.issuerValidlyIssued(anchor, current)) return { ok: true };
831
835
  }
832
836
  if (current.checkIssued(current)) {
833
837
  return { ok: false, reason: "self-signed root not in trust-anchor bundle" };
@@ -837,13 +841,9 @@ function _verifyCertChain(leaf, intermediates, anchors) {
837
841
  for (var ii = 0; ii < intermediates.length; ii += 1) {
838
842
  var cand = intermediates[ii];
839
843
  if (cand === current) continue;
840
- if (current.checkIssued(cand)) {
841
- try {
842
- if (current.verify(cand.publicKey)) {
843
- nextIssuer = cand;
844
- break;
845
- }
846
- } catch (_e) { /* fall through */ }
844
+ if (x509Chain.issuerValidlyIssued(cand, current)) {
845
+ nextIssuer = cand;
846
+ break;
847
847
  }
848
848
  }
849
849
  if (nextIssuer === null) {
@@ -448,7 +448,7 @@ function handler(opts) {
448
448
  opts = opts || {};
449
449
  var vendor = opts.vendor;
450
450
  var customParser = typeof opts.parser === "function" ? opts.parser : null;
451
- if (!customParser && (typeof vendor !== "string" || !VENDORS[vendor])) {
451
+ if (!customParser && (typeof vendor !== "string" || !Object.prototype.hasOwnProperty.call(VENDORS, vendor))) {
452
452
  throw _err("handler/bad-config",
453
453
  "mailBounce.handler requires { vendor } (one of " +
454
454
  Object.keys(VENDORS).join(", ") + ") or { parser }");
@@ -761,7 +761,7 @@ function _parseDsn(rawMessage) {
761
761
  throw _err("bounce/dsn-malformed",
762
762
  "mailBounce.dsn.parse: per-recipient group missing Final-Recipient");
763
763
  }
764
- if (action && !DSN_ACTIONS[action]) {
764
+ if (action && !Object.prototype.hasOwnProperty.call(DSN_ACTIONS, action)) {
765
765
  throw _err("bounce/dsn-malformed",
766
766
  "mailBounce.dsn.parse: Action token '" + action + "' is not RFC 3464 §2.3.3");
767
767
  }
@@ -825,7 +825,7 @@ function _buildDsn(opts) {
825
825
  validateOpts.requireNonEmptyString(opts.finalRecipient,
826
826
  "mailBounce.dsn.build: opts.finalRecipient", MailBounceError, "bounce/dsn-malformed");
827
827
  var action = String(opts.action || "failed").toLowerCase();
828
- if (!DSN_ACTIONS[action]) {
828
+ if (!Object.prototype.hasOwnProperty.call(DSN_ACTIONS, action)) {
829
829
  throw _err("bounce/dsn-malformed",
830
830
  "mailBounce.dsn.build: opts.action must be one of " +
831
831
  Object.keys(DSN_ACTIONS).join(" / ") + "; got '" + action + "'");
@@ -98,6 +98,7 @@ var lazyRequire = require("./lazy-require");
98
98
  var audit = lazyRequire(function () { return require("./audit"); });
99
99
  var nodeCrypto = require("node:crypto");
100
100
  var validateOpts = require("./validate-opts");
101
+ var x509Chain = require("./x509-chain");
101
102
  var cms = require("./cms-codec");
102
103
  var asn1 = require("./asn1-der");
103
104
  var pqcSoftware = require("./pqc-software");
@@ -297,7 +298,8 @@ function verify(opts) {
297
298
  // verification failure (bad alg, missing signed-attrs, message-
298
299
  // digest mismatch, signature mismatch); reaching the next line
299
300
  // means the per-signer verify succeeded.
300
- var siResult = _verifySignerInfo(sd.signerInfos[0], msgBytes, opts.signerPublicKey, opts.audit);
301
+ var siResult = _verifySignerInfo(sd.signerInfos[0], msgBytes, opts.signerPublicKey, opts.audit,
302
+ sd.encapContent && sd.encapContent.eContentType);
301
303
  // Trust-anchor chain validation when operator supplies roots. The
302
304
  // signer cert is in sd.certificates (its serialNumber matches the
303
305
  // sid's serialNumber); intermediate certs are also in
@@ -336,7 +338,7 @@ function verify(opts) {
336
338
  // signer's signature, masking real multi-signer envelopes as a single
337
339
  // false-failure). verifyAll now iterates `sd.signerInfos` directly and
338
340
  // calls this helper per index with the matching per-signer key.
339
- function _verifySignerInfo(si, msgBytes, signerPublicKey, auditHandle) {
341
+ function _verifySignerInfo(si, msgBytes, signerPublicKey, auditHandle, eContentType) {
340
342
  var sigAlg = _oidToSigAlg(si.sigAlgOid);
341
343
  if (!sigAlg) {
342
344
  throw new MailCryptoError("mail-crypto/smime/bad-sig-alg",
@@ -365,6 +367,26 @@ function _verifySignerInfo(si, msgBytes, signerPublicKey, auditHandle) {
365
367
  "smime.verify: recomputed message digest does not match signedAttrs.messageDigest " +
366
368
  "(message was tampered or signed-attrs were swapped)");
367
369
  }
370
+ // RFC 5652 §11.1: when signedAttrs are present the contentType attribute
371
+ // MUST be present and MUST equal the SignedData eContentType. The TSA
372
+ // sibling enforces this; S/MIME omitted it, so a SignerInfo with a missing
373
+ // or mismatched contentType still verified — a cross-protocol content-type
374
+ // binding gap. The check runs over signedAttrs, which the signature below
375
+ // covers, so a tampered attribute also fails the signature.
376
+ if (eContentType) {
377
+ var ctOid = _extractContentTypeOid(si.signedAttrsRaw);
378
+ if (!ctOid) {
379
+ _audit(auditHandle, "mail.crypto.smime.verify_fail", "denied", { reason: "no-content-type-attr" });
380
+ throw new MailCryptoError("mail-crypto/smime/no-content-type-attr",
381
+ "smime.verify: signedAttrs missing the contentType attribute (RFC 5652 §11.1)");
382
+ }
383
+ if (ctOid !== eContentType) {
384
+ _audit(auditHandle, "mail.crypto.smime.verify_fail", "denied", { reason: "content-type-mismatch" });
385
+ throw new MailCryptoError("mail-crypto/smime/content-type-mismatch",
386
+ "smime.verify: signedAttrs.contentType (" + ctOid + ") does not match eContentType (" +
387
+ eContentType + ")");
388
+ }
389
+ }
368
390
  var ok;
369
391
  try {
370
392
  ok = sigAlg.pqc.verify(
@@ -471,7 +493,10 @@ function _verifyTrustChain(sd, trustAnchorCertsPem, signerPublicKey, auditHandle
471
493
  // Stop when we've reached a trust anchor.
472
494
  for (var ri = 0; ri < roots.length; ri += 1) {
473
495
  var r = roots[ri];
474
- if (current.issuer === r.subject) {
496
+ // Enforce basicConstraints cA:TRUE on the issuing root in addition to
497
+ // the DN match + signature — a non-CA cert can never be a chain issuer
498
+ // (basicConstraints bypass, CVE-2002-0862 class).
499
+ if (current.issuer === r.subject && x509Chain.isCaCert(r)) {
475
500
  try {
476
501
  if (current.verify(r.publicKey)) {
477
502
  void auditHandle;
@@ -480,12 +505,12 @@ function _verifyTrustChain(sd, trustAnchorCertsPem, signerPublicKey, auditHandle
480
505
  } catch (_e) { /* fall through to next root */ }
481
506
  }
482
507
  }
483
- // Find an intermediate whose subject == current.issuer.
508
+ // Find an intermediate whose subject == current.issuer (and that is a CA).
484
509
  var found = null;
485
510
  for (var hi = 0; hi < chain.length; hi += 1) {
486
511
  var h = chain[hi];
487
512
  if (h === current) continue;
488
- if (h.subject === current.issuer) {
513
+ if (h.subject === current.issuer && x509Chain.isCaCert(h)) {
489
514
  try {
490
515
  if (current.verify(h.publicKey)) { found = h; break; }
491
516
  } catch (_e) { /* try next */ }
@@ -574,7 +599,8 @@ function verifyAll(opts) {
574
599
  throw new MailCryptoError("mail-crypto/smime/missing-key",
575
600
  "verifyAll: no public key supplied for SignerInfo serial " + serialHex);
576
601
  }
577
- var siRes = _verifySignerInfo(si, msgBytes, pub, opts.audit);
602
+ var siRes = _verifySignerInfo(si, msgBytes, pub, opts.audit,
603
+ sd.encapContent && sd.encapContent.eContentType);
578
604
  results.push({
579
605
  serialHex: serialHex,
580
606
  sigAlgOid: si.sigAlgOid,
@@ -621,6 +647,42 @@ function _extractSerialHex(sidBytes) {
621
647
 
622
648
  // RFC 5652 §11.2 messageDigest OID.
623
649
  var OID_MESSAGE_DIGEST = "1.2.840.113549.1.9.4";
650
+ // RFC 5652 §11.1 contentType signed-attribute OID.
651
+ var OID_CONTENT_TYPE_ATTR = "1.2.840.113549.1.9.3";
652
+
653
+ // Extract the contentType signed-attribute's OID value from a signedAttrs
654
+ // SET, or null if absent / malformed. Mirrors _extractMessageDigest's walk
655
+ // but the attribute value is an OID (the eContentType), not an OCTET STRING.
656
+ function _extractContentTypeOid(signedAttrsRaw) {
657
+ var node;
658
+ try { node = asn1.readNode(signedAttrsRaw); }
659
+ catch (_e) { return null; }
660
+ if (node.tag !== asn1.TAG.SET) return null;
661
+ var attrs;
662
+ try { attrs = asn1.readSequence(node.value); }
663
+ catch (_e) { return null; }
664
+ for (var i = 0; i < attrs.length; i += 1) {
665
+ var attr = attrs[i];
666
+ if (attr.tag !== asn1.TAG.SEQUENCE) continue;
667
+ var children;
668
+ try { children = asn1.readSequence(attr.value); }
669
+ catch (_e) { continue; }
670
+ if (children.length < 2) continue;
671
+ var oid;
672
+ try { oid = asn1.readOid(children[0]); }
673
+ catch (_e) { continue; }
674
+ if (oid !== OID_CONTENT_TYPE_ATTR) continue;
675
+ var valuesSet = children[1];
676
+ if (valuesSet.tag !== asn1.TAG.SET) continue;
677
+ var valueChildren;
678
+ try { valueChildren = asn1.readSequence(valuesSet.value); }
679
+ catch (_e) { continue; }
680
+ if (valueChildren.length === 0) continue;
681
+ try { return asn1.readOid(valueChildren[0]); }
682
+ catch (_e) { return null; }
683
+ }
684
+ return null;
685
+ }
624
686
 
625
687
  function _extractMessageDigest(signedAttrsRaw) {
626
688
  // signedAttrsRaw is `31 LL VV...` — the universal SET-tagged blob
@@ -821,4 +883,7 @@ module.exports = {
821
883
  // validation (a cert matches the verified signer key iff its SPKI public
822
884
  // key equals, or has as a suffix, the raw signer key bytes).
823
885
  _certKeyMatches: _certKeyMatches,
886
+ // Exposed for tests — RFC 5652 §11.1 contentType signed-attr extraction
887
+ // (verify binds it to the eContentType).
888
+ _extractContentTypeOid: _extractContentTypeOid,
824
889
  };
@@ -123,7 +123,7 @@ function mtaStsPublish(opts) {
123
123
  throw new MailDeployError("mail-deploy/bad-domain",
124
124
  "mtaStsPublish: opts.domain must be a valid hostname");
125
125
  }
126
- if (!STS_MODES[opts.mode]) {
126
+ if (!Object.prototype.hasOwnProperty.call(STS_MODES, opts.mode)) {
127
127
  throw new MailDeployError("mail-deploy/bad-mode",
128
128
  "mtaStsPublish: opts.mode must be 'enforce' | 'testing' | 'none'");
129
129
  }
@@ -730,14 +730,14 @@ function _validateTlsRptReport(raw, ctx) {
730
730
  var sRaw = summary["total-successful-session-count"];
731
731
  var fRaw = summary["total-failure-session-count"];
732
732
  if (sRaw !== undefined) {
733
- if (typeof sRaw !== "number" || !isFinite(sRaw) || sRaw < 0 || Math.floor(sRaw) !== sRaw) {
733
+ if (!numericBounds.isNonNegativeFiniteInt(sRaw)) {
734
734
  throw new TlsRptParseError("mail-tlsrpt/bad-summary",
735
735
  "parseTlsRptReport: policies[" + i + "].summary.total-successful-session-count must be a finite non-negative integer");
736
736
  }
737
737
  totalSuccess += sRaw;
738
738
  }
739
739
  if (fRaw !== undefined) {
740
- if (typeof fRaw !== "number" || !isFinite(fRaw) || fRaw < 0 || Math.floor(fRaw) !== fRaw) {
740
+ if (!numericBounds.isNonNegativeFiniteInt(fRaw)) {
741
741
  throw new TlsRptParseError("mail-tlsrpt/bad-summary",
742
742
  "parseTlsRptReport: policies[" + i + "].summary.total-failure-session-count must be a finite non-negative integer");
743
743
  }
@@ -776,7 +776,11 @@ function _validatePolicy(p, idx) {
776
776
  "parseTlsRptReport: policies[" + idx + "].policy missing");
777
777
  }
778
778
  var pType = policy["policy-type"];
779
- if (!TLSRPT_POLICY_TYPES[pType]) {
779
+ // hasOwnProperty, not `TLSRPT_POLICY_TYPES[pType]`: a remote MTA's report JSON
780
+ // controls pType, and a bracket lookup on the plain-object allowlist resolves
781
+ // inherited members ("constructor"/"__proto__"/"toString") to truthy, passing
782
+ // an out-of-vocabulary policy-type (prototype shadowing).
783
+ if (typeof pType !== "string" || !Object.prototype.hasOwnProperty.call(TLSRPT_POLICY_TYPES, pType)) {
780
784
  throw new TlsRptParseError("mail-tlsrpt/bad-policy",
781
785
  "parseTlsRptReport: policies[" + idx + "].policy.policy-type '" + pType +
782
786
  "' not in {sts, tlsa, no-policy-found}");
@@ -805,7 +809,7 @@ function _validatePolicy(p, idx) {
805
809
  throw new TlsRptParseError("mail-tlsrpt/bad-failure-detail",
806
810
  "parseTlsRptReport: policies[" + idx + "].failure-details[" + k + "] must be an object");
807
811
  }
808
- if (typeof fd["result-type"] === "string" && !TLSRPT_RESULT_TYPES[fd["result-type"]]) {
812
+ if (typeof fd["result-type"] === "string" && !Object.prototype.hasOwnProperty.call(TLSRPT_RESULT_TYPES, fd["result-type"])) {
809
813
  // Unknown result-type — surface as audit metadata but don't
810
814
  // refuse; RFC 8460 §4.4 result-type registry can grow over
811
815
  // time and we shouldn't break on new IANA entries.
@@ -162,7 +162,7 @@ var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
162
162
  function create(opts) {
163
163
  opts = opts || {};
164
164
  var profile = gateContract.resolveProfileName(opts, COMPLIANCE_POSTURES, DEFAULT_PROFILE);
165
- if (!PROFILES[profile]) {
165
+ if (!Object.prototype.hasOwnProperty.call(PROFILES, profile)) {
166
166
  throw new MailGreylistError("mail-greylist/bad-profile",
167
167
  "create: unknown profile '" + profile + "'");
168
168
  }
@@ -323,9 +323,7 @@ function create(opts) {
323
323
  * @example
324
324
  * b.mail.greylist.compliancePosture("hipaa"); // → "strict"
325
325
  */
326
- function compliancePosture(posture) {
327
- return COMPLIANCE_POSTURES[posture] || null;
328
- }
326
+ var compliancePosture = gateContract.makePostureAccessor(COMPLIANCE_POSTURES);
329
327
 
330
328
  function _hashFingerprint(cidr, mailFrom, rcptTo) {
331
329
  // Namespace-hash so the on-disk key is unlinkable to the PII
@@ -201,7 +201,7 @@ var LOCALHOST_REFUSED = Object.freeze({
201
201
  async function evaluate(ctx, opts) {
202
202
  opts = opts || {};
203
203
  var profile = gateContract.resolveProfileName(opts, COMPLIANCE_POSTURES, DEFAULT_PROFILE);
204
- if (!PROFILES[profile]) {
204
+ if (!Object.prototype.hasOwnProperty.call(PROFILES, profile)) {
205
205
  throw new MailHeloError("mail-helo/bad-profile",
206
206
  "evaluate: unknown profile '" + profile + "'");
207
207
  }
@@ -453,9 +453,7 @@ function _emitAudit(auditImpl, action, metadata) {
453
453
  * @example
454
454
  * b.mail.helo.compliancePosture("hipaa"); // → "strict"
455
455
  */
456
- function compliancePosture(posture) {
457
- return COMPLIANCE_POSTURES[posture] || null;
458
- }
456
+ var compliancePosture = gateContract.makePostureAccessor(COMPLIANCE_POSTURES);
459
457
 
460
458
  module.exports = {
461
459
  evaluate: evaluate,
@@ -180,9 +180,9 @@ function create(opts) {
180
180
  throw new MailJournalError("mail-journal/bad-vault",
181
181
  "b.mail.journal.create: opts.vault must be a b.vault handle");
182
182
  }
183
- if (!opts.legalHold || typeof opts.legalHold.isOnHold !== "function") {
183
+ if (!opts.legalHold || typeof opts.legalHold.isHeld !== "function") {
184
184
  throw new MailJournalError("mail-journal/bad-legal-hold",
185
- "b.mail.journal.create: opts.legalHold must be a b.legalHold handle (must expose isOnHold)");
185
+ "b.mail.journal.create: opts.legalHold must be a b.legalHold handle (must expose isHeld)");
186
186
  }
187
187
  if (!opts.db || typeof opts.db.runSql !== "function") {
188
188
  throw new MailJournalError("mail-journal/bad-db",
@@ -252,7 +252,7 @@ function create(opts) {
252
252
  async function record(req) {
253
253
  validateOpts.requireObject(req, "mail.journal.record",
254
254
  MailJournalError, "mail-journal/bad-record");
255
- if (!ALLOWED_DIRECTIONS[req.direction]) {
255
+ if (!Object.prototype.hasOwnProperty.call(ALLOWED_DIRECTIONS, req.direction)) {
256
256
  throw new MailJournalError("mail-journal/bad-direction",
257
257
  "mail.journal.record: opts.direction must be 'inbound' | 'outbound' | 'internal'");
258
258
  }
@@ -300,11 +300,13 @@ function create(opts) {
300
300
 
301
301
  var regimesJson = JSON.stringify(opts.regimes);
302
302
  var floorUntil = archivedAt + floorMs;
303
- // legal_hold is omitted from the INSERT so the column's
304
- // `NOT NULL DEFAULT 0` applies (the prior inline `0` SQL literal) b.sql
305
- // binds every value it is given, so leaving the column out keeps the row
306
- // unsealed-at-rest default without binding a redundant constant. b.sql
307
- // quotes every column + binds every remaining value as a placeholder.
303
+ // Auto-derive the legal-hold flag from the registry: an entry whose actor is
304
+ // under an active legal hold is born held, exempt from retention expiry even
305
+ // after the floor passes (the doc's "every entry carries a legalHold flag").
306
+ // setLegalHold remains the manual override. isHeld already treats a lapsed
307
+ // (retainUntil-expired) hold as not-held, so a stale hold won't over-flag.
308
+ var actorHeld = !!opts.legalHold.isHeld(req.actorId);
309
+ // b.sql quotes every column + binds every value as a placeholder.
308
310
  var insBuilt = _t("insert").values({
309
311
  journal_id: journalId,
310
312
  direction: req.direction,
@@ -314,6 +316,7 @@ function create(opts) {
314
316
  size_bytes: sizeBytes,
315
317
  regimes: regimesJson,
316
318
  floor_until: floorUntil,
319
+ legal_hold: actorHeld ? 1 : 0,
317
320
  storage_key: storageKey,
318
321
  sealed_payload: sealedBlob,
319
322
  }).toSql();
@@ -162,14 +162,14 @@ function build(opts) {
162
162
  validateOpts.requireNonEmptyString(opts.finalRecipient,
163
163
  "mailMdn.build: opts.finalRecipient", MailMdnError, "mdn/missing-required-field");
164
164
  var disposition = String(opts.disposition || "").toLowerCase();
165
- if (!DISPOSITION_TYPES[disposition]) {
165
+ if (!Object.prototype.hasOwnProperty.call(DISPOSITION_TYPES, disposition)) {
166
166
  throw _err("mdn/missing-required-field",
167
167
  "mailMdn.build: opts.disposition must be one of " +
168
168
  Object.keys(DISPOSITION_TYPES).join(" / ") +
169
169
  "; got '" + String(opts.disposition) + "'");
170
170
  }
171
171
  var actionMode = String(opts.actionMode || "manual-action").toLowerCase();
172
- if (!ACTION_MODES[actionMode]) {
172
+ if (!Object.prototype.hasOwnProperty.call(ACTION_MODES, actionMode)) {
173
173
  throw _err("mdn/missing-required-field",
174
174
  "mailMdn.build: opts.actionMode must be one of " +
175
175
  Object.keys(ACTION_MODES).join(" / ") +
@@ -179,7 +179,7 @@ function build(opts) {
179
179
  // Accept the canonical mixed-case form too — RFC 3798 §3.2.6.2 uses
180
180
  // `MDN-sent-manually` / `MDN-sent-automatically`. Compare lower-case
181
181
  // for robustness; emit canonical mixed-case in the output.
182
- if (!SENDING_MODES[sendingMode]) {
182
+ if (!Object.prototype.hasOwnProperty.call(SENDING_MODES, sendingMode)) {
183
183
  throw _err("mdn/missing-required-field",
184
184
  "mailMdn.build: opts.sendingMode must be one of " +
185
185
  "MDN-sent-manually / MDN-sent-automatically; got '" +
@@ -395,7 +395,11 @@ function parse(rawMessage) {
395
395
  "mailMdn.parse: message/disposition-notification missing Disposition");
396
396
  }
397
397
  var disposition = _parseDisposition(dispositionField);
398
- if (!disposition || !DISPOSITION_TYPES[disposition.type]) {
398
+ // hasOwnProperty: the Disposition token comes from an untrusted inbound MDN, so
399
+ // a bracket lookup lets "constructor"/"__proto__" pass as a valid type (proto
400
+ // shadowing).
401
+ if (!disposition || typeof disposition.type !== "string" ||
402
+ !Object.prototype.hasOwnProperty.call(DISPOSITION_TYPES, disposition.type)) {
399
403
  throw _err("mdn/parse-failed",
400
404
  "mailMdn.parse: Disposition type token not in RFC 3798 §3.2.6 vocabulary; got '" +
401
405
  (disposition && disposition.type) + "'");
@@ -140,7 +140,7 @@ function create(opts) {
140
140
  "create: opts.resolver must be a b.network.dns.resolver.create() instance");
141
141
  }
142
142
  var profile = gateContract.resolveProfileName(opts, COMPLIANCE_POSTURES, DEFAULT_PROFILE);
143
- if (!PROFILES[profile]) {
143
+ if (!Object.prototype.hasOwnProperty.call(PROFILES, profile)) {
144
144
  throw new MailRblError("mail-rbl/bad-profile",
145
145
  "create: unknown profile '" + profile + "'");
146
146
  }
@@ -314,9 +314,7 @@ function reverseIp(ip) {
314
314
  * @example
315
315
  * b.mail.rbl.compliancePosture("hipaa"); // → "strict"
316
316
  */
317
- function compliancePosture(posture) {
318
- return COMPLIANCE_POSTURES[posture] || null;
319
- }
317
+ var compliancePosture = gateContract.makePostureAccessor(COMPLIANCE_POSTURES);
320
318
 
321
319
  function _validateZoneNames(zones) {
322
320
  for (var i = 0; i < zones.length; i += 1) {
@@ -164,7 +164,7 @@ function create(opts) {
164
164
  numericBounds.requirePositiveFiniteInt(opts.port, "mail.scan.create.port",
165
165
  MailScanError, "mail-scan/bad-port", { max: 65535 }); // TCP port-number range cap
166
166
  var protocol = opts.protocol || DEFAULT_PROTOCOL;
167
- if (!ALLOWED_PROTOCOLS[protocol]) {
167
+ if (!Object.prototype.hasOwnProperty.call(ALLOWED_PROTOCOLS, protocol)) {
168
168
  throw new MailScanError("mail-scan/bad-protocol",
169
169
  "mail.scan.create.protocol must be 'icap' or 'clamav-instream'; got '" + protocol + "'");
170
170
  }
@@ -174,7 +174,7 @@ function create(opts) {
174
174
  MailScanError, "mail-scan/bad-service");
175
175
  }
176
176
  var profile = gateContract.resolveProfileName(opts, COMPLIANCE_POSTURES, DEFAULT_PROFILE);
177
- if (!PROFILES[profile]) {
177
+ if (!Object.prototype.hasOwnProperty.call(PROFILES, profile)) {
178
178
  throw new MailScanError("mail-scan/bad-profile",
179
179
  "mail.scan.create.profile: unknown '" + profile + "' (valid: strict / balanced / permissive)");
180
180
  }
@@ -448,9 +448,7 @@ function create(opts) {
448
448
  * @example
449
449
  * b.mail.scan.compliancePosture("hipaa"); // → "strict"
450
450
  */
451
- function compliancePosture(posture) {
452
- return COMPLIANCE_POSTURES[posture] || null;
453
- }
451
+ var compliancePosture = gateContract.makePostureAccessor(COMPLIANCE_POSTURES);
454
452
 
455
453
  function _emitScanResult(auditImpl, rv) {
456
454
  if (rv.verdict === "clean") {
@@ -1138,7 +1138,10 @@ function create(opts) {
1138
1138
  return;
1139
1139
  }
1140
1140
  var text = data.toString("utf8");
1141
- if (text.length > (opts.webSocketMaxMessageBytes || (10 * 1024 * 1024))) { // allow:raw-byte-literal — mirrors handleUpgrade cap
1141
+ // Byte cap measured on the raw frame buffer, not text.length (UTF-16
1142
+ // code units) — a multibyte payload is 2-4x larger in bytes than chars,
1143
+ // so a char-length check under-enforces the limit.
1144
+ if (data.length > (opts.webSocketMaxMessageBytes || (10 * 1024 * 1024))) { // allow:raw-byte-literal — mirrors handleUpgrade cap
1142
1145
  _sendRequestError(null,
1143
1146
  "urn:ietf:params:jmap:error:limit",
1144
1147
  "WebSocket message exceeds maxSizeRequest");
@@ -142,7 +142,7 @@ function create(opts) {
142
142
  validateOpts.requireNonEmptyString(opts.protocol,
143
143
  "b.mail.serverRegistry.create: protocol", MailServerRegistryError,
144
144
  "mail-server-registry/bad-protocol");
145
- if (!CATALOGUE[opts.protocol]) {
145
+ if (!Object.prototype.hasOwnProperty.call(CATALOGUE, opts.protocol)) {
146
146
  throw new MailServerRegistryError("mail-server-registry/unknown-protocol",
147
147
  "create: protocol must be 'imap', 'jmap', or 'managesieve' (got '" + opts.protocol + "')");
148
148
  }
@@ -93,6 +93,7 @@ var nodeFs = require("node:fs");
93
93
  var nodeTls = require("node:tls");
94
94
  var lazyRequire = require("./lazy-require");
95
95
  var C = require("./constants");
96
+ var atomicFile = require("./atomic-file");
96
97
  var validateOpts = require("./validate-opts");
97
98
  var { defineClass } = require("./framework-error");
98
99
 
@@ -177,7 +178,11 @@ function context(opts) {
177
178
  var stopped = false;
178
179
 
179
180
  function _readKey() {
180
- var raw = nodeFs.readFileSync(keyFile, "utf8");
181
+ // Cap + fd-bound TLS-private-key read. NO refuseSymlink: keyFile is commonly
182
+ // certbot's /etc/letsencrypt/live/<host>/privkey.pem, a symlink chain into
183
+ // ../../archive — refusing symlinks would break the documented Let's Encrypt
184
+ // layout. The cap is the OOM-before-use defense.
185
+ var raw = atomicFile.fdSafeReadSync(keyFile, { maxBytes: C.BYTES.kib(64), encoding: "utf8" });
181
186
  // b.vault.sealPemFile produces blobs that decrypt via vault.unseal.
182
187
  // Detect by the sealed-cell prefix the framework's vault layer
183
188
  // already documents (everything else passes through as plain PEM).
@@ -196,7 +201,9 @@ function context(opts) {
196
201
  function _build() {
197
202
  var certPem;
198
203
  try {
199
- certPem = nodeFs.readFileSync(certFile, "utf8");
204
+ // Cap + fd-bound cert-chain read. NO refuseSymlink (certbot fullchain.pem
205
+ // is a symlink); the cap is the safe hardening.
206
+ certPem = atomicFile.fdSafeReadSync(certFile, { maxBytes: C.BYTES.mib(1), encoding: "utf8" });
200
207
  } catch (e) {
201
208
  throw new MailServerTlsError("mail-server-tls/cert-unreadable",
202
209
  "b.mail.server.tls.context: cannot read certFile " + certFile + ": " +
@@ -133,7 +133,7 @@ function create(opts) {
133
133
  "mail.spamScore.create.scorer must be a function; got " + (typeof opts.scorer));
134
134
  }
135
135
  var profile = gateContract.resolveProfileName(opts, COMPLIANCE_POSTURES, DEFAULT_PROFILE);
136
- if (!PROFILES[profile]) {
136
+ if (!Object.prototype.hasOwnProperty.call(PROFILES, profile)) {
137
137
  throw new MailSpamScoreError("mail-spam-score/bad-profile",
138
138
  "mail.spamScore.create.profile: unknown '" + profile +
139
139
  "' (valid: strict / balanced / permissive)");
@@ -222,9 +222,7 @@ function create(opts) {
222
222
  * @example
223
223
  * b.mail.spamScore.compliancePosture("hipaa"); // → "strict"
224
224
  */
225
- function compliancePosture(posture) {
226
- return COMPLIANCE_POSTURES[posture] || null;
227
- }
225
+ var compliancePosture = gateContract.makePostureAccessor(COMPLIANCE_POSTURES);
228
226
 
229
227
  function _sanitizeReasons(reasons, caps) {
230
228
  if (reasons === undefined || reasons === null) return [];
@@ -321,7 +321,7 @@ var QUERY_KEY_MAP = {
321
321
  * // → { column: "addr_toks", field: "addr" }
322
322
  */
323
323
  function columnAndFieldFor(key) {
324
- return QUERY_KEY_MAP[key] || null;
324
+ return Object.prototype.hasOwnProperty.call(QUERY_KEY_MAP, key) ? QUERY_KEY_MAP[key] : null;
325
325
  }
326
326
 
327
327
  // Rewrite an operator query term into a FTS5 MATCH expression. The