@blamejs/blamejs-shop 0.5.12 → 0.5.13

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 (521) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +632 -416
  4. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
  5. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
  6. package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
  7. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  8. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
  9. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
  10. package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
  11. package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
  12. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
  13. package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
  14. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
  15. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  16. package/lib/vendor/blamejs/.gitignore +2 -0
  17. package/lib/vendor/blamejs/CHANGELOG.md +122 -0
  18. package/lib/vendor/blamejs/NOTICE +26 -1
  19. package/lib/vendor/blamejs/SECURITY.md +1 -1
  20. package/lib/vendor/blamejs/api-snapshot.json +207 -5
  21. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
  22. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
  25. package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
  26. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  27. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
  28. package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
  29. package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
  30. package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
  31. package/lib/vendor/blamejs/index.js +6 -0
  32. package/lib/vendor/blamejs/lib/a2a.js +4 -4
  33. package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
  34. package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
  35. package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
  36. package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
  37. package/lib/vendor/blamejs/lib/archive-read.js +8 -0
  38. package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
  39. package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
  40. package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
  41. package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
  42. package/lib/vendor/blamejs/lib/audit.js +71 -8
  43. package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
  44. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
  45. package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
  46. package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
  47. package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
  48. package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
  49. package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
  50. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
  51. package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
  52. package/lib/vendor/blamejs/lib/backup/index.js +16 -5
  53. package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
  54. package/lib/vendor/blamejs/lib/base32.js +21 -0
  55. package/lib/vendor/blamejs/lib/break-glass.js +19 -10
  56. package/lib/vendor/blamejs/lib/bundler.js +5 -1
  57. package/lib/vendor/blamejs/lib/cache-status.js +3 -7
  58. package/lib/vendor/blamejs/lib/calendar.js +21 -1
  59. package/lib/vendor/blamejs/lib/cbor.js +12 -1
  60. package/lib/vendor/blamejs/lib/cert.js +29 -11
  61. package/lib/vendor/blamejs/lib/cli.js +94 -24
  62. package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
  63. package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
  64. package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
  65. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
  66. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
  67. package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
  68. package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
  69. package/lib/vendor/blamejs/lib/content-digest.js +2 -1
  70. package/lib/vendor/blamejs/lib/cookies.js +13 -3
  71. package/lib/vendor/blamejs/lib/cose.js +31 -16
  72. package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
  73. package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
  74. package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
  75. package/lib/vendor/blamejs/lib/crypto.js +314 -19
  76. package/lib/vendor/blamejs/lib/csp.js +11 -3
  77. package/lib/vendor/blamejs/lib/daemon.js +270 -24
  78. package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
  79. package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
  80. package/lib/vendor/blamejs/lib/db-query.js +34 -7
  81. package/lib/vendor/blamejs/lib/db.js +18 -6
  82. package/lib/vendor/blamejs/lib/dbsc.js +17 -0
  83. package/lib/vendor/blamejs/lib/dev.js +21 -2
  84. package/lib/vendor/blamejs/lib/dsr.js +157 -102
  85. package/lib/vendor/blamejs/lib/external-db.js +41 -2
  86. package/lib/vendor/blamejs/lib/file-upload.js +25 -7
  87. package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
  88. package/lib/vendor/blamejs/lib/forms.js +113 -27
  89. package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
  90. package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
  91. package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
  92. package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
  93. package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
  94. package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
  95. package/lib/vendor/blamejs/lib/guard-html.js +26 -53
  96. package/lib/vendor/blamejs/lib/guard-image.js +24 -5
  97. package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
  98. package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
  99. package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
  100. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
  101. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
  102. package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
  105. package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
  106. package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
  107. package/lib/vendor/blamejs/lib/guard-time.js +1 -1
  108. package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
  109. package/lib/vendor/blamejs/lib/html-balance.js +3 -3
  110. package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
  111. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
  112. package/lib/vendor/blamejs/lib/http-client.js +39 -7
  113. package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
  114. package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
  115. package/lib/vendor/blamejs/lib/i18n.js +35 -21
  116. package/lib/vendor/blamejs/lib/incident-report.js +8 -1
  117. package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
  118. package/lib/vendor/blamejs/lib/json-path.js +23 -1
  119. package/lib/vendor/blamejs/lib/jwk.js +20 -3
  120. package/lib/vendor/blamejs/lib/link-header.js +2 -1
  121. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
  123. package/lib/vendor/blamejs/lib/log-stream.js +8 -3
  124. package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
  125. package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
  126. package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
  128. package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
  129. package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
  130. package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
  131. package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
  132. package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
  133. package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
  134. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
  136. package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
  137. package/lib/vendor/blamejs/lib/mail.js +15 -5
  138. package/lib/vendor/blamejs/lib/metrics.js +268 -63
  139. package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
  140. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
  141. package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
  142. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
  143. package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
  144. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
  145. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
  146. package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
  147. package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
  148. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
  149. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
  150. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
  151. package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
  152. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
  153. package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
  154. package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
  155. package/lib/vendor/blamejs/lib/network-dns.js +21 -2
  156. package/lib/vendor/blamejs/lib/network-tls.js +69 -7
  157. package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
  158. package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
  159. package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
  160. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
  161. package/lib/vendor/blamejs/lib/outbox.js +1 -1
  162. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
  163. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
  164. package/lib/vendor/blamejs/lib/permissions.js +6 -3
  165. package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
  166. package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
  167. package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
  168. package/lib/vendor/blamejs/lib/pubsub.js +20 -9
  169. package/lib/vendor/blamejs/lib/queue-local.js +8 -1
  170. package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
  171. package/lib/vendor/blamejs/lib/redact.js +54 -0
  172. package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
  173. package/lib/vendor/blamejs/lib/restore.js +19 -0
  174. package/lib/vendor/blamejs/lib/retention.js +12 -4
  175. package/lib/vendor/blamejs/lib/router.js +60 -6
  176. package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
  177. package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
  178. package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
  179. package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
  180. package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
  181. package/lib/vendor/blamejs/lib/safe-object.js +80 -0
  182. package/lib/vendor/blamejs/lib/safe-path.js +52 -4
  183. package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
  184. package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
  185. package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
  186. package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
  187. package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
  188. package/lib/vendor/blamejs/lib/scheduler.js +8 -1
  189. package/lib/vendor/blamejs/lib/security-assert.js +6 -6
  190. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
  191. package/lib/vendor/blamejs/lib/self-update.js +517 -87
  192. package/lib/vendor/blamejs/lib/server-timing.js +2 -4
  193. package/lib/vendor/blamejs/lib/session.js +34 -12
  194. package/lib/vendor/blamejs/lib/sql.js +15 -1
  195. package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
  196. package/lib/vendor/blamejs/lib/static.js +55 -13
  197. package/lib/vendor/blamejs/lib/storage.js +8 -2
  198. package/lib/vendor/blamejs/lib/subject.js +6 -1
  199. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
  200. package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
  201. package/lib/vendor/blamejs/lib/tsa.js +34 -13
  202. package/lib/vendor/blamejs/lib/uri-template.js +8 -1
  203. package/lib/vendor/blamejs/lib/vault/index.js +13 -0
  204. package/lib/vendor/blamejs/lib/vc.js +44 -5
  205. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
  206. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
  207. package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
  208. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
  209. package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
  210. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
  212. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
  213. package/lib/vendor/blamejs/lib/watcher.js +89 -17
  214. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
  215. package/lib/vendor/blamejs/lib/webhook.js +12 -2
  216. package/lib/vendor/blamejs/lib/ws-client.js +32 -1
  217. package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
  218. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
  219. package/lib/vendor/blamejs/package-lock.json +2 -2
  220. package/lib/vendor/blamejs/package.json +1 -1
  221. package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
  222. package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
  223. package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
  224. package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
  225. package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
  226. package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
  227. package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
  228. package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
  229. package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
  230. package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
  231. package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
  232. package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
  233. package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
  234. package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
  235. package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
  236. package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
  237. package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
  238. package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
  239. package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
  240. package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
  241. package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
  242. package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
  243. package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
  244. package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
  245. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
  246. package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
  247. package/lib/vendor/blamejs/socket.yml +94 -0
  248. package/lib/vendor/blamejs/test/00-primitives.js +605 -0
  249. package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
  250. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
  251. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
  252. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
  253. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
  254. package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
  255. package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
  256. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
  257. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
  258. package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
  259. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
  262. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
  268. package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
  284. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
  293. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
  294. package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
  302. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
  307. package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
  315. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
  317. package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
  318. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
  319. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
  320. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
  321. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
  322. package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
  323. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
  324. package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
  325. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
  326. package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
  327. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
  328. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
  329. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
  330. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
  331. package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
  334. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
  335. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
  336. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
  337. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
  341. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
  342. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
  346. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
  347. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
  348. package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
  349. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
  376. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
  388. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
  389. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
  390. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
  391. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
  392. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
  393. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
  395. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
  396. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
  397. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
  398. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
  399. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
  400. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
  401. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
  402. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
  403. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
  404. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
  405. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
  406. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
  407. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
  408. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
  409. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
  410. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
  411. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
  412. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
  413. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
  414. package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
  415. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
  416. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
  417. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
  418. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
  419. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
  420. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
  421. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
  422. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
  423. package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
  424. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
  425. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
  426. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
  427. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
  428. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
  429. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
  430. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
  431. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
  432. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
  433. package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
  434. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
  435. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
  436. package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
  437. package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
  438. package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
  439. package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
  440. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
  441. package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
  442. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
  443. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
  444. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
  445. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
  446. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
  447. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
  448. package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
  449. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
  450. package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
  451. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
  452. package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
  453. package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
  454. package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
  455. package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
  456. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
  457. package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
  458. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
  459. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
  460. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
  461. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
  462. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
  463. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
  464. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
  465. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
  466. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
  467. package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
  468. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
  469. package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
  470. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
  471. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
  472. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
  473. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
  474. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
  475. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
  476. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
  477. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
  478. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
  479. package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
  480. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
  481. package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
  482. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
  483. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
  484. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
  485. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
  486. package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
  487. package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
  488. package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
  489. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
  490. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
  491. package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
  492. package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
  493. package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
  494. package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
  495. package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
  496. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
  497. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
  498. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
  499. package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
  500. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
  501. package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
  502. package/lib/vendor/blamejs/test/smoke.js +2 -0
  503. package/package.json +1 -1
  504. package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
  505. package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
  506. package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
  507. package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
  508. package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
  509. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
  510. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
  511. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
  512. package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
  513. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
  514. package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
  515. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
  516. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
  517. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
  518. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
  519. package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
  520. package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
  521. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
