@blamejs/blamejs-shop 0.4.30 → 0.4.32

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 (338) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/checkout.js +8 -0
  4. package/lib/order.js +71 -11
  5. package/lib/vendor/MANIFEST.json +392 -278
  6. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  7. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  8. package/lib/vendor/blamejs/.gitignore +6 -0
  9. package/lib/vendor/blamejs/CHANGELOG.md +26 -0
  10. package/lib/vendor/blamejs/MIGRATING.md +43 -0
  11. package/lib/vendor/blamejs/README.md +8 -6
  12. package/lib/vendor/blamejs/SECURITY.md +19 -3
  13. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  14. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  15. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  16. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  17. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  18. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  19. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  20. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  21. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  25. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  26. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  27. package/lib/vendor/blamejs/index.js +4 -0
  28. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  29. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  30. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  31. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  32. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  33. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  34. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  35. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  36. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  37. package/lib/vendor/blamejs/lib/audit.js +259 -123
  38. package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
  39. package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
  40. package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
  41. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
  42. package/lib/vendor/blamejs/lib/backup/index.js +45 -10
  43. package/lib/vendor/blamejs/lib/break-glass.js +355 -147
  44. package/lib/vendor/blamejs/lib/cache.js +174 -105
  45. package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
  46. package/lib/vendor/blamejs/lib/cli.js +19 -14
  47. package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
  48. package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
  49. package/lib/vendor/blamejs/lib/cluster.js +119 -71
  50. package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
  51. package/lib/vendor/blamejs/lib/compliance.js +206 -4
  52. package/lib/vendor/blamejs/lib/consent.js +82 -29
  53. package/lib/vendor/blamejs/lib/constants.js +27 -11
  54. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  55. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  56. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  57. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  58. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  59. package/lib/vendor/blamejs/lib/db.js +249 -99
  60. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  61. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  62. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  63. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  64. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  65. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  66. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  67. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  68. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  69. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  70. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  71. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  72. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  73. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  74. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  75. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  76. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  77. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  78. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  79. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  80. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  81. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  82. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  83. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  84. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  85. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  86. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  87. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  88. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  89. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  90. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  91. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  92. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  93. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  94. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  95. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  96. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  97. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  98. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  99. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  100. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  101. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  102. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  103. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  104. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  105. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  106. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  107. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  108. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  109. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  110. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  111. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  112. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  113. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  114. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  115. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  116. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  117. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  118. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  119. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  120. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  121. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  122. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  123. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  124. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  125. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  126. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  127. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  128. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  129. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  131. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  132. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  133. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  134. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  135. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  136. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  137. package/lib/vendor/blamejs/lib/mail.js +8 -4
  138. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  139. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  140. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  141. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  142. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  143. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  144. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  145. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  146. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  147. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  148. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  149. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  150. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  151. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  152. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  153. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  154. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  155. package/lib/vendor/blamejs/lib/observability.js +124 -0
  156. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  157. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  158. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  159. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  160. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  161. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  162. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  163. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  164. package/lib/vendor/blamejs/lib/queue.js +7 -0
  165. package/lib/vendor/blamejs/lib/redact.js +68 -11
  166. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  167. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  168. package/lib/vendor/blamejs/lib/retention.js +101 -40
  169. package/lib/vendor/blamejs/lib/router.js +212 -5
  170. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  171. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  172. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  173. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  174. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  175. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  176. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  177. package/lib/vendor/blamejs/lib/scheduler.js +35 -12
  178. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  179. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  180. package/lib/vendor/blamejs/lib/session.js +175 -77
  181. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  182. package/lib/vendor/blamejs/lib/sse.js +26 -0
  183. package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
  184. package/lib/vendor/blamejs/lib/static.js +177 -34
  185. package/lib/vendor/blamejs/lib/subject.js +96 -49
  186. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  187. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  188. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  189. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  190. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  191. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  192. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  193. package/lib/vendor/blamejs/package.json +2 -2
  194. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  195. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  200. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  201. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  202. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  203. package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
  204. package/lib/vendor/blamejs/scripts/release.js +398 -38
  205. package/lib/vendor/blamejs/test/00-primitives.js +117 -0
  206. package/lib/vendor/blamejs/test/10-state.js +140 -14
  207. package/lib/vendor/blamejs/test/20-db.js +65 -2
  208. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  209. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  210. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  211. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  212. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  213. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  214. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  215. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  216. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  217. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  220. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  221. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  222. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  223. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  224. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  225. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  226. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  227. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  228. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  229. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  230. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  231. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  232. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  233. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  234. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  235. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  236. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  237. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  238. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  240. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  250. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
  251. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  256. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  260. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  261. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  272. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  273. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  274. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  275. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  279. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  280. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  283. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  284. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  285. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  293. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  304. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  310. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  312. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  313. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  314. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  315. package/lib/vendor/blamejs/test/smoke.js +79 -21
  316. package/package.json +1 -1
  317. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  318. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  319. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  320. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  321. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  322. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  323. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  324. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  325. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  326. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  327. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  328. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  329. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  330. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  331. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  332. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  333. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  334. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  335. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  336. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  337. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  338. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+ /**
3
+ * b.auth.saml.sp.verifyResponse — SubjectConfirmationData NotOnOrAfter
4
+ * is mandatory and must fail closed.
5
+ *
6
+ * SAML 2.0 Web Browser SSO Profile §4.1.4.2 requires every Bearer
7
+ * SubjectConfirmationData to carry a `NotOnOrAfter` attribute that
8
+ * bounds the assertion's freshness window. A SubjectConfirmationData
9
+ * with no NotOnOrAfter — or an unparseable one — must be rejected:
10
+ * accepting it grants an unbounded, replay-forever confirmation. The
11
+ * Holder-of-Key confirmation (Profile §3.1, which incorporates the
12
+ * §3 time-bounding by reference) has the same requirement.
13
+ *
14
+ * These tests drive the shipped consumer path:
15
+ * sp = b.auth.saml.sp.create({ ... }); sp.verifyResponse(b64, vopts).
16
+ * They mint a self-signed RSA IdP cert, build a genuinely XMLDSig-
17
+ * signed SAML Response (digest + SignatureValue computed through the
18
+ * framework's own b.xmlC14n so the verifier's recomputation matches),
19
+ * and vary ONLY the SubjectConfirmationData's NotOnOrAfter between the
20
+ * accepted and refused cases.
21
+ */
22
+
23
+ var helpers = require("../helpers");
24
+ var check = helpers.check;
25
+ var b = helpers.b;
26
+ var nodeCrypto = require("node:crypto");
27
+ var c14n = require("../../lib/xml-c14n");
28
+
29
+ var DS = "http://www.w3.org/2000/09/xmldsig#";
30
+ var EXC = "http://www.w3.org/2001/10/xml-exc-c14n#";
31
+
32
+ var IDP_ENTITY_ID = "https://idp.example";
33
+ var SP_ENTITY_ID = "https://sp.example";
34
+ var ACS_URL = "https://sp.example/saml/acs";
35
+
36
+ // Mint a self-signed RSA cert via the vendored @peculiar/x509 bundle.
37
+ // verifyResponse parses idpCertPem with nodeCrypto.createPublicKey and
38
+ // verifies an rsa-sha256 PKCS1 signature, so a real RSA cert + matching
39
+ // private key is required — there is no test bypass of the signature
40
+ // check.
41
+ async function _mintRsaCert(cn) {
42
+ var pki = require("../../lib/vendor/pki.cjs");
43
+ var x509 = pki.x509;
44
+ var keys = await nodeCrypto.webcrypto.subtle.generateKey(
45
+ { name: "RSASSA-PKCS1-v1_5", modulusLength: 2048, // allow:raw-byte-literal — RFC 8301 §3.1 RSA bit floor
46
+ publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" },
47
+ true, ["sign", "verify"]);
48
+ var now = new Date();
49
+ var cert = await x509.X509CertificateGenerator.createSelfSigned({
50
+ serialNumber: "01",
51
+ name: "CN=" + cn,
52
+ notBefore: now,
53
+ notAfter: new Date(now.getTime() + 365 * 24 * 3600 * 1000), // allow:raw-time-literal — 1y fixture validity
54
+ signingAlgorithm: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
55
+ keys: keys,
56
+ });
57
+ var pkcs8 = await nodeCrypto.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
58
+ var keyPem = "-----BEGIN PRIVATE KEY-----\n" +
59
+ Buffer.from(pkcs8).toString("base64").match(/.{1,64}/g).join("\n") +
60
+ "\n-----END PRIVATE KEY-----\n";
61
+ return { certPem: cert.toString("pem"), keyPem: keyPem };
62
+ }
63
+
64
+ function _isoFromNow(ms) { return new Date(Date.now() + ms).toISOString(); }
65
+
66
+ // Build a SAML Response with an Assertion-level enveloped XMLDSig
67
+ // signature. The Assertion's Signature child is stripped before the
68
+ // digest (the enveloped-signature transform), and both the digest and
69
+ // the SignedInfo are canonicalized through b.xmlC14n so the values
70
+ // match exactly what verifyResponse recomputes.
71
+ function _buildSignedResponse(idp, parts) {
72
+ var assertionId = "_assertion-" + parts.tag;
73
+ var responseId = "_response-" + parts.tag;
74
+ var issueInstant = _isoFromNow(0);
75
+ var subjectConfirmation =
76
+ "<saml:SubjectConfirmation Method=\"" + parts.method + "\">" +
77
+ parts.scd +
78
+ "</saml:SubjectConfirmation>";
79
+
80
+ var assertionInner =
81
+ "<saml:Issuer>" + IDP_ENTITY_ID + "</saml:Issuer>" +
82
+ "SIGNATURE_PLACEHOLDER" +
83
+ "<saml:Subject>" +
84
+ "<saml:NameID Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress\">" +
85
+ parts.nameId + "</saml:NameID>" +
86
+ subjectConfirmation +
87
+ "</saml:Subject>" +
88
+ "<saml:Conditions NotBefore=\"" + _isoFromNow(-5 * 60 * 1000) + // allow:raw-time-literal — 5m skew window
89
+ "\" NotOnOrAfter=\"" + _isoFromNow(5 * 60 * 1000) + "\">" + // allow:raw-time-literal — 5m skew window
90
+ "<saml:AudienceRestriction><saml:Audience>" + SP_ENTITY_ID +
91
+ "</saml:Audience></saml:AudienceRestriction>" +
92
+ "</saml:Conditions>" +
93
+ "<saml:AuthnStatement SessionIndex=\"_sess-1\" AuthnInstant=\"" + issueInstant + "\">" +
94
+ "<saml:AuthnContext><saml:AuthnContextClassRef>" +
95
+ "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" +
96
+ "</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement>";
97
+
98
+ var assertionOpen =
99
+ "<saml:Assertion xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" " +
100
+ "ID=\"" + assertionId + "\" Version=\"2.0\" IssueInstant=\"" + issueInstant + "\">";
101
+ var assertionClose = "</saml:Assertion>";
102
+
103
+ // Digest the assertion with no Signature child (enveloped-signature
104
+ // transform output), canonicalized through b.xmlC14n.
105
+ var assertionNoSig = assertionOpen +
106
+ assertionInner.replace("SIGNATURE_PLACEHOLDER", "") + assertionClose;
107
+ var digest = nodeCrypto.createHash("sha256")
108
+ .update(c14n.canonicalize(assertionNoSig)).digest("base64");
109
+
110
+ var signedInfo =
111
+ "<ds:SignedInfo xmlns:ds=\"" + DS + "\">" +
112
+ "<ds:CanonicalizationMethod Algorithm=\"" + EXC + "\"></ds:CanonicalizationMethod>" +
113
+ "<ds:SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\"></ds:SignatureMethod>" +
114
+ "<ds:Reference URI=\"#" + assertionId + "\">" +
115
+ "<ds:Transforms>" +
116
+ "<ds:Transform Algorithm=\"http://www.w3.org/2000/09/xmldsig#enveloped-signature\"></ds:Transform>" +
117
+ "<ds:Transform Algorithm=\"" + EXC + "\"></ds:Transform>" +
118
+ "</ds:Transforms>" +
119
+ "<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#sha256\"></ds:DigestMethod>" +
120
+ "<ds:DigestValue>" + digest + "</ds:DigestValue>" +
121
+ "</ds:Reference>" +
122
+ "</ds:SignedInfo>";
123
+ var priv = nodeCrypto.createPrivateKey({ key: idp.keyPem, format: "pem" });
124
+ var sigValue = nodeCrypto.sign("sha256", c14n.canonicalize(signedInfo),
125
+ { key: priv, padding: nodeCrypto.constants.RSA_PKCS1_PADDING }).toString("base64");
126
+
127
+ var signatureXml =
128
+ "<ds:Signature xmlns:ds=\"" + DS + "\">" + signedInfo +
129
+ "<ds:SignatureValue>" + sigValue + "</ds:SignatureValue></ds:Signature>";
130
+ var assertionFull = assertionOpen +
131
+ assertionInner.replace("SIGNATURE_PLACEHOLDER", signatureXml) + assertionClose;
132
+
133
+ var response =
134
+ "<samlp:Response xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" " +
135
+ "xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" " +
136
+ "ID=\"" + responseId + "\" Version=\"2.0\" IssueInstant=\"" + issueInstant + "\" " +
137
+ "Destination=\"" + ACS_URL + "\">" +
138
+ "<saml:Issuer>" + IDP_ENTITY_ID + "</saml:Issuer>" +
139
+ "<samlp:Status><samlp:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\"/></samlp:Status>" +
140
+ assertionFull + "</samlp:Response>";
141
+
142
+ return Buffer.from(response, "utf8").toString("base64");
143
+ }
144
+
145
+ function _bearerScd(notOnOrAfterAttr, inResponseTo) {
146
+ return "<saml:SubjectConfirmationData" + notOnOrAfterAttr +
147
+ " Recipient=\"" + ACS_URL + "\"" +
148
+ " InResponseTo=\"" + inResponseTo + "\"/>";
149
+ }
150
+
151
+ function _certBodyB64(pem) {
152
+ return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
153
+ .replace(/-----END CERTIFICATE-----/, "")
154
+ .replace(/\s+/g, "");
155
+ }
156
+
157
+ function _hokScd(notOnOrAfterAttr, holderCertPem) {
158
+ return "<saml:SubjectConfirmationData" + notOnOrAfterAttr +
159
+ " Recipient=\"" + ACS_URL + "\">" +
160
+ "<ds:KeyInfo xmlns:ds=\"" + DS + "\"><ds:X509Data><ds:X509Certificate>" +
161
+ _certBodyB64(holderCertPem) +
162
+ "</ds:X509Certificate></ds:X509Data></ds:KeyInfo>" +
163
+ "</saml:SubjectConfirmationData>";
164
+ }
165
+
166
+ function _newSp(idp) {
167
+ return b.auth.saml.sp.create({
168
+ entityId: SP_ENTITY_ID,
169
+ assertionConsumerServiceUrl: ACS_URL,
170
+ idpEntityId: IDP_ENTITY_ID,
171
+ idpSsoUrl: "https://idp.example/sso",
172
+ idpCertPem: idp.certPem,
173
+ });
174
+ }
175
+
176
+ function _verifyThrows(sp, b64, vopts) {
177
+ try { sp.verifyResponse(b64, vopts); return null; }
178
+ catch (e) { return e.code || e.message; }
179
+ }
180
+
181
+ // Case 1 — a valid future NotOnOrAfter succeeds. Proves the signer +
182
+ // harness are correct and the fail-closed fix does not break the
183
+ // happy path.
184
+ async function testBearerValidNotOnOrAfterAccepted() {
185
+ var idp = await _mintRsaCert("idp.example");
186
+ var sp = _newSp(idp);
187
+ var inResponseTo = "_req-valid";
188
+ var b64 = _buildSignedResponse(idp, {
189
+ tag: "bearer-valid",
190
+ method: "urn:oasis:names:tc:SAML:2.0:cm:bearer",
191
+ nameId: "alice@example.com",
192
+ scd: _bearerScd(" NotOnOrAfter=\"" + _isoFromNow(5 * 60 * 1000) + "\"", inResponseTo), // allow:raw-time-literal — 5m future
193
+ });
194
+ var info = sp.verifyResponse(b64, { expectedInResponseTo: inResponseTo });
195
+ check("Bearer with valid NotOnOrAfter verifies", info && typeof info === "object");
196
+ check("Bearer valid: nameId returned", info.nameId === "alice@example.com");
197
+ check("Bearer valid: issuer matches IdP entityID", info.issuer === IDP_ENTITY_ID);
198
+ check("Bearer valid: inResponseTo captured", info.inResponseTo === inResponseTo);
199
+ }
200
+
201
+ // Case 2 — a Bearer SubjectConfirmationData with NO NotOnOrAfter must
202
+ // be refused (§4.1.4.2). This is the RED case: on the unfixed tree the
203
+ // confirmation is wrongly accepted as fresh-forever.
204
+ async function testBearerMissingNotOnOrAfterRefused() {
205
+ var idp = await _mintRsaCert("idp.example");
206
+ var sp = _newSp(idp);
207
+ var inResponseTo = "_req-missing";
208
+ var b64 = _buildSignedResponse(idp, {
209
+ tag: "bearer-missing",
210
+ method: "urn:oasis:names:tc:SAML:2.0:cm:bearer",
211
+ nameId: "alice@example.com",
212
+ scd: _bearerScd("", inResponseTo),
213
+ });
214
+ var code = _verifyThrows(sp, b64, { expectedInResponseTo: inResponseTo });
215
+ check("Bearer missing NotOnOrAfter is refused",
216
+ code === "auth-saml/no-valid-confirmation");
217
+ }
218
+
219
+ // Case 3 — a Bearer SubjectConfirmationData with an UNPARSEABLE
220
+ // NotOnOrAfter must be refused (it cannot bound freshness).
221
+ async function testBearerUnparseableNotOnOrAfterRefused() {
222
+ var idp = await _mintRsaCert("idp.example");
223
+ var sp = _newSp(idp);
224
+ var inResponseTo = "_req-bad";
225
+ var b64 = _buildSignedResponse(idp, {
226
+ tag: "bearer-bad",
227
+ method: "urn:oasis:names:tc:SAML:2.0:cm:bearer",
228
+ nameId: "alice@example.com",
229
+ scd: _bearerScd(" NotOnOrAfter=\"not-a-date\"", inResponseTo),
230
+ });
231
+ var code = _verifyThrows(sp, b64, { expectedInResponseTo: inResponseTo });
232
+ check("Bearer unparseable NotOnOrAfter is refused",
233
+ code === "auth-saml/no-valid-confirmation");
234
+ }
235
+
236
+ // Case 4 — the Holder-of-Key sibling: an HoK SubjectConfirmationData
237
+ // missing NotOnOrAfter (and one with an unparseable value) must be
238
+ // refused. On the unfixed tree both are wrongly accepted (the missing
239
+ // case skips the check; the unparseable case is masked by an `&&`
240
+ // short-circuit).
241
+ async function testHolderOfKeyNotOnOrAfterRefused() {
242
+ var idp = await _mintRsaCert("idp.example");
243
+ var holder = await _mintRsaCert("holder.example");
244
+ var sp = _newSp(idp);
245
+ var vopts = { holderOfKey: { presentedCertPem: holder.certPem } };
246
+
247
+ // Sanity — a valid HoK NotOnOrAfter verifies (harness correctness).
248
+ var b64ok = _buildSignedResponse(idp, {
249
+ tag: "hok-valid",
250
+ method: "urn:oasis:names:tc:SAML:2.0:cm:holder-of-key",
251
+ nameId: "bob@example.com",
252
+ scd: _hokScd(" NotOnOrAfter=\"" + _isoFromNow(5 * 60 * 1000) + "\"", holder.certPem), // allow:raw-time-literal — 5m future
253
+ });
254
+ var info = sp.verifyResponse(b64ok, vopts);
255
+ check("HoK with valid NotOnOrAfter verifies", info && info.nameId === "bob@example.com");
256
+
257
+ var b64missing = _buildSignedResponse(idp, {
258
+ tag: "hok-missing",
259
+ method: "urn:oasis:names:tc:SAML:2.0:cm:holder-of-key",
260
+ nameId: "bob@example.com",
261
+ scd: _hokScd("", holder.certPem),
262
+ });
263
+ check("HoK missing NotOnOrAfter is refused",
264
+ _verifyThrows(sp, b64missing, vopts) === "auth-saml/no-valid-confirmation");
265
+
266
+ var b64bad = _buildSignedResponse(idp, {
267
+ tag: "hok-bad",
268
+ method: "urn:oasis:names:tc:SAML:2.0:cm:holder-of-key",
269
+ nameId: "bob@example.com",
270
+ scd: _hokScd(" NotOnOrAfter=\"not-a-date\"", holder.certPem),
271
+ });
272
+ check("HoK unparseable NotOnOrAfter is refused",
273
+ _verifyThrows(sp, b64bad, vopts) === "auth-saml/no-valid-confirmation");
274
+ }
275
+
276
+ async function run() {
277
+ await testBearerValidNotOnOrAfterAccepted();
278
+ await testBearerMissingNotOnOrAfterRefused();
279
+ await testBearerUnparseableNotOnOrAfterRefused();
280
+ await testHolderOfKeyNotOnOrAfterRefused();
281
+ }
282
+
283
+ if (require.main === module) {
284
+ run().then(function () { process.exit(0); })
285
+ .catch(function (e) { console.error(e); process.exit(1); });
286
+ }
287
+ module.exports = { run: run };
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ // #135: SD-JWT-VC ES256/ES384 signatures must be JOSE-encoded (raw r||s,
3
+ // "ieee-p1363"), not node:crypto's default DER. A DER signature (ASN.1
4
+ // SEQUENCE, leading 0x30, ~70-72 bytes for P-256) is rejected by every
5
+ // conformant JOSE / EUDI-wallet verifier, and this library would likewise
6
+ // reject a conformant wallet's raw-r||s signature. The issuer JWT and the
7
+ // holder KB-JWT both sign through the core _signJwt, so the format applies
8
+ // to both.
9
+ //
10
+ // RED on the buggy tree: the issuer-JWT signature is DER (length != 64,
11
+ // first byte 0x30) and a JOSE-conformant verifier (dsaEncoding ieee-p1363)
12
+ // rejects it. GREEN after the fix: signature is exactly 64 bytes and the
13
+ // conformant verifier accepts it.
14
+
15
+ var helpers = require("../helpers");
16
+ var b = helpers.b;
17
+ var check = helpers.check;
18
+ var nodeCrypto = require("node:crypto");
19
+ var sdJwtVc = b.auth.sdJwtVc;
20
+
21
+ function _b64uToBuf(s) {
22
+ return Buffer.from(s, "base64url");
23
+ }
24
+
25
+ async function run() {
26
+ var issuer = nodeCrypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
27
+
28
+ var sd = sdJwtVc.issue({
29
+ issuer: "https://issuer.example.com",
30
+ subject: "did:web:alice",
31
+ vct: "https://example.com/vct/identity",
32
+ claims: { given_name: "Alice", country: "US" },
33
+ selectivelyDisclosed: ["given_name"],
34
+ issuerKey: issuer.privateKey,
35
+ algorithm: "ES256",
36
+ });
37
+
38
+ // An SD-JWT serializes as <issuerJWT>~<disclosure>~…~ — strip the
39
+ // tilde-joined disclosures to get the issuer JWT before splitting on ".".
40
+ var issuerJwt = sd.token.split("~")[0];
41
+ var parts = issuerJwt.split(".");
42
+ check("issuer JWT has 3 parts", parts.length === 3);
43
+ var signingInput = parts[0] + "." + parts[1];
44
+ var sig = _b64uToBuf(parts[2]);
45
+
46
+ // ES256 raw r||s is exactly 64 bytes; DER is variable (~70-72) and starts
47
+ // with the 0x30 SEQUENCE tag.
48
+ check("#135 ES256 signature is JOSE raw r||s (64 bytes), not DER",
49
+ sig.length === 64);
50
+ check("#135 ES256 signature does not carry the DER SEQUENCE tag",
51
+ sig[0] !== 0x30 || sig.length === 64);
52
+
53
+ // A JOSE-conformant verifier (explicit ieee-p1363) must accept it. On the
54
+ // buggy tree the signature is DER, so a conformant verifier rejects it.
55
+ var conformantOk = nodeCrypto.verify(
56
+ "sha256",
57
+ Buffer.from(signingInput, "ascii"),
58
+ { key: issuer.publicKey, dsaEncoding: "ieee-p1363" },
59
+ sig);
60
+ check("#135 a JOSE-conformant verifier (ieee-p1363) accepts the issuer JWT",
61
+ conformantOk === true);
62
+
63
+ // ES384 carries the same root — exercise it too (96-byte raw r||s).
64
+ var issuer384 = nodeCrypto.generateKeyPairSync("ec", { namedCurve: "P-384" });
65
+ var sd384 = sdJwtVc.issue({
66
+ issuer: "https://issuer.example.com",
67
+ subject: "did:web:carol",
68
+ vct: "https://example.com/vct/identity",
69
+ claims: { given_name: "Carol" },
70
+ selectivelyDisclosed: ["given_name"],
71
+ issuerKey: issuer384.privateKey,
72
+ algorithm: "ES384",
73
+ });
74
+ var sig384 = _b64uToBuf(sd384.token.split("~")[0].split(".")[2]);
75
+ check("#135 ES384 signature is JOSE raw r||s (96 bytes), not DER",
76
+ sig384.length === 96);
77
+ }
78
+
79
+ module.exports = { run: run };
@@ -695,6 +695,55 @@ async function testHolderAlgFromKeyType() {
695
695
  rsaThrew && rsaThrew.code === "auth-sd-jwt-vc/holder-key-unsupported");
696
696
  }
