@blamejs/blamejs-shop 0.4.31 → 0.4.33

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 (343) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -1
  3. package/lib/asset-manifest.json +1 -1
  4. package/lib/vendor/MANIFEST.json +400 -282
  5. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  6. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  7. package/lib/vendor/blamejs/.gitignore +6 -0
  8. package/lib/vendor/blamejs/CHANGELOG.md +28 -0
  9. package/lib/vendor/blamejs/MIGRATING.md +55 -0
  10. package/lib/vendor/blamejs/README.md +8 -6
  11. package/lib/vendor/blamejs/SECURITY.md +19 -3
  12. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  13. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  14. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  15. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  16. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  17. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  18. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  19. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  20. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  21. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  23. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  24. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  25. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  26. package/lib/vendor/blamejs/index.js +4 -0
  27. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  28. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  29. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  30. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  31. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  32. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  33. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  34. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  35. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  36. package/lib/vendor/blamejs/lib/audit.js +259 -123
  37. package/lib/vendor/blamejs/lib/auth/elevation-grant.js +6 -2
  38. package/lib/vendor/blamejs/lib/auth/oauth.js +66 -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 +36 -7
  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 +210 -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/credential-hash.js +9 -0
  55. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  56. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  57. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  58. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  59. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  60. package/lib/vendor/blamejs/lib/db.js +249 -99
  61. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  62. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  63. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  64. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  65. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  66. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  67. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  68. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  69. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  70. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  71. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  72. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  73. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  74. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  75. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  76. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  77. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  78. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  79. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  80. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  81. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  82. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  83. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  84. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  85. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  86. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  87. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  88. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  89. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  90. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  91. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  92. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  93. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  94. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  95. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  96. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  97. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  98. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  99. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  100. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  101. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  102. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  105. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  106. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  107. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  108. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  109. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  110. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  111. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  112. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  113. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  114. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  115. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  116. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  117. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  118. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  119. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  120. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  121. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  122. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  123. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  124. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  125. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  126. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  128. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  129. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  131. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  132. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  133. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  134. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  136. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  137. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  138. package/lib/vendor/blamejs/lib/mail.js +8 -4
  139. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  140. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  141. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  142. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  143. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  144. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  145. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  146. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  147. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  148. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  149. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  150. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  151. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  152. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  153. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  154. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  155. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  156. package/lib/vendor/blamejs/lib/observability.js +124 -0
  157. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  158. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  159. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  160. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  161. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  162. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  163. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  164. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  165. package/lib/vendor/blamejs/lib/queue.js +7 -0
  166. package/lib/vendor/blamejs/lib/redact.js +68 -11
  167. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  168. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  169. package/lib/vendor/blamejs/lib/retention.js +117 -42
  170. package/lib/vendor/blamejs/lib/router.js +212 -5
  171. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  172. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  173. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  174. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  175. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  176. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  177. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  178. package/lib/vendor/blamejs/lib/scheduler.js +47 -12
  179. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  180. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  181. package/lib/vendor/blamejs/lib/session.js +175 -77
  182. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  183. package/lib/vendor/blamejs/lib/sse.js +26 -0
  184. package/lib/vendor/blamejs/lib/ssrf-guard.js +169 -4
  185. package/lib/vendor/blamejs/lib/static.js +177 -34
  186. package/lib/vendor/blamejs/lib/subject.js +96 -49
  187. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  188. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  189. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  190. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  191. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  192. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  193. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  194. package/lib/vendor/blamejs/package.json +2 -2
  195. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  200. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  201. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  202. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  203. package/lib/vendor/blamejs/release-notes/v0.15.7.json +43 -0
  204. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  205. package/lib/vendor/blamejs/scripts/gen-migrating.js +67 -0
  206. package/lib/vendor/blamejs/scripts/release.js +398 -38
  207. package/lib/vendor/blamejs/test/00-primitives.js +168 -0
  208. package/lib/vendor/blamejs/test/10-state.js +140 -14
  209. package/lib/vendor/blamejs/test/20-db.js +65 -2
  210. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  211. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  212. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  213. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  214. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  215. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  216. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  217. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  220. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  221. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  222. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  223. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  224. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  225. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  226. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  227. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  228. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  229. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  230. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  231. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  232. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  233. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  234. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  235. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  236. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  237. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  238. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  239. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  240. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  242. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  251. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  252. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1196 -14
  253. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +18 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  256. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  259. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  267. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  275. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  276. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  277. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  278. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  282. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  283. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  286. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  287. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  288. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  296. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +59 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +362 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-watchdog-stale-settle.test.js +71 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  309. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  315. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  317. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  318. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  319. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  320. package/lib/vendor/blamejs/test/smoke.js +79 -21
  321. package/package.json +2 -2
  322. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  323. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  324. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  325. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  326. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  327. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  328. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  329. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  330. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  331. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  332. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  333. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  334. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  335. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  336. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  337. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  338. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  339. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  340. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  341. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  342. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  343. 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,71 @@