@@ -28,36 +28,50 @@ var check = helpers.check;
28
28
 
29
29
  var fwkErr = require("../../lib/framework-error");
30
30
 
31
- // Mint an RSA self-signed cert + matching private-key PEM via the
32
- // vendored pki bundle. RS256 keeps the JWS verification path simple
33
- // and matches the real FIDO Alliance BLOB shape. The same cert is
34
- // used as both the JWS leaf (x5c[0]) and the trust root passed via
35
- // caCertificate so the chain anchors against itself this is the
36
- // operator escape-hatch path the primitive itself documents.
37
- async function _makeSelfSignedRsaCert() {
31
+ // Mint a self-signed cert + matching private-key PEM via the vendored pki
32
+ // bundle. `opts.algo` selects the key type ("RSA" default / "EC" P-256 /
33
+ // "Ed25519") so a single builder drives the RS256 / ES256 / alg-mismatch JWS
34
+ // verify branches; `opts.ca` toggles basicConstraints cA (false exercises the
35
+ // fingerprint-anchor fallback, which accepts a pinned non-CA leaf only on an
36
+ // exact fingerprint match); `opts.notBefore` / `opts.notAfter` drive the
37
+ // not-yet-valid / expired validity-window refusals. The cert is used as both
38
+ // the JWS leaf (x5c[0]) and the trust root passed via caCertificate so the
39
+ // chain anchors against itself — the operator escape-hatch the primitive docs.
40
+ async function _makeCert(opts) {
41
+ opts = opts || {};
38
42
  var pki = require("../../lib/vendor/pki.cjs");
39
43
  var x509 = pki.x509;
40
- var keys = await nodeCrypto.webcrypto.subtle.generateKey(
41
- { name: "RSASSA-PKCS1-v1_5",
42
- modulusLength: 2048, // allow:raw-byte-literal — RSA modulus bits
43
- publicExponent: new Uint8Array([1, 0, 1]), // allow:raw-byte-literal — RSA F4 exponent
44
- hash: "SHA-256" },
45
- true, ["sign", "verify"]);
44
+ var algo = opts.algo || "RSA";
45
+ var isCa = opts.ca === undefined ? true : opts.ca;
46
46
  var now = new Date();
47
- var notAfter = new Date(now.getTime() + 7 * 86400000); // allow:raw-byte-literal — fixture validity ms
47
+ var notBefore = opts.notBefore || now;
48
+ var notAfter = opts.notAfter || new Date(now.getTime() + 7 * 86400000); // allow:raw-byte-literal — fixture validity ms
49
+ var genAlg, signAlg;
50
+ if (algo === "EC") {
51
+ genAlg = { name: "ECDSA", namedCurve: "P-256" };
52
+ signAlg = { name: "ECDSA", hash: "SHA-256" };
53
+ } else if (algo === "Ed25519") {
54
+ genAlg = { name: "Ed25519" };
55
+ signAlg = { name: "Ed25519" };
56
+ } else {
57
+ genAlg = { name: "RSASSA-PKCS1-v1_5",
58
+ modulusLength: 2048, // allow:raw-byte-literal — RSA modulus bits
59
+ publicExponent: new Uint8Array([1, 0, 1]), // allow:raw-byte-literal — RSA F4 exponent
60
+ hash: "SHA-256" };
61
+ signAlg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
62
+ }
63
+ var keys = await nodeCrypto.webcrypto.subtle.generateKey(genAlg, true, ["sign", "verify"]);
64
+ var exts = [ new x509.BasicConstraintsExtension(isCa, 0, true) ];
65
+ if (isCa) exts.push(new x509.KeyUsagesExtension(
66
+ x509.KeyUsageFlags.keyCertSign | x509.KeyUsageFlags.digitalSignature, true));
48
67
  var cert = await x509.X509CertificateGenerator.createSelfSigned({
49
- serialNumber: "01",
50
- name: "CN=blamejs-mds3-test-root",
51
- notBefore: now,
68
+ serialNumber: opts.serial || "01",
69
+ name: "CN=" + (opts.cn || "blamejs-mds3-test-root"),
70
+ notBefore: notBefore,
52
71
  notAfter: notAfter,
53
- signingAlgorithm: { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
72
+ signingAlgorithm: signAlg,
54
73
  keys: keys,
55
- extensions: [
56
- new x509.BasicConstraintsExtension(true, 0, true),
57
- new x509.KeyUsagesExtension(
58
- x509.KeyUsageFlags.keyCertSign | x509.KeyUsageFlags.digitalSignature,
59
- true),
60
- ],
74
+ extensions: exts,
61
75
  });
62
76
  var pkcs8 = await nodeCrypto.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
63
77
  var pkB64 = Buffer.from(pkcs8).toString("base64").match(/.{1,64}/g).join("\n"); // allow:raw-byte-literal — RFC 7468 line width
@@ -65,35 +79,108 @@ async function _makeSelfSignedRsaCert() {
65
79
  return { keyPem: keyPem, certPem: cert.toString("pem") };
66
80
  }
67
81
 
82
+ // RS256 self-signed cert — the common case, matching the real FIDO Alliance
83
+ // BLOB shape. Thin wrapper over the general builder.
84
+ async function _makeSelfSignedRsaCert() {
85
+ return _makeCert({});
86
+ }
87
+
68
88
  function _b64url(buf) {
69
89
  return Buffer.from(buf).toString("base64url");
70
90
  }
71
91
 
72
- // Build a synthetic JWS-signed MDS3 BLOB. payload is the inner JSON;
73
- // keyPem signs it with RS256; certPem is the leaf x5c entry.
74
- function _makeBlob(payload, keyPem, certPem) {
75
- // Strip PEM markers + whitespace from cert to get DER-base64.
76
- var derB64 = certPem
77
- .replace(/-----BEGIN CERTIFICATE-----/g, "")
78
- .replace(/-----END CERTIFICATE-----/g, "")
79
- .replace(/\s+/g, "");
80
- var header = { alg: "RS256", typ: "JWT", x5c: [derB64] };
92
+ // Assemble the compact JWS from a caller-supplied header + payload, signing the
93
+ // signing-input with `hashAlgo` + `signOpts` (node:crypto.sign options). One
94
+ // core so the RS256 / ES256 / PS256 / Ed25519 fixture builders don't each
95
+ // re-roll the base64url-segment-then-sign body.
96
+ function _makeBlobSig(header, payload, keyPem, hashAlgo, signOpts) {
81
97
  var headerB64 = _b64url(JSON.stringify(header));
82
98
  var payloadB64 = _b64url(JSON.stringify(payload));
83
99
  var signingInput = headerB64 + "." + payloadB64;
84
- var sig = nodeCrypto.sign("sha256", Buffer.from(signingInput, "ascii"), {
85
- key: keyPem,
86
- padding: nodeCrypto.constants.RSA_PKCS1_PADDING,
87
- });
100
+ var sig = nodeCrypto.sign(hashAlgo, Buffer.from(signingInput, "ascii"),
101
+ Object.assign({ key: keyPem }, signOpts || {}));
88
102
  return signingInput + "." + _b64url(sig);
89
103
  }
90
104
 
91
- // In-future date (YYYY-MM-DD) so nextUpdate parsing succeeds.
105
+ // Build a synthetic JWS-signed MDS3 BLOB. payload is the inner JSON;
106
+ // keyPem signs it with RS256; certPem is the leaf x5c entry.
107
+ function _makeBlob(payload, keyPem, certPem) {
108
+ var header = { alg: "RS256", typ: "JWT", x5c: [_certDerB64(certPem)] };
109
+ return _makeBlobSig(header, payload, keyPem, "sha256",
110
+ { padding: nodeCrypto.constants.RSA_PKCS1_PADDING });
111
+ }
112
+
113
+ // In-future date (YYYY-MM-DD) so nextUpdate parsing succeeds. A negative
114
+ // argument produces a PAST date (used to drive the stale-BLOB refusal).
92
115
  function _futureDateString(daysFromNow) {
93
116
  var d = new Date(Date.now() + daysFromNow * 86400000); // allow:raw-byte-literal — ms-per-day
94
117
  return d.toISOString().slice(0, 10); // allow:raw-byte-literal — ISO date prefix length
95
118
  }
96
119
 
120
+ // Strip PEM markers + whitespace from a cert to get its DER-base64 (x5c form).
121
+ function _certDerB64(certPem) {
122
+ return certPem
123
+ .replace(/-----BEGIN CERTIFICATE-----/g, "")
124
+ .replace(/-----END CERTIFICATE-----/g, "")
125
+ .replace(/\s+/g, "");
126
+ }
127
+
128
+ // Like _makeBlob but the caller supplies the full JWS header (so a test can
129
+ // override alg / x5c to exercise the header-adversarial branches). The payload
130
+ // is still RS256-signed with keyPem, so the signature segment is valid,
131
+ // non-empty base64url even when the header advertises a different alg — the
132
+ // verifier reaches its alg check before the signature check.
133
+ function _makeBlobRaw(header, payload, keyPem) {
134
+ return _makeBlobSig(header, payload, keyPem, "sha256",
135
+ { padding: nodeCrypto.constants.RSA_PKCS1_PADDING });
136
+ }
137
+
138
+ // Mock httpClient.request with `handler`, reload fido-mds3 so it re-resolves
139
+ // the lazyRequire'd httpClient against the mock, run fn(fm), then restore the
140
+ // require cache. Mirrors testFetchRoundTrip's require-cache override so no real
141
+ // network handle is ever opened.
142
+ async function _withMockedHttp(handler, fn) {
143
+ var hcPath = require.resolve("../../lib/http-client");
144
+ var origHc = require.cache[hcPath].exports;
145
+ require.cache[hcPath].exports = Object.assign({}, origHc, { request: handler });
146
+ var fmPath = require.resolve("../../lib/auth/fido-mds3");
147
+ delete require.cache[fmPath];
148
+ var fm = require(fmPath);
149
+ try {
150
+ return await fn(fm);
151
+ } finally {
152
+ require.cache[hcPath].exports = origHc;
153
+ delete require.cache[fmPath];
154
+ }
155
+ }
156
+
157
+ // A request handler returning a 200 with `token` as the body.
158
+ function _respondWith(token) {
159
+ return async function () {
160
+ return { statusCode: 200, headers: {}, body: Buffer.from(token, "ascii") }; // allow:raw-byte-literal — HTTP success
161
+ };
162
+ }
163
+
164
+ // Patch the vendored SettingsService.getRootCertificates (the DEFAULT-trust-root
165
+ // resolver used when no caCertificate override is supplied), run fn, restore.
166
+ // `fakeGetter` receives the { identifier } arg fido-mds3 passes and returns the
167
+ // PEM array (or throws) so the no-trust-root fail-closed branch and the
168
+ // default-roots stale refusal can be driven without a live vendored bundle
169
+ // edit. fido-mds3 reads _wa.SettingsService.getRootCertificates dynamically at
170
+ // resolve time, so no module reload is needed — the same cached vendor object
171
+ // backs both this test and the primitive.
172
+ async function _withMockedRoots(fakeGetter, fn) {
173
+ var wa = require("../../lib/vendor/simplewebauthn-server.cjs");
174
+ var svc = wa.SettingsService;
175
+ var orig = svc.getRootCertificates;
176
+ svc.getRootCertificates = fakeGetter;
177
+ try {
178
+ return await fn();
179
+ } finally {
180
+ svc.getRootCertificates = orig;
181
+ }
182
+ }
183
+
97
184
  // ---- surface ----
98
185
 
99
186
  function testSurface() {
@@ -346,6 +433,86 @@ function testCertifiedLevelPlus() {
346
433
  rv.certifiedLevel.level === 3 && rv.certifiedLevel.plus === true);
347
434
  }
348
435
 
436
+ function testVerifyAuthenticatorAttestationKeyCompromise() {
437
+ // ATTESTATION_KEY_COMPROMISE is in the FIDO MDS3 3.1.4 compromise bucket: the
438
+ // manufacturer's batch-signing key is suspect, so every credential attested
439
+ // under it MUST be refused. Sibling of the REVOKED / USER_KEY_* refusals but
440
+ // previously untested.
441
+ var blob = {
442
+ entries: [{
443
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
444
+ metadataStatement: { description: "Compromised batch key" },
445
+ statusReports: [{ status: "ATTESTATION_KEY_COMPROMISE" }],
446
+ }],
447
+ };
448
+ var rv = b.auth.fidoMds3.verifyAuthenticator(blob, {
449
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
450
+ });
451
+ check("verifyAuthenticator ok=false on ATTESTATION_KEY_COMPROMISE", rv.ok === false);
452
+ check("verifyAuthenticator reason cites ATTESTATION_KEY_COMPROMISE",
453
+ rv.reason && /ATTESTATION_KEY_COMPROMISE/.test(rv.reason));
454
+ }
455
+
456
+ function testCertifiedLevelMissingDateOrdering() {
457
+ // A decertification (NOT_FIDO_CERTIFIED) appended AFTER a dated grant but
458
+ // WITHOUT its own effectiveDate must still win by array order (append order
459
+ // == chronological per spec). If the undated report is coerced to "" and run
460
+ // through a lexical compare it loses to every earlier DATED report, so
461
+ // certifiedLevel freezes at the stale L2 and a step-up policy requiring L2
462
+ // would accept a now-decertified authenticator (authenticator-assurance
463
+ // bypass).
464
+ var decertBlob = {
465
+ entries: [{
466
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
467
+ statusReports: [
468
+ { status: "FIDO_CERTIFIED_L2", effectiveDate: "2020-01-01" },
469
+ { status: "NOT_FIDO_CERTIFIED" }, // later in array, no effectiveDate
470
+ ],
471
+ }],
472
+ };
473
+ var rv = b.auth.fidoMds3.verifyAuthenticator(decertBlob, {
474
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
475
+ });
476
+ check("certifiedLevel: undated later NOT_FIDO_CERTIFIED decertifies to level 0",
477
+ rv.certifiedLevel.level === 0 && rv.certifiedLevel.plus === false);
478
+
479
+ // A downgrade whose newer level report has no effectiveDate must report the
480
+ // CURRENT (later) L1, not the historical dated L3.
481
+ var downgradeBlob = {
482
+ entries: [{
483
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
484
+ statusReports: [
485
+ { status: "FIDO_CERTIFIED_L3", effectiveDate: "2019-01-01" },
486
+ { status: "FIDO_CERTIFIED_L1" }, // later in array, no effectiveDate
487
+ ],
488
+ }],
489
+ };
490
+ var rv2 = b.auth.fidoMds3.verifyAuthenticator(downgradeBlob, {
491
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
492
+ });
493
+ check("certifiedLevel: undated later downgrade reports current L1, not historical L3",
494
+ rv2.certifiedLevel.level === 1);
495
+
496
+ // Symmetric case: an UPGRADE (later, higher level) whose effectiveDate is
497
+ // absent must also win by array order and report the current L3 — not be
498
+ // suppressed because its coerced "" loses the lexical compare against the
499
+ // earlier dated L1.
500
+ var upgradeBlob = {
501
+ entries: [{
502
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
503
+ statusReports: [
504
+ { status: "FIDO_CERTIFIED_L1", effectiveDate: "2024-01-01" },
505
+ { status: "FIDO_CERTIFIED_L3" }, // later in array, no effectiveDate
506
+ ],
507
+ }],
508
+ };
509
+ var rv3 = b.auth.fidoMds3.verifyAuthenticator(upgradeBlob, {
510
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
511
+ });
512
+ check("certifiedLevel: undated later upgrade reports current L3, not earlier L1",
513
+ rv3.certifiedLevel.level === 3);
514
+ }
515
+
349
516
  // ---- fetch (synthetic BLOB) ----
350
517
 
351
518
  async function testFetchRoundTrip() {
@@ -401,6 +568,207 @@ async function testFetchRoundTrip() {
401
568
  }
402
569
  }
403
570
 
571
+ async function testFetchRejectsStaleBlob() {
572
+ // A signed-but-expired BLOB (nextUpdate in the past) must be refused by the
573
+ // operator-facing fetch path, not accepted and cached. The internal
574
+ // _verifyAndParseBlob refuses stale BLOBs; fetch is the path operators
575
+ // actually drive, and it must enforce the same refusal (otherwise an attacker
576
+ // serving an ancient BLOB freezes the revoked-authenticator list at a chosen
577
+ // time).
578
+ var pair = await _makeSelfSignedRsaCert();
579
+ var payload = {
580
+ legalHeader: "Stale BLOB",
581
+ no: 7,
582
+ nextUpdate: _futureDateString(-7), // 7 days in the PAST — stale
583
+ entries: [{
584
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
585
+ metadataStatement: { description: "Stale entry" },
586
+ statusReports: [{ status: "REVOKED", effectiveDate: "2020-01-01" }],
587
+ }],
588
+ };
589
+ var token = _makeBlob(payload, pair.keyPem, pair.certPem);
590
+ var threw = null;
591
+ await _withMockedHttp(_respondWith(token), async function (fm) {
592
+ try {
593
+ await fm.fetch({ url: "https://stale.invalid/mds3", caCertificate: pair.certPem, force: true });
594
+ } catch (e) { threw = e; }
595
+ });
596
+ check("fetch refuses a stale BLOB (nextUpdate in the past)",
597
+ threw && /blob-stale/.test(threw.code || ""));
598
+ }
599
+
600
+ async function testFetchTamperedSignature() {
601
+ // Swap the payload segment after signing, keep the original header + sig: the
602
+ // signature no longer covers the payload, so the verify seam must refuse.
603
+ var pair = await _makeSelfSignedRsaCert();
604
+ var token = _makeBlob({
605
+ no: 1, nextUpdate: _futureDateString(7),
606
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
607
+ }, pair.keyPem, pair.certPem);
608
+ var parts = token.split(".");
609
+ var forgedPayload = _b64url(JSON.stringify({
610
+ no: 999, nextUpdate: _futureDateString(7),
611
+ entries: [{ aaguid: "ffffffff-ffff-ffff-ffff-ffffffffffff", statusReports: [] }],
612
+ }));
613
+ var forged = parts[0] + "." + forgedPayload + "." + parts[2];
614
+ var threw = null;
615
+ await _withMockedHttp(_respondWith(forged), async function (fm) {
616
+ try {
617
+ await fm.fetch({ url: "https://tamper.invalid/mds3", caCertificate: pair.certPem, force: true });
618
+ } catch (e) { threw = e; }
619
+ });
620
+ check("fetch refuses a BLOB whose signature does not cover the payload",
621
+ threw && /bad-signature/.test(threw.code || ""));
622
+ }
623
+
624
+ async function testFetchWrongTrustRoot() {
625
+ // The BLOB is signed by `signer`; the operator pins a DIFFERENT root
626
+ // (`stranger`). The x5c tail cannot anchor to it -> chain-not-anchored.
627
+ var signer = await _makeSelfSignedRsaCert();
628
+ var stranger = await _makeSelfSignedRsaCert();
629
+ var token = _makeBlob({
630
+ no: 2, nextUpdate: _futureDateString(7),
631
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
632
+ }, signer.keyPem, signer.certPem);
633
+ var threw = null;
634
+ await _withMockedHttp(_respondWith(token), async function (fm) {
635
+ try {
636
+ await fm.fetch({ url: "https://wrongroot.invalid/mds3", caCertificate: stranger.certPem, force: true });
637
+ } catch (e) { threw = e; }
638
+ });
639
+ check("fetch refuses a BLOB that does not anchor to the pinned trust root",
640
+ threw && /chain-not-anchored/.test(threw.code || ""));
641
+ }
642
+
643
+ async function testFetchUnsupportedAlg() {
644
+ // HS256 (HMAC) is the canonical alg-confusion vector; the MDS3 verifier's alg
645
+ // table has no HMAC/none entry, so it must refuse rather than treat the leaf
646
+ // cert's public key as an HMAC secret. The chain still anchors (self-signed
647
+ // via caCertificate), so the refusal proves the alg gate, not chain failure.
648
+ var pair = await _makeSelfSignedRsaCert();
649
+ var header = { alg: "HS256", typ: "JWT", x5c: [_certDerB64(pair.certPem)] };
650
+ var token = _makeBlobRaw(header, {
651
+ no: 3, nextUpdate: _futureDateString(7),
652
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
653
+ }, pair.keyPem);
654
+ var threw = null;
655
+ await _withMockedHttp(_respondWith(token), async function (fm) {
656
+ try {
657
+ await fm.fetch({ url: "https://badalg.invalid/mds3", caCertificate: pair.certPem, force: true });
658
+ } catch (e) { threw = e; }
659
+ });
660
+ check("fetch refuses an HMAC alg (no alg-confusion path)",
661
+ threw && /unsupported-alg/.test(threw.code || ""));
662
+ }
663
+
664
+ async function testFetchRejectsImpossibleNextUpdate() {
665
+ // 2026-02-31 is not a real calendar date; _parseNextUpdate must reject it
666
+ // (Date.UTC would silently normalise it to 2026-03-03 and let a malformed
667
+ // nextUpdate masquerade as a valid future timestamp). Driven through fetch.
668
+ var pair = await _makeSelfSignedRsaCert();
669
+ var token = _makeBlob({
670
+ no: 1, nextUpdate: "2026-02-31",
671
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
672
+ }, pair.keyPem, pair.certPem);
673
+ var threw = null;
674
+ await _withMockedHttp(_respondWith(token), async function (fm) {
675
+ try {
676
+ await fm.fetch({ url: "https://baddate.invalid/mds3", caCertificate: pair.certPem, force: true });
677
+ } catch (e) { threw = e; }
678
+ });
679
+ check("fetch rejects an impossible calendar nextUpdate (2026-02-31)",
680
+ threw && /bad-payload/.test(threw.code || ""));
681
+ }
682
+
683
+ async function testFetchMalformedBlobHeaders() {
684
+ var pair = await _makeSelfSignedRsaCert();
685
+ var goodPayload = {
686
+ no: 1, nextUpdate: _futureDateString(7),
687
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
688
+ };
689
+ var noAlg = _makeBlobRaw({ typ: "JWT", x5c: [_certDerB64(pair.certPem)] }, goodPayload, pair.keyPem);
690
+ var noX5c = _makeBlobRaw({ alg: "RS256", typ: "JWT" }, goodPayload, pair.keyPem);
691
+ var badX5c = _makeBlobRaw({ alg: "RS256", typ: "JWT", x5c: ["!!!not-a-cert!!!"] }, goodPayload, pair.keyPem);
692
+
693
+ async function fetchExpect(token, codeRe, label) {
694
+ var threw = null;
695
+ await _withMockedHttp(_respondWith(token), async function (fm) {
696
+ try {
697
+ await fm.fetch({ url: "https://malformed.invalid/mds3", caCertificate: pair.certPem, force: true });
698
+ } catch (e) { threw = e; }
699
+ });
700
+ check(label, threw && codeRe.test(threw.code || ""));
701
+ }
702
+ await fetchExpect(noAlg, /bad-jws-header/, "fetch rejects a header missing alg");
703
+ await fetchExpect(noX5c, /bad-jws-header/, "fetch rejects a header missing x5c");
704
+ await fetchExpect(badX5c, /bad-x5c/, "fetch rejects an unparseable x5c cert");
705
+ }
706
+
707
+ async function testFetchRejectsBadStatus() {
708
+ // Root resolution (a plain string caCertificate) succeeds before the request;
709
+ // the non-2xx status is refused inside the loader.
710
+ var threw = null;
711
+ await _withMockedHttp(async function () {
712
+ return { statusCode: 404, headers: {}, body: Buffer.from("not found", "ascii") }; // allow:raw-byte-literal — HTTP error
713
+ }, async function (fm) {
714
+ try {
715
+ await fm.fetch({ url: "https://notfound.invalid/mds3", caCertificate: "ca-not-reached", force: true });
716
+ } catch (e) { threw = e; }
717
+ });
718
+ check("fetch refuses a non-2xx HTTP status",
719
+ threw && /bad-status/.test(threw.code || ""));
720
+ }
721
+
722
+ async function testFetchNetworkFailure() {
723
+ var threw = null;
724
+ await _withMockedHttp(async function () {
725
+ throw new Error("ECONNREFUSED synthetic");
726
+ }, async function (fm) {
727
+ try {
728
+ await fm.fetch({ url: "https://down.invalid/mds3", caCertificate: "ca-not-reached", force: true });
729
+ } catch (e) { threw = e; }
730
+ });
731
+ check("fetch wraps a transport failure as fido-mds3/network",
732
+ threw && /fido-mds3\/network/.test(threw.code || ""));
733
+ }
734
+
735
+ async function testFetchBadCaCertificate() {
736
+ // _resolveRoots runs before any HTTP; each bad shape fails closed with
737
+ // bad-ca. No mock needed — the throw precedes the request.
738
+ async function expectBadCa(ca, label) {
739
+ var threw = null;
740
+ try { await b.auth.fidoMds3.fetch({ url: "https://x.invalid/mds3", caCertificate: ca }); }
741
+ catch (e) { threw = e; }
742
+ check(label, threw && /bad-ca/.test(threw.code || ""));
743
+ }
744
+ await expectBadCa([], "fetch rejects an empty caCertificate array");
745
+ await expectBadCa([123], "fetch rejects a non-string caCertificate array element"); // allow:raw-byte-literal — bad type sample
746
+ await expectBadCa(5, "fetch rejects a non-string/non-array caCertificate"); // allow:raw-byte-literal — bad type sample
747
+ }
748
+
749
+ async function testFetchCacheHitAndForceBypass() {
750
+ // The cache path: a non-force second call is served from cache (no new HTTP);
751
+ // force:true bypasses the cache and refetches.
752
+ var pair = await _makeSelfSignedRsaCert();
753
+ var token = _makeBlob({
754
+ no: 100, nextUpdate: _futureDateString(7), // allow:raw-byte-literal — fixture identifier
755
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
756
+ }, pair.keyPem, pair.certPem);
757
+ var calls = 0;
758
+ await _withMockedHttp(async function () {
759
+ calls += 1;
760
+ return { statusCode: 200, headers: {}, body: Buffer.from(token, "ascii") }; // allow:raw-byte-literal — HTTP success
761
+ }, async function (fm) {
762
+ var url = "https://cache.invalid/mds3";
763
+ var a = await fm.fetch({ url: url, caCertificate: pair.certPem, force: true });
764
+ check("fetch (force) performs one HTTP call", calls === 1 && a.no === 100); // allow:raw-byte-literal — fixture identifier
765
+ var hit = await fm.fetch({ url: url, caCertificate: pair.certPem });
766
+ check("fetch serves the second (non-force) call from cache", calls === 1 && hit.no === 100); // allow:raw-byte-literal — fixture identifier
767
+ var refetched = await fm.fetch({ url: url, caCertificate: pair.certPem, force: true });
768
+ check("fetch force:true bypasses the cache and refetches", calls === 2 && refetched.no === 100); // allow:raw-byte-literal — fixture identifier
769
+ });
770
+ }
771
+
404
772
  async function testFetchRejectsNonHttps() {
405
773
  var threw = null;
406
774
  try { await b.auth.fidoMds3.fetch({ url: "http://insecure.example/mds3" }); }
@@ -445,6 +813,473 @@ async function testInternalVerifyRejectsBadJws() {
445
813
  threw && /bad-jws/.test(threw.code || ""));
446
814
  }
447
815
 
816
+ // ---- fetch: x5c chain validity + anchoring adversarial branches ----
817
+
818
+ async function testFetchExpiredSigningCert() {
819
+ // A signed BLOB whose leaf certificate has already expired must be refused,
820
+ // even though the JWS signature itself would verify. An attacker replaying an
821
+ // ancient BLOB signed under a now-expired cert must not slip past the validity
822
+ // window (fail-open would pin operators to a frozen, possibly-revoked list).
823
+ var expired = await _makeCert({
824
+ notBefore: new Date(Date.now() - 30 * 86400000), // allow:raw-byte-literal — fixture days
825
+ notAfter: new Date(Date.now() - 10 * 86400000), // allow:raw-byte-literal — fixture days
826
+ });
827
+ var token = _makeBlob({
828
+ no: 1, nextUpdate: _futureDateString(7),
829
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
830
+ }, expired.keyPem, expired.certPem);
831
+ var threw = null;
832
+ await _withMockedHttp(_respondWith(token), async function (fm) {
833
+ try {
834
+ await fm.fetch({ url: "https://expired.invalid/mds3", caCertificate: expired.certPem, force: true });
835
+ } catch (e) { threw = e; }
836
+ });
837
+ check("fetch refuses a BLOB whose leaf signing cert has expired",
838
+ threw && /cert-expired/.test(threw.code || ""));
839
+ }
840
+
841
+ async function testFetchNotYetValidCert() {
842
+ // A leaf certificate whose notBefore is in the future is not yet valid and
843
+ // must be refused — a pre-dated / clock-skew forgery must not validate.
844
+ var future = await _makeCert({
845
+ notBefore: new Date(Date.now() + 20 * 86400000), // allow:raw-byte-literal — fixture days
846
+ notAfter: new Date(Date.now() + 40 * 86400000), // allow:raw-byte-literal — fixture days
847
+ });
848
+ var token = _makeBlob({
849
+ no: 1, nextUpdate: _futureDateString(7),
850
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
851
+ }, future.keyPem, future.certPem);
852
+ var threw = null;
853
+ await _withMockedHttp(_respondWith(token), async function (fm) {
854
+ try {
855
+ await fm.fetch({ url: "https://notyet.invalid/mds3", caCertificate: future.certPem, force: true });
856
+ } catch (e) { threw = e; }
857
+ });
858
+ check("fetch refuses a BLOB whose leaf signing cert is not yet valid",
859
+ threw && /cert-not-yet-valid/.test(threw.code || ""));
860
+ }
861
+
862
+ async function testFetchBrokenChain() {
863
+ // A two-cert x5c where the leaf is NOT validly issued by the second link must
864
+ // be refused with chain-broken — a cert spliced into the chain that did not
865
+ // sign the leaf cannot bridge it to the root, even when that second cert is
866
+ // itself the pinned trust anchor.
867
+ var leaf = await _makeCert({ cn: "blamejs-leaf" });
868
+ var other = await _makeCert({ cn: "blamejs-other-ca" });
869
+ var header = { alg: "RS256", typ: "JWT",
870
+ x5c: [_certDerB64(leaf.certPem), _certDerB64(other.certPem)] };
871
+ var token = _makeBlobRaw(header, {
872
+ no: 1, nextUpdate: _futureDateString(7),
873
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
874
+ }, leaf.keyPem);
875
+ var threw = null;
876
+ await _withMockedHttp(_respondWith(token), async function (fm) {
877
+ try {
878
+ await fm.fetch({ url: "https://broken.invalid/mds3", caCertificate: other.certPem, force: true });
879
+ } catch (e) { threw = e; }
880
+ });
881
+ check("fetch refuses a two-cert chain whose leaf is not issued by the next link",
882
+ threw && /chain-broken/.test(threw.code || ""));
883
+ }
884
+
885
+ async function testFetchGarbageRootInArrayStillAnchors() {
886
+ // caCertificate as an ARRAY exercises the array-of-PEMs override path; a
887
+ // garbage PEM among the roots must be skipped (parse-fail -> continue), and a
888
+ // valid trailing root still anchors the chain.
889
+ var pair = await _makeSelfSignedRsaCert();
890
+ var token = _makeBlob({
891
+ no: 5, nextUpdate: _futureDateString(7),
892
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
893
+ metadataStatement: { description: "arr" }, statusReports: [] }],
894
+ }, pair.keyPem, pair.certPem);
895
+ var garbageRoot = "-----BEGIN CERTIFICATE-----\nnot-a-real-cert\n-----END CERTIFICATE-----\n";
896
+ var blob = null, threw = null;
897
+ await _withMockedHttp(_respondWith(token), async function (fm) {
898
+ try {
899
+ blob = await fm.fetch({ url: "https://arrroot.invalid/mds3",
900
+ caCertificate: [garbageRoot, pair.certPem], force: true });
901
+ } catch (e) { threw = e; }
902
+ });
903
+ check("fetch skips an unparseable root in the caCertificate array and anchors on a valid one",
904
+ !threw && blob && blob.no === 5); // allow:raw-byte-literal — fixture identifier
905
+ }
906
+
907
+ async function testFetchFingerprintAnchorsPinnedNonCaLeaf() {
908
+ // A self-signed, NON-CA leaf pinned as the trust root anchors via the exact
909
+ // fingerprint256-match fallback: issuerValidlyIssued fails because the pinned
910
+ // cert asserts basicConstraints cA:FALSE, but an operator pinning that exact
911
+ // cert as their root trusts it by identity. Covers the CAs-ship-root-in-x5c
912
+ // convenience branch (a SHA-256 collision would be needed to abuse it).
913
+ var leaf = await _makeCert({ ca: false });
914
+ var token = _makeBlob({
915
+ no: 6, nextUpdate: _futureDateString(7),
916
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
917
+ }, leaf.keyPem, leaf.certPem);
918
+ var blob = null, threw = null;
919
+ await _withMockedHttp(_respondWith(token), async function (fm) {
920
+ try {
921
+ blob = await fm.fetch({ url: "https://fp.invalid/mds3", caCertificate: leaf.certPem, force: true });
922
+ } catch (e) { threw = e; }
923
+ });
924
+ check("fetch anchors a pinned non-CA leaf via exact fingerprint match",
925
+ !threw && blob && blob.no === 6); // allow:raw-byte-literal — fixture identifier
926
+ }
927
+
928
+ // ---- fetch: JWS alg verify branches (ES256 / PS256 / alg-key mismatch) ----
929
+
930
+ async function testFetchEs256() {
931
+ // An ES256 (ECDSA P-256) BLOB exercises the dsaEncoding verify branch. MDS3 is
932
+ // RS256 in practice, but the shared alg table lists ES256; a real ES256 BLOB
933
+ // must validate without a code edit.
934
+ var ec = await _makeCert({ algo: "EC" });
935
+ var header = { alg: "ES256", typ: "JWT", x5c: [_certDerB64(ec.certPem)] };
936
+ var token = _makeBlobSig(header, {
937
+ no: 7, nextUpdate: _futureDateString(7),
938
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
939
+ metadataStatement: { description: "ec" }, statusReports: [] }],
940
+ }, ec.keyPem, "sha256", { dsaEncoding: "ieee-p1363" });
941
+ var blob = null, threw = null;
942
+ await _withMockedHttp(_respondWith(token), async function (fm) {
943
+ try {
944
+ blob = await fm.fetch({ url: "https://es256.invalid/mds3", caCertificate: ec.certPem, force: true });
945
+ } catch (e) { threw = e; }
946
+ });
947
+ check("fetch verifies an ES256 (ECDSA) BLOB",
948
+ !threw && blob && blob.no === 7); // allow:raw-byte-literal — fixture identifier
949
+ }
950
+
951
+ async function testFetchPs256() {
952
+ // A PS256 (RSASSA-PSS) BLOB exercises the saltLength verify branch. The
953
+ // signer's RSA_PSS_SALTLEN_DIGEST salt equals the SHA-256 digest length, which
954
+ // is exactly the salt length the shared verifier expects for PS256.
955
+ var rsa = await _makeSelfSignedRsaCert();
956
+ var header = { alg: "PS256", typ: "JWT", x5c: [_certDerB64(rsa.certPem)] };
957
+ var token = _makeBlobSig(header, {
958
+ no: 8, nextUpdate: _futureDateString(7),
959
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
960
+ }, rsa.keyPem, "sha256", {
961
+ padding: nodeCrypto.constants.RSA_PKCS1_PSS_PADDING,
962
+ saltLength: nodeCrypto.constants.RSA_PSS_SALTLEN_DIGEST,
963
+ });
964
+ var blob = null, threw = null;
965
+ await _withMockedHttp(_respondWith(token), async function (fm) {
966
+ try {
967
+ blob = await fm.fetch({ url: "https://ps256.invalid/mds3", caCertificate: rsa.certPem, force: true });
968
+ } catch (e) { threw = e; }
969
+ });
970
+ check("fetch verifies a PS256 (RSASSA-PSS) BLOB",
971
+ !threw && blob && blob.no === 8); // allow:raw-byte-literal — fixture identifier
972
+ }
973
+
974
+ async function testFetchAlgKeyTypeMismatch() {
975
+ // A header advertising RS256 (a hash + RSA-padding verify) over a leaf carrying
976
+ // an Ed25519 key makes node:crypto.verify throw ("invalid digest"); the
977
+ // verifier must CATCH it and refuse as bad-signature rather than let the
978
+ // exception crash the request. Alg/key-type confusion is refused, not
979
+ // propagated.
980
+ var ed = await _makeCert({ algo: "Ed25519" });
981
+ var header = { alg: "RS256", typ: "JWT", x5c: [_certDerB64(ed.certPem)] };
982
+ var token = _makeBlobSig(header, {
983
+ no: 9, nextUpdate: _futureDateString(7),
984
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
985
+ }, ed.keyPem, null, {});
986
+ var threw = null;
987
+ await _withMockedHttp(_respondWith(token), async function (fm) {
988
+ try {
989
+ await fm.fetch({ url: "https://algmix.invalid/mds3", caCertificate: ed.certPem, force: true });
990
+ } catch (e) { threw = e; }
991
+ });
992
+ check("fetch refuses (not crashes) when the leaf key type cannot satisfy the header alg",
993
+ threw && /bad-signature/.test(threw.code || ""));
994
+ }
995
+
996
+ // ---- fetch: JWS parse-segment adversarial branches ----
997
+
998
+ async function testFetchBadJwsSegment() {
999
+ // A JWS whose SIGNATURE segment carries a non-base64url character is refused at
1000
+ // decode (bad-jws-segment). The header/payload segments are decoded inside a
1001
+ // try that rewraps any decode failure as bad-jws-json, so the signature
1002
+ // segment — decoded outside that try — is the one that surfaces the raw
1003
+ // segment error; a mangled sig can't be quietly coerced to empty bytes.
1004
+ var pair = await _makeSelfSignedRsaCert();
1005
+ var token = _makeBlob({
1006
+ no: 1, nextUpdate: _futureDateString(7),
1007
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
1008
+ }, pair.keyPem, pair.certPem);
1009
+ var parts = token.split(".");
1010
+ var mangled = parts[0] + "." + parts[1] + "." + parts[2] + "#bad"; // '#' is not base64url
1011
+ var threw = null;
1012
+ await _withMockedHttp(_respondWith(mangled), async function (fm) {
1013
+ try {
1014
+ await fm.fetch({ url: "https://seg.invalid/mds3", caCertificate: pair.certPem, force: true });
1015
+ } catch (e) { threw = e; }
1016
+ });
1017
+ check("fetch refuses a JWS signature segment with a non-base64url character",
1018
+ threw && /bad-jws-segment/.test(threw.code || ""));
1019
+ }
1020
+
1021
+ async function testFetchBadJwsJson() {
1022
+ // A header segment that is valid base64url but decodes to invalid JSON is
1023
+ // refused as bad-jws-json (the decode succeeds, the parse fails).
1024
+ var pair = await _makeSelfSignedRsaCert();
1025
+ var token = _makeBlob({
1026
+ no: 1, nextUpdate: _futureDateString(7),
1027
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
1028
+ }, pair.keyPem, pair.certPem);
1029
+ var parts = token.split(".");
1030
+ var mangled = _b64url("{ not valid json ") + "." + parts[1] + "." + parts[2];
1031
+ var threw = null;
1032
+ await _withMockedHttp(_respondWith(mangled), async function (fm) {
1033
+ try {
1034
+ await fm.fetch({ url: "https://json.invalid/mds3", caCertificate: pair.certPem, force: true });
1035
+ } catch (e) { threw = e; }
1036
+ });
1037
+ check("fetch refuses a base64url header that is not valid JSON",
1038
+ threw && /bad-jws-json/.test(threw.code || ""));
1039
+ }
1040
+
1041
+ async function testFetchBadX5cElements() {
1042
+ // x5c array present but the element itself is unusable. An empty-string and a
1043
+ // non-string element are refused as bad-x5c (inside chain validation); an
1044
+ // EMPTY x5c array is refused earlier as bad-jws-header (the header-shape gate).
1045
+ var pair = await _makeSelfSignedRsaCert();
1046
+ var goodPayload = {
1047
+ no: 1, nextUpdate: _futureDateString(7),
1048
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
1049
+ };
1050
+ var emptyStr = _makeBlobRaw({ alg: "RS256", typ: "JWT", x5c: [""] }, goodPayload, pair.keyPem);
1051
+ var nonString = _makeBlobRaw({ alg: "RS256", typ: "JWT", x5c: [123] }, goodPayload, pair.keyPem); // allow:raw-byte-literal — bad x5c type
1052
+ var emptyArr = _makeBlobRaw({ alg: "RS256", typ: "JWT", x5c: [] }, goodPayload, pair.keyPem);
1053
+ async function fetchExpect(token, codeRe, label) {
1054
+ var threw = null;
1055
+ await _withMockedHttp(_respondWith(token), async function (fm) {
1056
+ try {
1057
+ await fm.fetch({ url: "https://x5c.invalid/mds3", caCertificate: pair.certPem, force: true });
1058
+ } catch (e) { threw = e; }
1059
+ });
1060
+ check(label, threw && codeRe.test(threw.code || ""));
1061
+ }
1062
+ await fetchExpect(emptyStr, /bad-x5c/, "fetch rejects an empty-string x5c element");
1063
+ await fetchExpect(nonString, /bad-x5c/, "fetch rejects a non-string x5c element");
1064
+ await fetchExpect(emptyArr, /bad-jws-header/, "fetch rejects an empty x5c array");
1065
+ }
1066
+
1067
+ // ---- fetch: payload-shape + nextUpdate adversarial branches ----
1068
+
1069
+ async function testFetchPayloadMissingEntries() {
1070
+ // A validly-signed, anchored BLOB whose payload lacks an entries array is
1071
+ // refused as bad-payload.
1072
+ var pair = await _makeSelfSignedRsaCert();
1073
+ var token = _makeBlob({ no: 1, nextUpdate: _futureDateString(7) }, pair.keyPem, pair.certPem);
1074
+ var threw = null;
1075
+ await _withMockedHttp(_respondWith(token), async function (fm) {
1076
+ try {
1077
+ await fm.fetch({ url: "https://noentries.invalid/mds3", caCertificate: pair.certPem, force: true });
1078
+ } catch (e) { threw = e; }
1079
+ });
1080
+ check("fetch refuses a payload with no entries array",
1081
+ threw && /bad-payload/.test(threw.code || ""));
1082
+ }
1083
+
1084
+ async function testFetchPayloadMissingNo() {
1085
+ // A payload with entries but no numeric 'no' sequence number is refused.
1086
+ var pair = await _makeSelfSignedRsaCert();
1087
+ var token = _makeBlob({ nextUpdate: _futureDateString(7), entries: [] }, pair.keyPem, pair.certPem);
1088
+ var threw = null;
1089
+ await _withMockedHttp(_respondWith(token), async function (fm) {
1090
+ try {
1091
+ await fm.fetch({ url: "https://nono.invalid/mds3", caCertificate: pair.certPem, force: true });
1092
+ } catch (e) { threw = e; }
1093
+ });
1094
+ check("fetch refuses a payload missing the numeric 'no'",
1095
+ threw && /bad-payload/.test(threw.code || ""));
1096
+ }
1097
+
1098
+ async function testFetchBadNextUpdateShapes() {
1099
+ // nextUpdate must be a real YYYY-MM-DD calendar date. A non-string value, a
1100
+ // non-date string, and an out-of-range month each parse to null and are
1101
+ // refused as bad-payload (a malformed nextUpdate must not masquerade as a
1102
+ // valid future timestamp and influence the cache-TTL clamp).
1103
+ var pair = await _makeSelfSignedRsaCert();
1104
+ function payload(nu) {
1105
+ return { no: 1, nextUpdate: nu,
1106
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }] };
1107
+ }
1108
+ var numberNu = _makeBlob(payload(20260101), pair.keyPem, pair.certPem); // allow:raw-byte-literal — non-string nextUpdate
1109
+ var wordNu = _makeBlob(payload("not-a-date"), pair.keyPem, pair.certPem);
1110
+ var badMonth = _makeBlob(payload("2026-13-15"), pair.keyPem, pair.certPem);
1111
+ async function fetchExpect(token, label) {
1112
+ var threw = null;
1113
+ await _withMockedHttp(_respondWith(token), async function (fm) {
1114
+ try {
1115
+ await fm.fetch({ url: "https://nu.invalid/mds3", caCertificate: pair.certPem, force: true });
1116
+ } catch (e) { threw = e; }
1117
+ });
1118
+ check(label, threw && /bad-payload/.test(threw.code || ""));
1119
+ }
1120
+ await fetchExpect(numberNu, "fetch refuses a non-string nextUpdate");
1121
+ await fetchExpect(wordNu, "fetch refuses a nextUpdate that is not a date");
1122
+ await fetchExpect(badMonth, "fetch refuses a nextUpdate with an out-of-range month");
1123
+ }
1124
+
1125
+ async function testFetchFarFutureNextUpdateClampsTtl() {
1126
+ // A nextUpdate far beyond the 30-day cache ceiling is still accepted; the TTL
1127
+ // clamp caps the cached lifetime at the ceiling so a runaway nextUpdate can't
1128
+ // freeze trust indefinitely.
1129
+ var pair = await _makeSelfSignedRsaCert();
1130
+ var token = _makeBlob({
1131
+ no: 11, nextUpdate: _futureDateString(45), // allow:raw-byte-literal — beyond 30-day ceiling
1132
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
1133
+ }, pair.keyPem, pair.certPem);
1134
+ var blob = null, threw = null;
1135
+ await _withMockedHttp(_respondWith(token), async function (fm) {
1136
+ try {
1137
+ blob = await fm.fetch({ url: "https://farfuture.invalid/mds3", caCertificate: pair.certPem, force: true });
1138
+ } catch (e) { threw = e; }
1139
+ });
1140
+ check("fetch accepts a far-future nextUpdate (TTL clamped to the ceiling)",
1141
+ !threw && blob && blob.no === 11); // allow:raw-byte-literal — fixture identifier
1142
+ }
1143
+
1144
+ // ---- fetch / parse: default-trust-root resolution branches ----
1145
+
1146
+ async function testFetchNoTrustRootWhenVendorEmpty() {
1147
+ // When the DEFAULT trust-root resolver yields no anchors, fetch must fail
1148
+ // closed with no-trust-root rather than proceed against an empty root set
1149
+ // (which would let any chain "anchor" against nothing). Driven for an empty
1150
+ // return, a null return, and a throwing resolver.
1151
+ async function expectNoRoot(getter, label) {
1152
+ var threw = null;
1153
+ await _withMockedRoots(getter, async function () {
1154
+ try { await b.auth.fidoMds3.fetch({ url: "https://noroot.invalid/mds3" }); }
1155
+ catch (e) { threw = e; }
1156
+ });
1157
+ check(label, threw && /no-trust-root/.test(threw.code || ""));
1158
+ }
1159
+ await expectNoRoot(function () { return []; },
1160
+ "fetch fails closed when the default root set is empty");
1161
+ await expectNoRoot(function () { return null; },
1162
+ "fetch fails closed when the default root resolver returns null");
1163
+ await expectNoRoot(function () { throw new Error("vendor boom"); },
1164
+ "fetch fails closed when the default root resolver throws");
1165
+ }
1166
+
1167
+ async function testParsePathRefusesStaleBlob() {
1168
+ // The internal parse path (_verifyAndParseBlob, DEFAULT vendored roots) must
1169
+ // enforce the same stale-BLOB refusal as fetch — both route through the one
1170
+ // shared verifier. Pinning the default root to a self-signed cert lets the
1171
+ // parse path reach the stale check on an anchoring chain and confirms it
1172
+ // refuses a nextUpdate-in-the-past BLOB (the v0.16.18 fail-open class, on the
1173
+ // non-fetch path).
1174
+ var pair = await _makeSelfSignedRsaCert();
1175
+ var token = _makeBlob({
1176
+ no: 1, nextUpdate: _futureDateString(-7), // 7 days in the PAST — stale
1177
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
1178
+ }, pair.keyPem, pair.certPem);
1179
+ var threw = null;
1180
+ await _withMockedRoots(function () { return [pair.certPem]; }, async function () {
1181
+ try { b.auth.fidoMds3._verifyAndParseBlob(token); }
1182
+ catch (e) { threw = e; }
1183
+ });
1184
+ check("_verifyAndParseBlob (default-roots parse path) refuses a stale BLOB",
1185
+ threw && /blob-stale/.test(threw.code || ""));
1186
+ }
1187
+
1188
+ async function testFetchNoArgUsesDefaultRoots() {
1189
+ // fetch() with no argument object exercises the opts-defaulting path and the
1190
+ // real vendored default-root resolution. A synthetic BLOB signed by a test
1191
+ // cert cannot anchor to the genuine FIDO root, so it is refused — proving
1192
+ // fetch() reaches root resolution + chain anchoring even with no opts passed.
1193
+ var pair = await _makeSelfSignedRsaCert();
1194
+ var token = _makeBlob({
1195
+ no: 1, nextUpdate: _futureDateString(7),
1196
+ entries: [{ aaguid: "01234567-89ab-cdef-0123-456789abcdef", statusReports: [] }],
1197
+ }, pair.keyPem, pair.certPem);
1198
+ var threw = null;
1199
+ await _withMockedHttp(_respondWith(token), async function (fm) {
1200
+ try { await fm.fetch(); }
1201
+ catch (e) { threw = e; }
1202
+ });
1203
+ check("fetch() with no opts resolves default roots and refuses an unanchored BLOB",
1204
+ threw && /chain-not-anchored/.test(threw.code || ""));
1205
+ }
1206
+
1207
+ async function testFetchNetworkFailureNonError() {
1208
+ // The transport rejection is normalized to fido-mds3/network even when it is
1209
+ // not a well-formed Error (a message-less value); the network wrapper falls
1210
+ // back to String(e) rather than surfacing "undefined" in the audit + message.
1211
+ var threw = null;
1212
+ await _withMockedHttp(async function () {
1213
+ var rejection = new Error(""); // Error with an empty message
1214
+ throw rejection;
1215
+ }, async function (fm) {
1216
+ try {
1217
+ await fm.fetch({ url: "https://nonerr.invalid/mds3", caCertificate: "ca-not-reached", force: true });
1218
+ } catch (e) { threw = e; }
1219
+ });
1220
+ check("fetch normalizes a message-less transport rejection to fido-mds3/network",
1221
+ threw && /fido-mds3\/network/.test(threw.code || ""));
1222
+ }
1223
+
1224
+ // ---- lookupAaguid / certifiedLevel malformed-entry branches ----
1225
+
1226
+ function testLookupAaguidSkipsMalformedEntries() {
1227
+ // Entries that are null or whose aaguid is non-string are skipped during
1228
+ // lookup; a valid later entry still resolves.
1229
+ var blob = {
1230
+ entries: [
1231
+ null,
1232
+ { aaguid: 12345, metadataStatement: { description: "non-string aaguid" } }, // allow:raw-byte-literal — malformed entry
1233
+ { aaguid: "01234567-89ab-cdef-0123-456789abcdef",
1234
+ metadataStatement: { description: "good" }, statusReports: [] },
1235
+ ],
1236
+ };
1237
+ var hit = b.auth.fidoMds3.lookupAaguid(blob, "01234567-89ab-cdef-0123-456789abcdef");
1238
+ check("lookupAaguid skips null + non-string-aaguid entries and still finds the match",
1239
+ hit && hit.metadataStatement.description === "good");
1240
+ }
1241
+
1242
+ function testCertifiedLevelSkipsMalformedReports() {
1243
+ // A null report, a non-string status, and an over-64-char status token are all
1244
+ // skipped when resolving the certified level; only the well-formed grant
1245
+ // counts. Guards the length-bound-before-regex convention (an unbounded status
1246
+ // must never reach the CERT_LEVEL_RE test).
1247
+ var blob = {
1248
+ entries: [{
1249
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
1250
+ statusReports: [
1251
+ null,
1252
+ { status: 42 }, // allow:raw-byte-literal — non-string status
1253
+ { status: "A".repeat(65) }, // allow:raw-byte-literal — over-64-char status
1254
+ { status: "FIDO_CERTIFIED_L1" },
1255
+ ],
1256
+ }],
1257
+ };
1258
+ var rv = b.auth.fidoMds3.verifyAuthenticator(blob, {
1259
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
1260
+ });
1261
+ check("certifiedLevel ignores null / non-string / over-long status reports",
1262
+ rv.certifiedLevel.level === 1 && rv.ok === true);
1263
+ }
1264
+
1265
+ function testVerifyAuthenticatorEntryWithoutStatusReports() {
1266
+ // An entry that omits statusReports (a non-array) is treated as an empty report
1267
+ // list: ok=true, certifiedLevel 0. Exercises the non-array coercion in
1268
+ // verifyAuthenticator.
1269
+ var blob = {
1270
+ entries: [{
1271
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
1272
+ metadataStatement: { description: "no reports" },
1273
+ }],
1274
+ };
1275
+ var rv = b.auth.fidoMds3.verifyAuthenticator(blob, {
1276
+ aaguid: "01234567-89ab-cdef-0123-456789abcdef",
1277
+ });
1278
+ check("verifyAuthenticator treats a missing statusReports as empty (ok=true, level 0)",
1279
+ rv.ok === true && rv.certifiedLevel.level === 0 &&
1280
+ rv.statement && rv.statement.description === "no reports");
1281
+ }
1282
+
448
1283
  // ---- run ----