697
697
 
698
+ // ---- FIX 4B: holder KB-JWT alg/kty cross-check ----
699
+
700
+ // The KB-JWT header alg is attacker-controllable (the holder mints the
701
+ // KB-JWT). The verifier must cross-check it against the holder's cnf.jwk
702
+ // key type BEFORE handing bytes to node:crypto.verify — the same
703
+ // CVE-2026-22817 defense the issuer path applies. An EC cnf key with a
704
+ // KB-JWT header claiming EdDSA (which requires kty=OKP) must be refused
705
+ // with the precise alg-mismatch error.
706
+ async function testKbAlgKtyCrossCheck() {
707
+ var issuer = _newKeyPair();
708
+ var holder = _newKeyPair(); // EC P-256
709
+ var sd = sdJwtVc.issue({
710
+ issuer: "https://issuer", vct: "x",
711
+ claims: { given_name: "Alice" },
712
+ selectivelyDisclosed: ["given_name"],
713
+ issuerKey: issuer.privateKey,
714
+ holderKey: _jwk(holder.publicKey),
715
+ });
716
+ // Build a valid presentation, then replace its real KB-JWT with a forged
717
+ // one whose header declares EdDSA against the EC holder key.
718
+ var pres = sdJwtVc.present({
719
+ sdJwt: sd.token,
720
+ disclosedClaimNames: ["given_name"],
721
+ audience: "https://verifier",
722
+ nonce: "n-1",
723
+ holderKey: holder.privateKey,
724
+ algorithm: "ES256",
725
+ });
726
+ var segs = pres.presentation.split("~");
727
+ // Forge a KB-JWT segment: EdDSA header (OKP), EC holder key → mismatch.
728
+ function b64u(obj) { return Buffer.from(JSON.stringify(obj), "utf8").toString("base64url"); }
729
+ var forgedHeader = b64u({ typ: "kb+jwt", alg: "EdDSA" });
730
+ var forgedPayload = b64u({ aud: "https://verifier", nonce: "n-1", iat: Math.floor(Date.now() / 1000), sd_hash: "x" });
731
+ segs[segs.length - 1] = forgedHeader + "." + forgedPayload + ".AAAA";
732
+ var forgedPres = segs.join("~");
733
+
734
+ var threw = null;
735
+ try {
736
+ await sdJwtVc.verify(forgedPres, {
737
+ issuerKeyResolver: async function () { return issuer.publicKey; },
738
+ audience: "https://verifier",
739
+ nonce: "n-1",
740
+ requireKeyBinding: true,
741
+ });
742
+ } catch (e) { threw = e; }
743
+ check("KB alg/kty: mismatched KB-JWT alg refused with precise error",
744
+ threw && threw.code === "auth-jwt-external/alg-kty-mismatch");
745
+ }
746
+
698
747
  // ---- Module exports ----
