@blamejs/blamejs-shop 0.4.69 → 0.4.71

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 (299) 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/security-middleware.js +65 -23
  5. package/lib/shipping-insurance.js +29 -4
  6. package/lib/sms-dispatcher.js +17 -4
  7. package/lib/storefront.js +10 -7
  8. package/lib/vendor/MANIFEST.json +319 -267
  9. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  10. package/lib/vendor/blamejs/api-snapshot.json +58 -5
  11. package/lib/vendor/blamejs/examples/wiki/README.md +1 -1
  12. package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +9 -8
  13. package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +10 -9
  14. package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +4 -3
  15. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +33 -17
  16. package/lib/vendor/blamejs/examples/wiki/routes/admin.js +7 -10
  17. package/lib/vendor/blamejs/examples/wiki/server.js +5 -4
  18. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +5 -0
  19. package/lib/vendor/blamejs/lib/a2a-tasks.js +38 -6
  20. package/lib/vendor/blamejs/lib/agent-event-bus.js +13 -0
  21. package/lib/vendor/blamejs/lib/agent-idempotency.js +5 -1
  22. package/lib/vendor/blamejs/lib/agent-snapshot.js +32 -2
  23. package/lib/vendor/blamejs/lib/ai-aedt-bias-audit.js +2 -1
  24. package/lib/vendor/blamejs/lib/ai-content-detect.js +1 -3
  25. package/lib/vendor/blamejs/lib/ai-frontier-protocol.js +1 -1
  26. package/lib/vendor/blamejs/lib/ai-model-manifest.js +1 -1
  27. package/lib/vendor/blamejs/lib/ai-output.js +16 -7
  28. package/lib/vendor/blamejs/lib/api-snapshot.js +4 -1
  29. package/lib/vendor/blamejs/lib/app-shutdown.js +7 -1
  30. package/lib/vendor/blamejs/lib/archive-gz.js +9 -0
  31. package/lib/vendor/blamejs/lib/archive-read.js +9 -7
  32. package/lib/vendor/blamejs/lib/archive-tar-read.js +51 -8
  33. package/lib/vendor/blamejs/lib/archive.js +4 -2
  34. package/lib/vendor/blamejs/lib/asn1-der.js +70 -22
  35. package/lib/vendor/blamejs/lib/atomic-file.js +204 -2
  36. package/lib/vendor/blamejs/lib/audit-chain.js +54 -5
  37. package/lib/vendor/blamejs/lib/audit-daily-review.js +12 -2
  38. package/lib/vendor/blamejs/lib/audit-sign.js +2 -1
  39. package/lib/vendor/blamejs/lib/audit-tools.js +108 -23
  40. package/lib/vendor/blamejs/lib/audit.js +7 -2
  41. package/lib/vendor/blamejs/lib/auth/access-lock.js +2 -2
  42. package/lib/vendor/blamejs/lib/auth/bot-challenge.js +1 -1
  43. package/lib/vendor/blamejs/lib/auth/ciba.js +43 -4
  44. package/lib/vendor/blamejs/lib/auth/dpop.js +6 -1
  45. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +5 -1
  46. package/lib/vendor/blamejs/lib/auth/jwt.js +2 -2
  47. package/lib/vendor/blamejs/lib/auth/lockout.js +18 -2
  48. package/lib/vendor/blamejs/lib/auth/passkey.js +1 -1
  49. package/lib/vendor/blamejs/lib/auth/password.js +1 -1
  50. package/lib/vendor/blamejs/lib/auth/saml.js +33 -13
  51. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +24 -4
  52. package/lib/vendor/blamejs/lib/auth/status-list.js +14 -2
  53. package/lib/vendor/blamejs/lib/auth/step-up.js +9 -1
  54. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +21 -2
  55. package/lib/vendor/blamejs/lib/backup/bundle.js +7 -2
  56. package/lib/vendor/blamejs/lib/backup/crypto.js +23 -8
  57. package/lib/vendor/blamejs/lib/backup/index.js +41 -20
  58. package/lib/vendor/blamejs/lib/backup/manifest.js +7 -1
  59. package/lib/vendor/blamejs/lib/break-glass.js +41 -22
  60. package/lib/vendor/blamejs/lib/cbor.js +34 -11
  61. package/lib/vendor/blamejs/lib/cdn-cache-control.js +7 -3
  62. package/lib/vendor/blamejs/lib/cert.js +5 -3
  63. package/lib/vendor/blamejs/lib/cli.js +5 -1
  64. package/lib/vendor/blamejs/lib/cloud-events.js +3 -2
  65. package/lib/vendor/blamejs/lib/cluster-storage.js +7 -3
  66. package/lib/vendor/blamejs/lib/codepoint-class.js +17 -0
  67. package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -1
  68. package/lib/vendor/blamejs/lib/compliance-sanctions.js +9 -7
  69. package/lib/vendor/blamejs/lib/compliance.js +1 -1
  70. package/lib/vendor/blamejs/lib/config-drift.js +22 -8
  71. package/lib/vendor/blamejs/lib/content-credentials.js +11 -8
  72. package/lib/vendor/blamejs/lib/content-digest.js +11 -4
  73. package/lib/vendor/blamejs/lib/cookies.js +10 -2
  74. package/lib/vendor/blamejs/lib/cose.js +20 -0
  75. package/lib/vendor/blamejs/lib/crdt.js +2 -1
  76. package/lib/vendor/blamejs/lib/crypto-field.js +29 -23
  77. package/lib/vendor/blamejs/lib/crypto.js +18 -4
  78. package/lib/vendor/blamejs/lib/csp.js +4 -0
  79. package/lib/vendor/blamejs/lib/daemon.js +4 -1
  80. package/lib/vendor/blamejs/lib/data-act.js +27 -4
  81. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +14 -6
  82. package/lib/vendor/blamejs/lib/db-query.js +69 -9
  83. package/lib/vendor/blamejs/lib/db.js +32 -15
  84. package/lib/vendor/blamejs/lib/dora.js +43 -13
  85. package/lib/vendor/blamejs/lib/dr-runbook.js +1 -1
  86. package/lib/vendor/blamejs/lib/dsa.js +2 -1
  87. package/lib/vendor/blamejs/lib/dsr.js +22 -8
  88. package/lib/vendor/blamejs/lib/early-hints.js +19 -0
  89. package/lib/vendor/blamejs/lib/eat.js +5 -1
  90. package/lib/vendor/blamejs/lib/external-db.js +60 -4
  91. package/lib/vendor/blamejs/lib/fda-21cfr11.js +30 -5
  92. package/lib/vendor/blamejs/lib/flag-providers.js +6 -2
  93. package/lib/vendor/blamejs/lib/forms.js +1 -1
  94. package/lib/vendor/blamejs/lib/gate-contract.js +46 -5
  95. package/lib/vendor/blamejs/lib/gdpr-ropa.js +18 -9
  96. package/lib/vendor/blamejs/lib/graphql-federation.js +17 -4
  97. package/lib/vendor/blamejs/lib/guard-all.js +2 -2
  98. package/lib/vendor/blamejs/lib/guard-dsn.js +1 -1
  99. package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
  100. package/lib/vendor/blamejs/lib/guard-html.js +9 -11
  101. package/lib/vendor/blamejs/lib/guard-imap-command.js +1 -1
  102. package/lib/vendor/blamejs/lib/guard-jmap.js +1 -1
  103. package/lib/vendor/blamejs/lib/guard-json.js +14 -6
  104. package/lib/vendor/blamejs/lib/guard-mail-move.js +1 -1
  105. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +1 -1
  106. package/lib/vendor/blamejs/lib/guard-pop3-command.js +1 -1
  107. package/lib/vendor/blamejs/lib/guard-smtp-command.js +1 -1
  108. package/lib/vendor/blamejs/lib/guard-svg.js +8 -9
  109. package/lib/vendor/blamejs/lib/html-balance.js +7 -3
  110. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +33 -12
  111. package/lib/vendor/blamejs/lib/http-client.js +225 -53
  112. package/lib/vendor/blamejs/lib/iab-tcf.js +3 -2
  113. package/lib/vendor/blamejs/lib/importmap-integrity.js +41 -1
  114. package/lib/vendor/blamejs/lib/incident-report.js +9 -6
  115. package/lib/vendor/blamejs/lib/json-patch.js +1 -1
  116. package/lib/vendor/blamejs/lib/json-path.js +24 -3
  117. package/lib/vendor/blamejs/lib/jtd.js +2 -2
  118. package/lib/vendor/blamejs/lib/legal-hold.js +24 -8
  119. package/lib/vendor/blamejs/lib/log.js +2 -2
  120. package/lib/vendor/blamejs/lib/mail-agent.js +2 -2
  121. package/lib/vendor/blamejs/lib/mail-arf.js +1 -1
  122. package/lib/vendor/blamejs/lib/mail-auth.js +3 -3
  123. package/lib/vendor/blamejs/lib/mail-bimi.js +16 -16
  124. package/lib/vendor/blamejs/lib/mail-bounce.js +3 -3
  125. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +71 -6
  126. package/lib/vendor/blamejs/lib/mail-deploy.js +9 -5
  127. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -4
  128. package/lib/vendor/blamejs/lib/mail-helo.js +2 -4
  129. package/lib/vendor/blamejs/lib/mail-journal.js +11 -8
  130. package/lib/vendor/blamejs/lib/mail-mdn.js +8 -4
  131. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -4
  132. package/lib/vendor/blamejs/lib/mail-scan.js +3 -5
  133. package/lib/vendor/blamejs/lib/mail-server-jmap.js +4 -1
  134. package/lib/vendor/blamejs/lib/mail-server-registry.js +1 -1
  135. package/lib/vendor/blamejs/lib/mail-server-tls.js +9 -2
  136. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -4
  137. package/lib/vendor/blamejs/lib/mail-store-fts.js +1 -1
  138. package/lib/vendor/blamejs/lib/mail.js +22 -2
  139. package/lib/vendor/blamejs/lib/markup-tokenizer.js +24 -0
  140. package/lib/vendor/blamejs/lib/mcp.js +6 -4
  141. package/lib/vendor/blamejs/lib/mdoc.js +26 -3
  142. package/lib/vendor/blamejs/lib/metrics.js +14 -3
  143. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +2 -2
  144. package/lib/vendor/blamejs/lib/middleware/body-parser.js +10 -4
  145. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +26 -18
  146. package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +5 -1
  147. package/lib/vendor/blamejs/lib/middleware/compression.js +9 -0
  148. package/lib/vendor/blamejs/lib/middleware/cors.js +32 -23
  149. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +60 -21
  150. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -4
  151. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +28 -4
  152. package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +61 -30
  153. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +25 -16
  154. package/lib/vendor/blamejs/lib/middleware/scim-server.js +2 -1
  155. package/lib/vendor/blamejs/lib/middleware/security-headers.js +24 -6
  156. package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +6 -3
  157. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +2 -2
  158. package/lib/vendor/blamejs/lib/money.js +1 -1
  159. package/lib/vendor/blamejs/lib/mtls-ca.js +10 -6
  160. package/lib/vendor/blamejs/lib/network-dns-resolver.js +1 -1
  161. package/lib/vendor/blamejs/lib/network-dns.js +9 -2
  162. package/lib/vendor/blamejs/lib/network-dnssec.js +2 -1
  163. package/lib/vendor/blamejs/lib/network-smtp-policy.js +23 -5
  164. package/lib/vendor/blamejs/lib/network-tls.js +27 -5
  165. package/lib/vendor/blamejs/lib/network-tsig.js +2 -2
  166. package/lib/vendor/blamejs/lib/nis2-report.js +1 -1
  167. package/lib/vendor/blamejs/lib/nist-crosswalk.js +1 -1
  168. package/lib/vendor/blamejs/lib/ntp-check.js +28 -0
  169. package/lib/vendor/blamejs/lib/numeric-bounds.js +9 -0
  170. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +1 -2
  171. package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +4 -2
  172. package/lib/vendor/blamejs/lib/object-store/gcs.js +6 -4
  173. package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -2
  174. package/lib/vendor/blamejs/lib/object-store/http-request.js +30 -1
  175. package/lib/vendor/blamejs/lib/object-store/local.js +37 -17
  176. package/lib/vendor/blamejs/lib/object-store/sigv4.js +1 -2
  177. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +20 -4
  178. package/lib/vendor/blamejs/lib/outbox.js +11 -4
  179. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +1 -1
  180. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +21 -3
  181. package/lib/vendor/blamejs/lib/queue-local.js +10 -3
  182. package/lib/vendor/blamejs/lib/redact.js +7 -3
  183. package/lib/vendor/blamejs/lib/request-helpers.js +201 -23
  184. package/lib/vendor/blamejs/lib/resource-access-lock.js +3 -3
  185. package/lib/vendor/blamejs/lib/restore-bundle.js +46 -18
  186. package/lib/vendor/blamejs/lib/restore-rollback.js +10 -4
  187. package/lib/vendor/blamejs/lib/restore.js +19 -0
  188. package/lib/vendor/blamejs/lib/retention.js +20 -4
  189. package/lib/vendor/blamejs/lib/router.js +17 -4
  190. package/lib/vendor/blamejs/lib/safe-ical.js +2 -2
  191. package/lib/vendor/blamejs/lib/safe-icap.js +1 -1
  192. package/lib/vendor/blamejs/lib/safe-json.js +44 -0
  193. package/lib/vendor/blamejs/lib/safe-sieve.js +1 -1
  194. package/lib/vendor/blamejs/lib/safe-vcard.js +1 -1
  195. package/lib/vendor/blamejs/lib/sandbox-worker.js +6 -0
  196. package/lib/vendor/blamejs/lib/sandbox.js +1 -1
  197. package/lib/vendor/blamejs/lib/scheduler.js +17 -1
  198. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +16 -0
  199. package/lib/vendor/blamejs/lib/session.js +27 -3
  200. package/lib/vendor/blamejs/lib/sql.js +3 -3
  201. package/lib/vendor/blamejs/lib/static.js +65 -13
  202. package/lib/vendor/blamejs/lib/template.js +7 -5
  203. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -19
  204. package/lib/vendor/blamejs/lib/tsa.js +5 -2
  205. package/lib/vendor/blamejs/lib/vault/index.js +5 -0
  206. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +22 -26
  207. package/lib/vendor/blamejs/lib/vault/passphrase-source.js +8 -3
  208. package/lib/vendor/blamejs/lib/vault/rotate.js +13 -18
  209. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +4 -1
  210. package/lib/vendor/blamejs/lib/vc.js +1 -1
  211. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +10 -10
  212. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +23 -10
  213. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5498 -5494
  214. package/lib/vendor/blamejs/lib/webhook.js +16 -1
  215. package/lib/vendor/blamejs/lib/websocket.js +1 -1
  216. package/lib/vendor/blamejs/lib/worm.js +1 -1
  217. package/lib/vendor/blamejs/lib/ws-client.js +57 -46
  218. package/lib/vendor/blamejs/lib/x509-chain.js +44 -0
  219. package/lib/vendor/blamejs/package.json +1 -1
  220. package/lib/vendor/blamejs/release-notes/v0.15.14.json +122 -0
  221. package/lib/vendor/blamejs/scripts/check-vendor-currency.js +119 -4
  222. package/lib/vendor/blamejs/test/00-primitives.js +5 -1
  223. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +18 -4
  224. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +42 -0
  225. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +36 -0
  226. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  227. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +47 -0
  228. package/lib/vendor/blamejs/test/layer-0-primitives/archive-gz.test.js +24 -0
  229. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-hardening.test.js +160 -0
  230. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +45 -0
  231. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +30 -0
  232. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-open-nofollow.test.js +79 -0
  233. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-excl.test.js +132 -0
  234. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-stream.test.js +181 -0
  235. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-corrupted-anchor.test.js +65 -0
  236. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-incremental-verify.test.js +83 -0
  237. package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +48 -1
  238. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +13 -3
  239. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +122 -0
  240. package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +37 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +5 -3
  242. package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +21 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +73 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +17 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +62 -3
  246. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +12 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-storage.test.js +40 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +146 -5
  249. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +14 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/compression-range.test.js +115 -0
  251. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +17 -5
  252. package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +27 -5
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +83 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +58 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +30 -0
  256. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +74 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +20 -6
  258. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-alg-kty.test.js +64 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +32 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +43 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +30 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +33 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +34 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +12 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +72 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-throttle-transform.test.js +88 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +25 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +28 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +20 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/mail-header-injection.test.js +58 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +63 -9
  272. package/lib/vendor/blamejs/test/layer-0-primitives/mdoc.test.js +41 -14
  273. package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +61 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/object-store-range-header.test.js +51 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +35 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/output-header-hardening.test.js +102 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/parser-verify-hardening.test.js +191 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/proto-shadow-allowlist.test.js +120 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +75 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +128 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/restore-blob-remap.test.js +128 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/retention-sweep-termination.test.js +104 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/router-body-validation.test.js +98 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json-stringify-for-script.test.js +43 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +48 -5
  286. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +23 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +54 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +24 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +42 -1
  290. package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +7 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/template-escape-html.test.js +43 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +15 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/vault-default-store.test.js +48 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/vendor-currency-classify.test.js +77 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +50 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +22 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/x509-chain-ca-enforcement.test.js +149 -0
  298. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +34 -0
  299. package/package.json +1 -1