449
1284
 
450
1285
  // fido-mds3.fetch dials the MDS3 endpoint through the shared httpClient
@@ -471,14 +1306,48 @@ async function run() {
471
1306
  testVerifyAuthenticatorDecertified();
472
1307
  testVerifyAuthenticatorPhysicalCompromise();
473
1308
  testVerifyAuthenticatorRemoteCompromise();
1309
+ testVerifyAuthenticatorAttestationKeyCompromise();
474
1310
  testVerifyAuthenticatorUnknownAaguid();
475
1311
  testVerifyAuthenticatorBadInputs();
476
1312
  testCertifiedLevelPlus();
1313
+ testCertifiedLevelMissingDateOrdering();
477
1314
  await testFetchRoundTrip();
1315
+ await testFetchRejectsStaleBlob();
1316
+ await testFetchTamperedSignature();
1317
+ await testFetchWrongTrustRoot();
1318
+ await testFetchUnsupportedAlg();
1319
+ await testFetchRejectsImpossibleNextUpdate();
1320
+ await testFetchMalformedBlobHeaders();
1321
+ await testFetchRejectsBadStatus();
1322
+ await testFetchNetworkFailure();
1323
+ await testFetchBadCaCertificate();
1324
+ await testFetchCacheHitAndForceBypass();
478
1325
  await testFetchRejectsNonHttps();
479
1326
  await testFetchRejectsEmptyUrl();
480
1327
  await testFetchRejectsBadTimeout();
481
1328
  await testInternalVerifyRejectsBadJws();
1329
+ await testFetchExpiredSigningCert();
1330
+ await testFetchNotYetValidCert();
1331
+ await testFetchBrokenChain();
1332
+ await testFetchGarbageRootInArrayStillAnchors();
1333
+ await testFetchFingerprintAnchorsPinnedNonCaLeaf();
1334
+ await testFetchEs256();
1335
+ await testFetchPs256();
1336
+ await testFetchAlgKeyTypeMismatch();
1337
+ await testFetchBadJwsSegment();
1338
+ await testFetchBadJwsJson();
1339
+ await testFetchBadX5cElements();
1340
+ await testFetchPayloadMissingEntries();
1341
+ await testFetchPayloadMissingNo();
1342
+ await testFetchBadNextUpdateShapes();
1343
+ await testFetchFarFutureNextUpdateClampsTtl();
1344
+ await testFetchNoTrustRootWhenVendorEmpty();
1345
+ await testParsePathRefusesStaleBlob();
1346
+ await testFetchNoArgUsesDefaultRoots();
1347
+ await testFetchNetworkFailureNonError();
1348
+ testLookupAaguidSkipsMalformedEntries();
1349
+ testCertifiedLevelSkipsMalformedReports();
1350
+ testVerifyAuthenticatorEntryWithoutStatusReports();
482
1351
  } finally {
483
1352
  await _drainTcpHandles();
484
1353
  }