699
748
 
700
749
  function testExports() {
@@ -742,5 +791,6 @@ function testExports() {
742
791
  await testHolderPresentNonexistent();
743
792
  testHolderValidation();
744
793
  await testHolderAlgFromKeyType();
794
+ await testKbAlgKtyCrossCheck();
745
795
  testExports();
746
796
  })().catch(function (e) { console.error(e); process.exit(1); });
@@ -168,8 +168,9 @@ function testReportOnlyHeadersEmittedWhenOptedIn() {
168
168
 
169
169
  function testReportOnlyDoesNotTouchEnforcingHeaders() {
170
170
  // Monitor-mode opt-ins must not alter the enforcing COOP / COEP /
171
- // Document-Policy headers: COOP stays same-origin, COEP stays off by
172
- // default, Document-Policy keeps its enforcing default.
171
+ // Document-Policy headers: COOP stays same-origin, the enforcing COEP
172
+ // keeps its default-on `credentialless` value (the report-only opt is a
173
+ // separate header), Document-Policy keeps its enforcing default.
173
174
  var mw = b.middleware.securityHeaders({
174
175
  coopReportOnly: "same-origin",
175
176
  coepReportOnly: "require-corp",
@@ -178,8 +179,8 @@ function testReportOnlyDoesNotTouchEnforcingHeaders() {
178
179
  mw({ headers: {} }, res, function () {});
179
180
  check("enforcing COOP unchanged by coopReportOnly",
180
181
  res._hdrs["Cross-Origin-Opener-Policy"] === "same-origin");
181
- check("COEP stays off by default despite coepReportOnly",
182
- res._hdrs["Cross-Origin-Embedder-Policy"] === undefined);
182
+ check("enforcing COEP keeps its default-on value despite coepReportOnly",
183
+ res._hdrs["Cross-Origin-Embedder-Policy"] === "credentialless");
183
184
  check("enforcing Document-Policy unchanged by report-only opts",
184
185
  res._hdrs["Document-Policy"] === b.middleware._modules.securityHeaders.DEFAULT_DOCUMENT_POLICY);
185
186
  }
@@ -254,6 +255,31 @@ function testUnknownOptStillRefused() {
254
255
  check("typo'd report-only opt refused at config-time", threw);
255
256
  }
256
257
 
258
+ function testCoepDefaultOnAndOptOut() {
259
+ // Default-on (v0.15.0): the enforcing Cross-Origin-Embedder-Policy is
260
+ // emitted as `credentialless` with no operator action, so COOP+COEP
261
+ // together yield cross-origin isolation out of the box.
262
+ var resDefault = _mkRes();
263
+ b.middleware.securityHeaders()({ headers: {} }, resDefault, function () {});
264
+ check("COEP default-on: Cross-Origin-Embedder-Policy is credentialless",
265
+ resDefault._hdrs["Cross-Origin-Embedder-Policy"] === "credentialless");
266
+ check("COOP stays same-origin alongside the default COEP",
267
+ resDefault._hdrs["Cross-Origin-Opener-Policy"] === "same-origin");
268
+
269
+ // Tighten: operators serving only same-origin / CORP-marked subresources
270
+ // pass coep: "require-corp" for the strict enforcing mode.
271
+ var resStrict = _mkRes();
272
+ b.middleware.securityHeaders({ coep: "require-corp" })({ headers: {} }, resStrict, function () {});
273
+ check("COEP tighten: coep:'require-corp' overrides the default",
274
+ resStrict._hdrs["Cross-Origin-Embedder-Policy"] === "require-corp");
275
+
276
+ // Documented opt-out: coep:false disables COEP entirely (no header).
277
+ var resOff = _mkRes();
278
+ b.middleware.securityHeaders({ coep: false })({ headers: {} }, resOff, function () {});
279
+ check("COEP opt-out: coep:false emits no Cross-Origin-Embedder-Policy header",
280
+ resOff._hdrs["Cross-Origin-Embedder-Policy"] === undefined);
281
+ }
282
+
257
283
  async function run() {
258
284
  testFencedFrameSrcInDefaultCsp();
259
285
  testDocumentPolicyDefault();
@@ -276,6 +302,7 @@ async function run() {
276
302
  testServiceWorkerAllowedDefaultOff();
277
303
  testNewOptsNonStringIgnored();
278
304
  testUnknownOptStillRefused();
305
+ testCoepDefaultOnAndOptOut();
279
306
  }
280
307
 
281
308
  module.exports = { run: run };
@@ -273,6 +273,50 @@ async function testUpdateDataPreservesFingerprint() {
273
273
  }
274
274
  }
275
275
 
276
+ async function testRotateRekeysFingerprint() {
277
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "ses-rotate-fp-"));
278
+ try {
279
+ await setupTestDb(tmpDir);
280
+ var req = _makeReq({ "user-agent": "ua-rot-1", "x-forwarded-for": "203.0.113.10" });
281
+ var s = await b.session.create({
282
+ userId: "u-rot",
283
+ data: { roles: ["user"] },
284
+ req: req,
285
+ fingerprintFields: ["clientIp", "userAgent"],
286
+ });
287
+ var pre = await b.session.verify(s.token, { req: req, fingerprintFields: ["clientIp", "userAgent"] });
288
+ check("rotate-fp: pre-rotation no drift", pre && pre.fingerprintDrift === false);
289
+
290
+ // Rotation (login transition / role escalation) moves the sid. __bj_fingerprint
291
+ // is sid-keyed, so the new session must RE-KEY the binding to the new sid from
292
+ // the live request — otherwise verify(newToken, sameReq) recomputes against the
293
+ // new sid and falsely reports drift (logout under strict operators), or the
294
+ // binding silently breaks.
295
+ var rotated = await b.session.rotate(s.token, {
296
+ req: req, fingerprintFields: ["clientIp", "userAgent"],
297
+ });
298
+ check("rotate-fp: rotation returns a new token", rotated && typeof rotated.token === "string");
299
+
300
+ var sameDevice = await b.session.verify(rotated.token, {
301
+ req: req, fingerprintFields: ["clientIp", "userAgent"],
302
+ });
303
+ check("rotate-fp: same device → no drift after rotation (binding re-keyed)",
304
+ sameDevice && sameDevice.fingerprintDrift === false);
305
+ check("rotate-fp: operator data carried across rotation",
306
+ sameDevice && sameDevice.data && sameDevice.data.roles && sameDevice.data.roles[0] === "user");
307
+
308
+ // A different device must still drift — proves the binding is live, not dropped.
309
+ var otherReq = _makeReq({ "user-agent": "ua-OTHER", "x-forwarded-for": "198.51.100.7" });
310
+ var otherDevice = await b.session.verify(rotated.token, {
311
+ req: otherReq, fingerprintFields: ["clientIp", "userAgent"],
312
+ });
313
+ check("rotate-fp: different device → drift after rotation (binding still enforced)",
314
+ otherDevice && otherDevice.fingerprintDrift === true);
315
+ } finally {
316
+ await teardownTestDb(tmpDir);
317
+ }
318
+ }
319
+
276
320
  async function run() {
277
321
  await testSealedCookieDefault();
278
322
  await testSealedCookieRotateAndDestroy();
@@ -283,6 +327,7 @@ async function run() {
283
327
  await testPluggableStoreValidation();
284
328
  await testUpdateDataReplaceAndMerge();
285
329
  await testUpdateDataPreservesFingerprint();
330
+ await testRotateRekeysFingerprint();
286
331
  }
287
332
 
288
333
  module.exports = { run: run };
@@ -14,6 +14,7 @@
14
14
  var helpers = require("../helpers");
15
15
  var http = require("http");
16
16
  var bucketOps = require("../../lib/object-store/sigv4-bucket-ops");
17
+ var sigv4 = require("../../lib/object-store/sigv4");
17
18
  var b = helpers.b;
18
19
  var check = helpers.check;
19
20
  var listenOnRandomPort = helpers.listenOnRandomPort;
@@ -969,8 +970,56 @@ async function testPerCallActorOverrideHonored() {
969
970
  }
970
971
  }
971
972
 
973
+ function testCanonicalPathSingleEncodeForS3() {
974
+ // Regression: S3 (and S3-compatible stores + GCS's V4) URI-encode the
975
+ // canonical path ONCE; the older code double-encoded it, so any object key
976
+ // with a space / + / & / unicode signed a path the wire never carried →
977
+ // SignatureDoesNotMatch (403). Drive the real signRequest path with a
978
+ // special-char key and assert the canonical path line equals the wire
979
+ // pathname byte-for-byte. (Pre-fix this matched only for ASCII keys, which
980
+ // is why every shipped test passed while real keys 403'd.)
981
+ var key = "my report (v2)+final & draft.txt";
982
+ var encodedKey = key.split("/").map(function (s) { return sigv4.awsUriEncode(s, true); }).join("/");
983
+ var url = new URL("https://bucket.s3.example.com");
984
+ url.pathname = "/" + encodedKey;
985
+
986
+ var s3 = sigv4.signRequest({
987
+ method: "GET", url: url, headers: {}, payloadHash: "UNSIGNED-PAYLOAD",
988
+ region: "us-east-1", accessKeyId: "AK", secretAccessKey: "sk", date: new Date(0),
989
+ });
990
+ var s3CanonPath = s3.canonicalRequest.split("\n")[1];
991
+ check("S3 canonical path single-encodes — equals the wire pathname (no double-encode)",
992
+ s3CanonPath === url.pathname);
993
+ check("S3 canonical path has no double-encoded %25 sequence",
994
+ s3CanonPath.indexOf("%25") === -1 && url.pathname.indexOf("%25") === -1);
995
+
996
+ // The non-S3 services (sqs/logs/sns) MUST keep the double-encode (AWS spec).
997
+ var u2 = new URL("https://sqs.us-east-1.amazonaws.com");
998
+ u2.pathname = "/a%20b";
999
+ var sqs = sigv4.signRequest({
1000
+ method: "GET", url: u2, headers: {}, payloadHash: sigv4.sha256Hex(""),
1001
+ region: "us-east-1", service: "sqs", accessKeyId: "AK", secretAccessKey: "sk", date: new Date(0),
1002
+ });
1003
+ var sqsCanonPath = sqs.canonicalRequest.split("\n")[1];
1004
+ check("non-S3 service still double-encodes the canonical path (spec-correct, unchanged)",
1005
+ sqsCanonPath === "/a%2520b");
1006
+
1007
+ // awsUriEncode escapes the AWS reserved set (!*'()) that encodeURIComponent
1008
+ // leaves alone, so the bucket-ops wire path matches the bytes S3 signs over.
1009
+ check("awsUriEncode escapes !*'() that encodeURIComponent leaves raw",
1010
+ sigv4.awsUriEncode("a!b*c'd(e)", true) === "a%21b%2Ac%27d%28e%29");
1011
+
1012
+ // A key with a non-BMP code point (emoji, CJK extension B, ...) must encode
1013
+ // by code point, not UTF-16 unit — otherwise the surrogate pair is split and
1014
+ // encodeURIComponent throws "URIError: URI malformed" before the request is
1015
+ // even signed.
1016
+ check("awsUriEncode encodes a non-BMP code point as one UTF-8 sequence (no URIError)",
1017
+ sigv4.awsUriEncode("photo-\u{1F600}.jpg", true) === "photo-%F0%9F%98%80.jpg");
1018
+ }
1019
+
972
1020
  async function run() {
973
1021
  testSurface();
1022
+ testCanonicalPathSingleEncodeForS3();
974
1023
  testFactoryValidation();
975
1024
  testBucketNameValidation();
976
1025
  testLifecycleXml();