@@ -343,7 +343,7 @@ function create(opts) {
343
343
  var secret = opts.secret;
344
344
 
345
345
  var providerKey = opts.provider !== undefined ? opts.provider : DEFAULT_PROVIDER;
346
- if (typeof providerKey !== "string" || !PROVIDERS[providerKey]) {
346
+ if (typeof providerKey !== "string" || !Object.prototype.hasOwnProperty.call(PROVIDERS, providerKey)) {
347
347
  var supported = Object.keys(PROVIDERS).join(", ");
348
348
  throw new BotChallengeError("bot-challenge/bad-opt",
349
349
  "provider: expected one of [" + supported + "], got " + JSON.stringify(providerKey));
@@ -452,6 +452,23 @@ function create(opts) {
452
452
  });
453
453
  }
454
454
 
455
+ // Verify an OIDC ID token (if present) via the composed inner OAuth client,
456
+ // returning its verified claims, or null when no id_token was supplied. A
457
+ // present-but-invalid id_token throws (fail-closed) so a forged token's
458
+ // sub/acr/amr can never be returned as trusted.
459
+ async function _verifyIdTokenIfPresent(idToken, auditKey, op) {
460
+ if (!idToken) return null;
461
+ try {
462
+ return await inner.verifyIdToken(idToken);
463
+ } catch (e) {
464
+ _emitAudit("id_token_verify_fail", "failure",
465
+ auditKey ? { authReqIdHash: sha3Hash(auditKey) } : {});
466
+ throw new AuthError("auth-ciba/id-token-invalid",
467
+ "ciba." + op + ": id_token failed verification: " +
468
+ ((e && e.code) || (e && e.message) || String(e)));
469
+ }
470
+ }
471
+
455
472
  async function pollToken(popts) {
456
473
  popts = popts || {};
457
474
  if (typeof popts.authReqId !== "string" || popts.authReqId.length === 0) {
@@ -514,6 +531,12 @@ function create(opts) {
514
531
  }
515
532
  // Token issued — clear interval tracking for this authReqId.
516
533
  _intervalState.delete(popts.authReqId);
534
+ // Verify the ID token (OIDC Core §3.1.3.7) via the composed inner OAuth
535
+ // client — it applies the create()-level issuer / clientId / JWKS /
536
+ // accepted-algorithms and enforces signature + iss/aud/exp. Returning an
537
+ // unverified id_token let a forged token's sub/acr/amr be trusted.
538
+ var pollClaims = await _verifyIdTokenIfPresent(rv.id_token,
539
+ "auth-ciba:" + popts.authReqId, "pollToken");
517
540
  _emitAudit("token_received", "success", {
518
541
  authReqIdHash: sha3Hash("auth-ciba:" + popts.authReqId),
519
542
  });
@@ -521,6 +544,7 @@ function create(opts) {
521
544
  return {
522
545
  accessToken: rv.access_token || null,
523
546
  idToken: rv.id_token || null,
547
+ claims: pollClaims,
524
548
  refreshToken: rv.refresh_token || null,
525
549
  tokenType: rv.token_type || null,
526
550
  scope: rv.scope || null,
@@ -545,17 +569,23 @@ function create(opts) {
545
569
  * - In **push** mode the body carries the full token-response
546
570
  * object; no follow-up call needed.
547
571
  *
572
+ * Async because a pushed `id_token` is verified (signature + iss/aud/exp)
573
+ * via the composed inner OAuth client before it is returned — the
574
+ * verified claims are surfaced as `claims`. A present-but-invalid
575
+ * id_token throws `auth-ciba/id-token-invalid` (the notification-token
576
+ * bearer authenticates the caller, never the token itself).
577
+ *
548
578
  * @opts
549
579
  * { body?: object } // pre-parsed body; defaults to req.body
550
580
  *
551
581
  * @example
552
- * app.post("/ciba/notify", function (req, res) {
553
- * var info = ciba.parseNotification(req, { body: req.body });
554
- * // → { authReqId, accessToken, idToken, ... }
582
+ * app.post("/ciba/notify", async function (req, res) {
583
+ * var info = await ciba.parseNotification(req, { body: req.body });
584
+ * // → { authReqId, accessToken, idToken, claims, ... }
555
585
  * res.statusCode = 204; res.end();
556
586
  * });
557
587
  */
558
- function parseNotification(req, popts) {
588
+ async function parseNotification(req, popts) {
559
589
  popts = popts || {};
560
590
  if (!req || !req.headers) {
561
591
  throw new AuthError("auth-ciba/bad-notification-req",
@@ -605,6 +635,14 @@ function create(opts) {
605
635
  throw new AuthError("auth-ciba/no-auth-req-id-in-body",
606
636
  "ciba.parseNotification: body missing auth_req_id");
607
637
  }
638
+ // Verify the pushed ID token (CIBA §10.2 / OIDC Core MUST) via the
639
+ // composed inner OAuth client before returning it as trusted. The
640
+ // notification-token bearer authenticates the CALLER, not the token; a
641
+ // leaked/observed notification token previously let an attacker inject
642
+ // arbitrary id_token claims the RP would trust on the documented
643
+ // "no follow-up call" push path.
644
+ var pushClaims = await _verifyIdTokenIfPresent(body.id_token,
645
+ "auth-ciba:" + body.auth_req_id, "parseNotification");
608
646
  _emitAudit("notification_received", "success", {
609
647
  authReqIdHash: sha3Hash("auth-ciba:" + body.auth_req_id),
610
648
  mode: deliveryMode,
@@ -614,6 +652,7 @@ function create(opts) {
614
652
  authReqId: body.auth_req_id,
615
653
  accessToken: body.access_token || null,
616
654
  idToken: body.id_token || null,
655
+ claims: pushClaims,
617
656
  refreshToken: body.refresh_token || null,
618
657
  tokenType: body.token_type || null,
619
658
  scope: body.scope || null,
@@ -92,7 +92,7 @@ function thumbprint(key) {
92
92
  if (!key || typeof key !== "object" || typeof key.kty !== "string" || key.kty.length === 0) {
93
93
  throw new AuthError("auth-dpop/bad-jwk", "jwk must be an object with a kty");
94
94
  }
95
- if (!DPOP_KTY[key.kty]) {
95
+ if (!Object.prototype.hasOwnProperty.call(DPOP_KTY, key.kty)) {
96
96
  throw new AuthError("auth-dpop/refused-kty", "jwk.kty='" + key.kty + "' is not allowed (DPoP requires asymmetric kty)");
97
97
  }
98
98
  // The RFC 7638 thumbprint itself is computed by b.jwk.
@@ -348,6 +348,11 @@ async function verify(proof, opts) {
348
348
  "DPoP proof declares 'crit' header — refused");
349
349
  }
350
350
 
351
+ // Bind the declared alg to the embedded JWK's kty/curve before handing
352
+ // the self-asserted key to node:crypto — every other JWS verifier in the
353
+ // framework enforces this (alg-confusion family, CVE-2026-22817 class).
354
+ jwtExternal._assertAlgKtyMatch(header.alg, header.jwk);
355
+
351
356
  // Verify signature against the embedded jwk
352
357
  var key = _jwkToKeyObject(header.jwk);
353
358
  var params = _signParamsForAlg(header.alg);
@@ -43,6 +43,7 @@ var safeJson = require("../safe-json");
43
43
  var safeBuffer = require("../safe-buffer");
44
44
  var lazyRequire = require("../lazy-require");
45
45
  var validateOpts = require("../validate-opts");
46
+ var x509Chain = require("../x509-chain");
46
47
  var jwtExternal = require("./jwt-external");
47
48
  var _wa = require("../vendor/simplewebauthn-server.cjs");
48
49
  var { FidoMds3Error } = require("../framework-error");
@@ -239,7 +240,10 @@ function _validateChain(x5c, rootPems) {
239
240
  var root;
240
241
  try { root = new nodeCrypto.X509Certificate(rootPems[r]); }
241
242
  catch (_e) { continue; }
242
- if (tail.checkIssued(root) && tail.verify(root.publicKey)) {
243
+ // issuerValidlyIssued enforces basicConstraints cA:TRUE on the root in
244
+ // addition to the issuance + signature linkage — a non-CA cert cannot
245
+ // anchor the x5c chain (basicConstraints bypass, CVE-2002-0862 class).
246
+ if (x509Chain.issuerValidlyIssued(root, tail)) {
243
247
  anchored = true;
244
248
  break;
245
249
  }
@@ -117,7 +117,7 @@ function _toKeyObject(pemOrKey, kind) {
117
117
  }
118
118
 
119
119
  function _resolveAlgorithm(alg) {
120
- if (typeof alg !== "string" || !ALGORITHM_TO_NODE[alg]) {
120
+ if (typeof alg !== "string" || !Object.prototype.hasOwnProperty.call(ALGORITHM_TO_NODE, alg)) {
121
121
  throw new AuthError("auth-jwt/unsupported-algorithm",
122
122
  "algorithm must be one of " + SUPPORTED_ALGORITHMS.join(", ") + " (got: " + alg + ")");
123
123
  }
@@ -222,7 +222,7 @@ async function verify(token, opts) {
222
222
  // Validate the allowlist itself — typoed entries should surface here,
223
223
  // not as silent "every token rejected."
224
224
  for (var i = 0; i < allowed.length; i++) {
225
- if (!ALGORITHM_TO_NODE[allowed[i]]) {
225
+ if (!Object.prototype.hasOwnProperty.call(ALGORITHM_TO_NODE, allowed[i])) {
226
226
  throw new AuthError("auth-jwt/unsupported-algorithm",
227
227
  "opts.algorithms[" + i + "] = '" + allowed[i] + "' is not in the supported list (" +
228
228
  SUPPORTED_ALGORITHMS.join(", ") + ")");
@@ -80,6 +80,7 @@
80
80
  */
81
81
 
82
82
  var C = require("../constants");
83
+ var numericBounds = require("../numeric-bounds");
83
84
  var lazyRequire = require("../lazy-require");
84
85
  var requestHelpers = require("../request-helpers");
85
86
  var validateOpts = require("../validate-opts");
@@ -119,7 +120,7 @@ function _requireString(name, val) {
119
120
  }
120
121
 
121
122
  function _requirePositiveInt(name, val) {
122
- if (typeof val !== "number" || !isFinite(val) || val < 1 || Math.floor(val) !== val) {
123
+ if (!numericBounds.isPositiveFiniteInt(val)) {
123
124
  throw _err("BAD_OPT", name + ": expected positive integer, got " +
124
125
  typeof val + " " + JSON.stringify(val));
125
126
  }
@@ -261,7 +262,22 @@ function create(opts) {
261
262
 
262
263
  // ---- Public surface ----
263
264
 
264
- async function recordFailure(key, callOpts) {
265
+ // Per-key serialization of the failure counter (read→increment→write on an
266
+ // async store): concurrent recordFailure calls for the same key would lose
267
+ // updates, letting parallel failures stay under the lockout threshold. A
268
+ // per-key promise chain applies them sequentially in-process.
269
+ var _recordChains = new Map();
270
+ function recordFailure(key, callOpts) {
271
+ var prev = _recordChains.get(key) || Promise.resolve();
272
+ var run = prev.then(function () { return _doRecordFailure(key, callOpts); },
273
+ function () { return _doRecordFailure(key, callOpts); });
274
+ var tail = run.then(function () {}, function () {});
275
+ _recordChains.set(key, tail);
276
+ tail.then(function () { if (_recordChains.get(key) === tail) _recordChains.delete(key); });
277
+ return run;
278
+ }
279
+
280
+ async function _doRecordFailure(key, callOpts) {
265
281
  _requireKey(key);
266
282
  callOpts = callOpts || {};
267
283
  var now = clock();
@@ -385,7 +385,7 @@ function _largeBlobExt(args) {
385
385
  var SUPPORT = { preferred: 1, required: 1 };
386
386
  var modes = 0;
387
387
  if (args.support !== undefined) {
388
- if (!SUPPORT[args.support]) {
388
+ if (!Object.prototype.hasOwnProperty.call(SUPPORT, args.support)) {
389
389
  throw new AuthError("auth-passkey/bad-largeblob-support",
390
390
  "extensions.largeBlob support must be 'preferred' or 'required'");
391
391
  }
@@ -282,7 +282,7 @@ function policy(opts) {
282
282
  // Apply named profile FIRST, then operator opts on top so the
283
283
  // operator can override profile defaults per-field.
284
284
  if (typeof opts.profile === "string" && opts.profile.length > 0) {
285
- if (!POLICY_PROFILES[opts.profile]) {
285
+ if (!Object.prototype.hasOwnProperty.call(POLICY_PROFILES, opts.profile)) {
286
286
  throw new AuthError("auth-password/bad-policy",
287
287
  "policy.profile must be one of " + Object.keys(POLICY_PROFILES).join("/") +
288
288
  ", got " + JSON.stringify(opts.profile));
@@ -170,7 +170,7 @@ function _verifyXmldsig(envelope, signatureNode, certPem) {
170
170
  }
171
171
  var sigMethodNode = _findChild(signedInfo, "SignatureMethod");
172
172
  var sigAlgo = sigMethodNode && _attr(sigMethodNode, "Algorithm");
173
- if (!SUPPORTED_SIG[sigAlgo]) {
173
+ if (!Object.prototype.hasOwnProperty.call(SUPPORTED_SIG, sigAlgo)) {
174
174
  throw new AuthError("auth-saml/unsupported-sig-alg",
175
175
  "Unsupported SignatureMethod: " + sigAlgo);
176
176
  }
@@ -184,7 +184,7 @@ function _verifyXmldsig(envelope, signatureNode, certPem) {
184
184
  var refId = refUri.substring(1);
185
185
  var digestMethodNode = _findChild(refNode, "DigestMethod");
186
186
  var digestAlgo = digestMethodNode && _attr(digestMethodNode, "Algorithm");
187
- if (!SUPPORTED_DIGEST[digestAlgo]) {
187
+ if (!Object.prototype.hasOwnProperty.call(SUPPORTED_DIGEST, digestAlgo)) {
188
188
  throw new AuthError("auth-saml/unsupported-digest",
189
189
  "Unsupported DigestMethod: " + digestAlgo);
190
190
  }
@@ -745,26 +745,46 @@ function create(opts) {
745
745
  var cNotOnOrAfter = _attr(conditions, "NotOnOrAfter");
746
746
  if (cNotBefore) {
747
747
  var cnb = Date.parse(cNotBefore) / 1000; // ms→s
748
- if (isFinite(cnb) && cnb > nowSec + clockSkewSec) {
748
+ // Fail CLOSED on a present-but-unparseable bound (mirrors the Bearer
749
+ // SCD path at line ~708) instead of skipping the window via isFinite().
750
+ if (!isFinite(cnb)) {
751
+ throw new AuthError("auth-saml/conditions-bad-timestamp",
752
+ "Conditions NotBefore is present but unparseable");
753
+ }
754
+ if (cnb > nowSec + clockSkewSec) {
749
755
  throw new AuthError("auth-saml/conditions-not-yet-valid",
750
756
  "Conditions NotBefore is in the future");
751
757
  }
752
758
  }
753
759
  if (cNotOnOrAfter) {
754
760
  var cnoa = Date.parse(cNotOnOrAfter) / 1000; // ms→s
755
- if (isFinite(cnoa) && cnoa < nowSec - clockSkewSec) {
761
+ if (!isFinite(cnoa)) {
762
+ throw new AuthError("auth-saml/conditions-bad-timestamp",
763
+ "Conditions NotOnOrAfter is present but unparseable");
764
+ }
765
+ if (cnoa < nowSec - clockSkewSec) {
756
766
  throw new AuthError("auth-saml/conditions-expired",
757
767
  "Conditions NotOnOrAfter has passed");
758
768
  }
759
769
  }
760
- var ar = _findChild(conditions, "AudienceRestriction", SAML_NS.assertion);
761
- if (ar) {
762
- var audiences = _findAllChildren(ar, "Audience", SAML_NS.assertion).map(_textContent);
763
- if (audiences.indexOf(audience) === -1) {
764
- throw new AuthError("auth-saml/wrong-audience",
765
- "Audience \"" + audience + "\" not in assertion's AudienceRestriction (got " +
766
- JSON.stringify(audiences) + ")");
767
- }
770
+ }
771
+ // Audience binding — a signed assertion is bound to THIS SP via
772
+ // AudienceRestriction. A missing Conditions or AudienceRestriction means
773
+ // it is not bound here (audience-confusion: an assertion minted for another
774
+ // SP). Fail closed when an audience is configured; opt out only via
775
+ // vopts.requireAudienceRestriction === false.
776
+ if (audience && vopts.requireAudienceRestriction !== false) {
777
+ var ar = conditions && _findChild(conditions, "AudienceRestriction", SAML_NS.assertion);
778
+ if (!ar) {
779
+ throw new AuthError("auth-saml/no-audience-restriction",
780
+ "verifyResponse: assertion has no AudienceRestriction binding it to \"" +
781
+ audience + "\" (audience-confusion defense; set requireAudienceRestriction:false to opt out)");
782
+ }
783
+ var audiences = _findAllChildren(ar, "Audience", SAML_NS.assertion).map(_textContent);
784
+ if (audiences.indexOf(audience) === -1) {
785
+ throw new AuthError("auth-saml/wrong-audience",
786
+ "Audience \"" + audience + "\" not in assertion's AudienceRestriction (got " +
787
+ JSON.stringify(audiences) + ")");
768
788
  }
769
789
  }
770
790
 
@@ -1897,7 +1917,7 @@ function _verifyEmbeddedXmlDsig(xml, idpVerifyKey, idpVerifyAlg, expectedRootLoc
1897
1917
  // Allow either sha3-512 (framework default) or the SHA-2 family.
1898
1918
  var digestAlgName;
1899
1919
  if (digestUri === "http://www.w3.org/2007/05/xmldsig-more#sha3-512") digestAlgName = "sha3-512";
1900
- else if (SUPPORTED_DIGEST[digestUri]) digestAlgName = SUPPORTED_DIGEST[digestUri];
1920
+ else if (Object.prototype.hasOwnProperty.call(SUPPORTED_DIGEST, digestUri)) digestAlgName = SUPPORTED_DIGEST[digestUri];
1901
1921
  else {
1902
1922
  throw new AuthError("auth-saml/unsupported-digest",
1903
1923
  "_verifyEmbeddedXmlDsig: DigestMethod " + digestUri + " not supported");
@@ -212,7 +212,7 @@ function issue(opts) {
212
212
  "issue: algorithm must be one of " + SUPPORTED_ALGS.join(", "));
213
213
  }
214
214
  var hashAlg = opts.hashAlg || DEFAULT_HASH_ALG;
215
- if (!SUPPORTED_HASH_ALGS[hashAlg]) {
215
+ if (!Object.prototype.hasOwnProperty.call(SUPPORTED_HASH_ALGS, hashAlg)) {
216
216
  throw new AuthError("auth-sd-jwt-vc/bad-hash",
217
217
  "issue: hashAlg must be one of " + Object.keys(SUPPORTED_HASH_ALGS).join(", "));
218
218
  }
@@ -413,8 +413,8 @@ async function verify(presentation, opts) {
413
413
  validateOpts.requireObject(opts, "auth.sdJwtVc.verify", AuthError);
414
414
  validateOpts(opts, [
415
415
  "issuerKeyResolver", "audience", "nonce",
416
- "now", "expectedVct", "maxClockSkewSec",
417
- "requireKeyBinding",
416
+ "now", "expectedVct", "expectedIssuer", "maxClockSkewSec",
417
+ "requireKeyBinding", "requireExp",
418
418
  "keyAttestationVerifier", "requireKeyAttestation",
419
419
  ], "auth.sdJwtVc.verify");
420
420
 
@@ -528,6 +528,15 @@ async function verify(presentation, opts) {
528
528
  throw new AuthError("auth-sd-jwt-vc/iat-future",
529
529
  "verify: iat is in the future (clock skew?)");
530
530
  }
531
+ // SD-JWT-VC makes `exp` OPTIONAL, so the default only checks it when present.
532
+ // Operators with a time-bounded trust expectation (esp. for FOREIGN issuers
533
+ // resolved via issuerKeyResolver) pass requireExp:true to fail closed on a
534
+ // missing / non-numeric exp — mirroring jwt-external's unconditional exp
535
+ // requirement (a credential that never expires is accepted otherwise).
536
+ if (opts.requireExp === true && typeof jwtParsed.payload.exp !== "number") {
537
+ throw new AuthError("auth-sd-jwt-vc/missing-exp",
538
+ "verify: requireExp is set but the credential has no numeric exp claim");
539
+ }
531
540
  if (typeof jwtParsed.payload.exp === "number" && jwtParsed.payload.exp < nowSec - skew) {
532
541
  throw new AuthError("auth-sd-jwt-vc/expired",
533
542
  "verify: token is expired");
@@ -556,7 +565,7 @@ async function verify(presentation, opts) {
556
565
  // to its own DEFAULT_HASH_ALG (`sha3-512`) which broke verification
557
566
  // against spec-conformant issuers when `_sd_alg` was omitted.
558
567
  var hashAlg = jwtParsed.payload._sd_alg || "sha-256";
559
- if (!SUPPORTED_HASH_ALGS[hashAlg]) {
568
+ if (!Object.prototype.hasOwnProperty.call(SUPPORTED_HASH_ALGS, hashAlg)) {
560
569
  throw new AuthError("auth-sd-jwt-vc/bad-hash",
561
570
  "verify: _sd_alg \"" + hashAlg + "\" not supported");
562
571
  }
@@ -638,6 +647,17 @@ async function verify(presentation, opts) {
638
647
  jwtExternal._assertAlgKtyMatch(kbAlg, holderKey);
639
648
  var holderKeyObj = bCrypto.importPublicJwk(holderKey);
640
649
  var kbParsed = _verifyJwt(maybeKbJwt, holderKeyObj, kbAlg);
650
+ // A KB-JWT proves holder possession of THIS presentation's bytes (sd_hash),
651
+ // but binds it to a verifier + a fresh challenge only via aud + nonce. If
652
+ // the caller processes a KB-JWT without supplying both, the aud/nonce
653
+ // compares below would silently skip — making the presentation replayable
654
+ // and acceptable at any verifier. Fail CLOSED: require both (oid4vp always
655
+ // supplies them). RFC: SD-JWT-VC §KB-JWT / OIDC4VP nonce binding.
656
+ if (typeof opts.audience !== "string" || opts.audience.length === 0 ||
657
+ typeof opts.nonce !== "string" || opts.nonce.length === 0) {
658
+ throw new AuthError("auth-sd-jwt-vc/missing-replay-binding",
659
+ "verify: a KB-JWT requires opts.audience + opts.nonce to bind the presentation to this verifier and a fresh challenge (replay / audience-redirection defense)");
660
+ }
641
661
  // Constant-time compares: the nonce is a verifier-issued replay-defense
642
662
  // value, so a short-circuiting !== leaks a matching-prefix timing oracle.
643
663
  // Matches the sd_hash check below (the framework's hash/token discipline).
@@ -78,7 +78,7 @@ var _fromB64url = bCrypto.makeBase64UrlDecoder({
78
78
  });
79
79
 
80
80
  function _validateBits(bits) {
81
- if (!SUPPORTED_BIT_SIZES[bits]) {
81
+ if (!Object.prototype.hasOwnProperty.call(SUPPORTED_BIT_SIZES, bits)) {
82
82
  throw new StatusListError("status-list/bad-bits",
83
83
  "statusList: bits must be 1, 2, 4, or 8 (draft §6.1.1) — got " + bits);
84
84
  }
@@ -249,7 +249,19 @@ async function fromJwt(token, opts) {
249
249
  list: {
250
250
  size: size,
251
251
  bits: bits,
252
- get: function (idx) { return _getAt(inflated, bits, idx); },
252
+ // Bounds-check the relying-party status read, mirroring create().get. An
253
+ // out-of-range index must FAIL CLOSED (throw): _getAt over-reads the buffer
254
+ // and returns 0 for an out-of-bounds index, and status 0 = VALID — so a
255
+ // credential whose status_list index points past the list would otherwise
256
+ // read as "not revoked", a revocation bypass.
257
+ get: function (idx) {
258
+ if (typeof idx !== "number" || idx < 0 || idx >= size || (idx >> 0) !== idx) {
259
+ throw new StatusListError("status-list/bad-index",
260
+ "statusList.fromJwt get: idx out of range — got " + idx + ", size=" + size +
261
+ " (an out-of-range status index fails closed, never reads as status 0/valid)");
262
+ }
263
+ return _getAt(inflated, bits, idx);
264
+ },
253
265
  snapshot: function () { return { size: size, bits: bits, bytes: Buffer.from(inflated) }; },
254
266
  },
255
267
  claims: claims,
@@ -386,7 +386,15 @@ function parseChallenge(headerValue) {
386
386
  if (key === "error") out.error = val;
387
387
  else if (key === "scope") out.scope = val;
388
388
  else if (key === "acr_values") out.acrValues = val.split(/\s+/);
389
- else if (key === "max_age") out.maxAge = parseInt(val, 10);
389
+ else if (key === "max_age") {
390
+ // Defensive: a malformed max_age (non-numeric / negative) from the
391
+ // server's challenge must not land as NaN — a downstream `age > maxAge`
392
+ // comparison against NaN is always false and would silently mis-handle
393
+ // the freshness requirement. Omit it unless it parses to a non-negative
394
+ // integer, so callers fall back to their own default.
395
+ var ma = parseInt(val, 10);
396
+ if (isFinite(ma) && ma >= 0) out.maxAge = ma;
397
+ }
390
398
  });
391
399
  return out;
392
400
  }
@@ -40,6 +40,7 @@ var C = require("./constants");
40
40
  var lazyRequire = require("./lazy-require");
41
41
  var requestHelpers = require("./request-helpers");
42
42
  var validateOpts = require("./validate-opts");
43
+ var numericBounds = require("./numeric-bounds");
43
44
  var { AuthBotChallengeError } = require("./framework-error");
44
45
 
45
46
  var observability = lazyRequire(function () { return require("./observability"); });
@@ -67,7 +68,7 @@ function _requireFunction(name, val) {
67
68
  }
68
69
 
69
70
  function _requirePositiveInt(name, val) {
70
- if (typeof val !== "number" || !isFinite(val) || val < 1 || Math.floor(val) !== val) {
71
+ if (!numericBounds.isPositiveFiniteInt(val)) {
71
72
  throw new AuthBotChallengeError("auth-bot-challenge/bad-opt",
72
73
  name + ": expected positive integer, got " + JSON.stringify(val));
73
74
  }
@@ -272,7 +273,25 @@ function create(opts) {
272
273
 
273
274
  // ---- Internal staircase advance ----
274
275
 
275
- async function _advanceFailure(key, req) {
276
+ // Per-key serialization: the failure staircase is a read→increment→write on
277
+ // an async store, so concurrent recordFailure calls for the SAME key would
278
+ // both read N and both write N+1 (lost update), letting an attacker fire
279
+ // parallel failures to stay under the challenge / lockout thresholds. A
280
+ // per-key promise chain applies advances for a key sequentially. (Cross-node
281
+ // atomicity additionally needs an atomic store; this fixes the in-process
282
+ // race the gate actually depends on.)
283
+ var _advanceChains = new Map();
284
+ function _advanceFailure(key, req) {
285
+ var prev = _advanceChains.get(key) || Promise.resolve();
286
+ var run = prev.then(function () { return _doAdvanceFailure(key, req); },
287
+ function () { return _doAdvanceFailure(key, req); });
288
+ var tail = run.then(function () {}, function () {});
289
+ _advanceChains.set(key, tail);
290
+ tail.then(function () { if (_advanceChains.get(key) === tail) _advanceChains.delete(key); });
291
+ return run;
292
+ }
293
+
294
+ async function _doAdvanceFailure(key, req) {
276
295
  var now = clock();
277
296
  var state = await _readState(key) || {
278
297
  stage: STATE_NEW, failures: 0, challengedAt: null, passedAt: null,
@@ -160,14 +160,18 @@ async function create(opts) {
160
160
  },
161
161
  });
162
162
  var checksum = bCrypto.checksum(plain);
163
- var encResult = await bCrypto.encryptWithFreshSalt(plain, passphrase);
163
+ // Bind the ciphertext to this blob's canonical relativePath as AEAD
164
+ // associated data. A blob copied to a different manifest entry (the
165
+ // restore-corruption / blob-remap attack) then fails the Poly1305 tag on
166
+ // restore — tamper-evident even on an unsigned bundle (manifest.aadBound).
167
+ var encResult = await bCrypto.encryptWithFreshSalt(plain, passphrase, entry.relativePath);
164
168
  var encPath = _encryptedPathFor(entry.relativePath);
165
169
  var destFull = nodePath.join(outDir, encPath);
166
170
  atomicFile.ensureDir(nodePath.dirname(destFull));
167
171
  atomicFile.writeSync(destFull, encResult.encrypted, { fileMode: 0o600 });
168
172
 
169
173
  var kind = entry.kind || "raw";
170
- if (!backupManifest.VALID_KINDS[kind]) {
174
+ if (!Object.prototype.hasOwnProperty.call(backupManifest.VALID_KINDS, kind)) {
171
175
  throw new BackupBundleError("backup-bundle/bad-kind",
172
176
  "create: files[" + i + "].kind must be one of raw, vault-sealed, plaintext (got '" + kind + "')");
173
177
  }
@@ -205,6 +209,7 @@ async function create(opts) {
205
209
  vaultKeyEnc: wrappedVk.encrypted.toString("base64"),
206
210
  files: fileEntries,
207
211
  metadata: opts.metadata || undefined,
212
+ aadBound: true, // every blob above was sealed with its relativePath as AEAD AAD
208
213
  });
209
214
  // Sign the manifest with the audit-sign keypair so a tampered
210
215
  // manifest fails verification on restore. The signer is best-
@@ -117,7 +117,21 @@ async function deriveKey(passphrase, saltHex, opts) {
117
117
  return hash;
118
118
  }
119
119
 
120
- async function encryptWithPassphrase(plaintext, passphrase, saltHex) {
120
+ // Normalize optional associated-authenticated-data (AAD) into the
121
+ // Uint8Array the AEAD expects, or undefined when none. AAD is NOT encrypted
122
+ // but IS authenticated: ciphertext sealed under one AAD fails the Poly1305
123
+ // tag when decrypted under a different AAD. Backup file blobs pass their
124
+ // canonical relativePath so a blob remapped to a different manifest entry is
125
+ // cryptographically rejected (the blob-remap / restore-corruption defense).
126
+ function _aadBytes(aad) {
127
+ if (aad === undefined || aad === null) return undefined;
128
+ if (Buffer.isBuffer(aad)) return new Uint8Array(aad);
129
+ if (typeof aad === "string") return new Uint8Array(Buffer.from(aad, "utf8"));
130
+ throw new BackupCryptoError("backup-crypto/bad-aad",
131
+ "associated data must be a Buffer or string");
132
+ }
133
+
134
+ async function encryptWithPassphrase(plaintext, passphrase, saltHex, aad) {
121
135
  if (!Buffer.isBuffer(plaintext) && typeof plaintext !== "string") {
122
136
  throw new BackupCryptoError("backup-crypto/bad-plaintext",
123
137
  "encryptWithPassphrase: plaintext must be a Buffer or string");
@@ -125,11 +139,11 @@ async function encryptWithPassphrase(plaintext, passphrase, saltHex) {
125
139
  var plainBuf = Buffer.isBuffer(plaintext) ? plaintext : Buffer.from(plaintext, "utf8");
126
140
  var key = await deriveKey(passphrase, saltHex);
127
141
  var nonce = nodeCrypto.randomBytes(NONCE_BYTES);
128
- var ct = xchacha20poly1305(new Uint8Array(key), nonce).encrypt(new Uint8Array(plainBuf));
142
+ var ct = xchacha20poly1305(new Uint8Array(key), nonce, _aadBytes(aad)).encrypt(new Uint8Array(plainBuf));
129
143
  return Buffer.concat([nonce, Buffer.from(ct)]);
130
144
  }
131
145
 
132
- async function decryptWithPassphrase(encrypted, passphrase, saltHex) {
146
+ async function decryptWithPassphrase(encrypted, passphrase, saltHex, aad) {
133
147
  if (!Buffer.isBuffer(encrypted)) {
134
148
  throw new BackupCryptoError("backup-crypto/bad-input",
135
149
  "decryptWithPassphrase: encrypted must be a Buffer");
@@ -143,11 +157,11 @@ async function decryptWithPassphrase(encrypted, passphrase, saltHex) {
143
157
  var ct = encrypted.subarray(NONCE_BYTES);
144
158
  var plain;
145
159
  try {
146
- plain = xchacha20poly1305(new Uint8Array(key), new Uint8Array(nonce))
160
+ plain = xchacha20poly1305(new Uint8Array(key), new Uint8Array(nonce), _aadBytes(aad))
147
161
  .decrypt(new Uint8Array(ct));
148
162
  } catch (e) {
149
163
  throw new BackupCryptoError("backup-crypto/decrypt-failed",
150
- "XChaCha20-Poly1305 decryption failed (wrong passphrase or tampered ciphertext): " +
164
+ "XChaCha20-Poly1305 decryption failed (wrong passphrase, tampered ciphertext, or blob remapped to a different path): " +
151
165
  ((e && e.message) || String(e)));
152
166
  }
153
167
  return Buffer.from(plain);
@@ -155,11 +169,12 @@ async function decryptWithPassphrase(encrypted, passphrase, saltHex) {
155
169
 
156
170
  // Convenience for the common "encrypt this with a fresh salt" pattern.
157
171
  // Returns the salt as hex so callers can store it alongside the
158
- // ciphertext in the bundle manifest.
159
- async function encryptWithFreshSalt(plaintext, passphrase) {
172
+ // ciphertext in the bundle manifest. `aad` (optional) is bound as AEAD
173
+ // associated data (see _aadBytes).
174
+ async function encryptWithFreshSalt(plaintext, passphrase, aad) {
160
175
  var salt = nodeCrypto.randomBytes(SALT_BYTES);
161
176
  var saltHex = salt.toString("hex");
162
- var encrypted = await encryptWithPassphrase(plaintext, passphrase, saltHex);
177
+ var encrypted = await encryptWithPassphrase(plaintext, passphrase, saltHex, aad);
163
178
  return { encrypted: encrypted, salt: saltHex };
164
179
  }
165
180