1
+ "use strict";
2
+ // #130: the scheduler watchdog force-clears task.running after maxJobMs and
3
+ // lets the next tick re-fire. The ORIGINAL (slow) run's promise then settles
4
+ // late and, before the fix, unconditionally wrote back task.running/lastFinish/
5
+ // lastError AND emitted system.scheduler.task.success|failure — clobbering the
6
+ // state the watchdog (and the new run) had moved on from, and double-counting.
7
+ // The fix tags each run with a generation the watchdog + each fire bump; a
8
+ // settle whose tag is stale is ignored.
9
+ //
10
+ // Driven through the public scheduler with a run() whose promise the test
11
+ // controls. RED on the buggy tree: resolving the watchdog-abandoned run emits
12
+ // a stale success. GREEN: it emits nothing; only the current run settles.
13
+
14
+ var helpers = require("../helpers");
15
+ var b = helpers.b;
16
+ var check = helpers.check;
17
+ var auditMod = require("../../lib/audit");
18
+
19
+ var TASK = "wd-stale-settle-test";
20
+
21
+ async function run() {
22
+ var realEmit = auditMod.safeEmit;
23
+ var successes = 0;
24
+ auditMod.safeEmit = function (ev) {
25
+ if (ev && ev.action === "system.scheduler.task.success" &&
26
+ ev.metadata && ev.metadata.name === TASK) {
27
+ successes += 1;
28
+ }
29
+ return realEmit.call(auditMod, ev);
30
+ };
31
+
32
+ var resolvers = []; // one resolve fn per fire — the test settles them by hand
33
+ var sched = b.scheduler.create({ maxJobMs: 1, audit: true }); // 1ms watchdog → any stuck run is reaped next tick
34
+ try {
35
+ sched.schedule({
36
+ name: TASK,
37
+ every: 1000, // builder floor is 1000ms; fire 1 ≈ 1s, watchdog re-fire ≈ 2s
38
+ run: function () { return new Promise(function (resolve) { resolvers.push(resolve); }); },
39
+ });
40
+ sched.start();
41
+
42
+ // Wait until the watchdog has reaped fire 1 (still pending) and re-fired,
43
+ // so two runs exist: resolvers[0] (abandoned) + resolvers[1] (current).
44
+ await helpers.waitUntil(function () { return resolvers.length >= 2; },
45
+ { timeoutMs: 9000, label: "#130: watchdog re-fired the task after a stuck run" });
46
+
47
+ var before = successes;
48
+ // Settle the FIRST run — the one the watchdog abandoned. Its late resolve
49
+ // must NOT emit a success (its generation is stale).
50
+ resolvers[0]();
51
+ await helpers.passiveObserve(400, "#130: stale-settle window for the abandoned run");
52
+ check("#130 a watchdog-abandoned run's late resolve emits NO stale success",
53
+ successes === before);
54
+
55
+ // The current run still settles normally → exactly one success.
56
+ resolvers[1]();
57
+ await helpers.waitUntil(function () { return successes === before + 1; },
58
+ { timeoutMs: 5000, label: "#130: the current run records its success" });
59
+ check("#130 the current (post-watchdog) run still records its success",
60
+ successes === before + 1);
61
+ } finally {
62
+ sched.stop();
63
+ auditMod.safeEmit = realEmit;
64
+ }
65
+ }
66
+
67
+ module.exports = { run: run };
68
+ if (require.main === module) {
69
+ run().then(function () { process.exit(0); })
70
+ .catch(function (err) { process.stderr.write(String(err && err.stack || err) + "\n"); process.exit(1); });
71
+ }
@@ -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 };