@blamejs/blamejs-shop 0.0.44

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 (1220) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +17 -0
  3. package/README.md +117 -0
  4. package/SECURITY.md +139 -0
  5. package/lib/admin.js +952 -0
  6. package/lib/analytics.js +267 -0
  7. package/lib/cart.js +279 -0
  8. package/lib/catalog-import.js +344 -0
  9. package/lib/catalog.js +769 -0
  10. package/lib/checkout.js +320 -0
  11. package/lib/config.js +151 -0
  12. package/lib/customers.js +322 -0
  13. package/lib/email.js +242 -0
  14. package/lib/externaldb-d1.js +283 -0
  15. package/lib/index.js +57 -0
  16. package/lib/inventory-alerts.js +198 -0
  17. package/lib/newsletter.js +142 -0
  18. package/lib/order.js +380 -0
  19. package/lib/payment.js +318 -0
  20. package/lib/pricing.js +185 -0
  21. package/lib/r2-bridge.js +169 -0
  22. package/lib/shipping.js +185 -0
  23. package/lib/storefront.js +2160 -0
  24. package/lib/subscriptions.js +410 -0
  25. package/lib/tax.js +161 -0
  26. package/lib/theme.js +194 -0
  27. package/lib/vendor/MANIFEST.json +19 -0
  28. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +23 -0
  29. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +34 -0
  30. package/lib/vendor/blamejs/.clusterfuzzlite/project.yaml +16 -0
  31. package/lib/vendor/blamejs/.dockerignore +45 -0
  32. package/lib/vendor/blamejs/.gitattributes +42 -0
  33. package/lib/vendor/blamejs/.github/CODEOWNERS +4 -0
  34. package/lib/vendor/blamejs/.github/FUNDING.yml +2 -0
  35. package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/bug_report.md +58 -0
  36. package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/config.yml +8 -0
  37. package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/feature_request.md +99 -0
  38. package/lib/vendor/blamejs/.github/PULL_REQUEST_TEMPLATE.md +77 -0
  39. package/lib/vendor/blamejs/.github/dependabot.yml +37 -0
  40. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +148 -0
  41. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +107 -0
  42. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +122 -0
  43. package/lib/vendor/blamejs/.github/workflows/ci.yml +511 -0
  44. package/lib/vendor/blamejs/.github/workflows/codeql.yml +50 -0
  45. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +655 -0
  46. package/lib/vendor/blamejs/.github/workflows/release-container.yml +406 -0
  47. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +101 -0
  48. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +134 -0
  49. package/lib/vendor/blamejs/.gitignore +102 -0
  50. package/lib/vendor/blamejs/.gitleaks.toml +166 -0
  51. package/lib/vendor/blamejs/.hadolint.yaml +18 -0
  52. package/lib/vendor/blamejs/.npmrc +5 -0
  53. package/lib/vendor/blamejs/.pinact.yaml +17 -0
  54. package/lib/vendor/blamejs/ARCHITECTURE.md +158 -0
  55. package/lib/vendor/blamejs/CHANGELOG.md +1351 -0
  56. package/lib/vendor/blamejs/CODE_OF_CONDUCT.md +86 -0
  57. package/lib/vendor/blamejs/CONTRIBUTING.md +156 -0
  58. package/lib/vendor/blamejs/GOVERNANCE.md +201 -0
  59. package/lib/vendor/blamejs/LICENSE +201 -0
  60. package/lib/vendor/blamejs/LTS-CALENDAR.md +29 -0
  61. package/lib/vendor/blamejs/MIGRATING.md +29 -0
  62. package/lib/vendor/blamejs/NOTICE +81 -0
  63. package/lib/vendor/blamejs/README.md +304 -0
  64. package/lib/vendor/blamejs/SECURITY.md +432 -0
  65. package/lib/vendor/blamejs/api-snapshot.json +48709 -0
  66. package/lib/vendor/blamejs/assets/BlameJS_Logo.png +0 -0
  67. package/lib/vendor/blamejs/assets/BlameJS_Logo.svg +129 -0
  68. package/lib/vendor/blamejs/bench/README.md +77 -0
  69. package/lib/vendor/blamejs/bench/_helpers.js +70 -0
  70. package/lib/vendor/blamejs/bench/baseline.json +183 -0
  71. package/lib/vendor/blamejs/bench/crypto-hash.bench.js +19 -0
  72. package/lib/vendor/blamejs/bench/crypto-symmetric.bench.js +28 -0
  73. package/lib/vendor/blamejs/bench/run.js +140 -0
  74. package/lib/vendor/blamejs/bench/safe-json.bench.js +31 -0
  75. package/lib/vendor/blamejs/bin/blamejs.js +13 -0
  76. package/lib/vendor/blamejs/docker/caddy/Caddyfile +46 -0
  77. package/lib/vendor/blamejs/docker/coredns/Corefile +37 -0
  78. package/lib/vendor/blamejs/docker/haproxy/haproxy.cfg +52 -0
  79. package/lib/vendor/blamejs/docker/init/generate-certs.sh +118 -0
  80. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +87 -0
  81. package/lib/vendor/blamejs/docker/mitmproxy/config.yaml +16 -0
  82. package/lib/vendor/blamejs/docker/mongo/init-tls.sh +17 -0
  83. package/lib/vendor/blamejs/docker/mysql/my.cnf +12 -0
  84. package/lib/vendor/blamejs/docker/nats/nats.conf +33 -0
  85. package/lib/vendor/blamejs/docker/postgres/init-tls.sh +17 -0
  86. package/lib/vendor/blamejs/docker/postgres/postgresql.conf +18 -0
  87. package/lib/vendor/blamejs/docker/rabbitmq/rabbitmq.conf +18 -0
  88. package/lib/vendor/blamejs/docker/redis/redis.conf +15 -0
  89. package/lib/vendor/blamejs/docker/squid/squid.conf +24 -0
  90. package/lib/vendor/blamejs/docker/syslog/syslog-ng.conf +34 -0
  91. package/lib/vendor/blamejs/docker-compose.test.yml +545 -0
  92. package/lib/vendor/blamejs/docs/cis-postgres-crosswalk.md +102 -0
  93. package/lib/vendor/blamejs/docs/cis-sqlite-equivalent.md +92 -0
  94. package/lib/vendor/blamejs/eslint.config.mjs +204 -0
  95. package/lib/vendor/blamejs/examples/wiki/Caddyfile +40 -0
  96. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +218 -0
  97. package/lib/vendor/blamejs/examples/wiki/Dockerfile +120 -0
  98. package/lib/vendor/blamejs/examples/wiki/README.md +157 -0
  99. package/lib/vendor/blamejs/examples/wiki/cli-snapshot.json +250 -0
  100. package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +231 -0
  101. package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +166 -0
  102. package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +217 -0
  103. package/lib/vendor/blamejs/examples/wiki/lib/auto-site-entries.js +139 -0
  104. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +555 -0
  105. package/lib/vendor/blamejs/examples/wiki/lib/harvest-cli.js +507 -0
  106. package/lib/vendor/blamejs/examples/wiki/lib/harvest-env-vars.js +435 -0
  107. package/lib/vendor/blamejs/examples/wiki/lib/harvest-errors.js +282 -0
  108. package/lib/vendor/blamejs/examples/wiki/lib/harvest-vendored-deps.js +321 -0
  109. package/lib/vendor/blamejs/examples/wiki/lib/nav.js +15 -0
  110. package/lib/vendor/blamejs/examples/wiki/lib/opts-resolver.js +75 -0
  111. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +508 -0
  112. package/lib/vendor/blamejs/examples/wiki/lib/section.js +276 -0
  113. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +587 -0
  114. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +318 -0
  115. package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +122 -0
  116. package/lib/vendor/blamejs/examples/wiki/migrations/0001-pages-schema.js +74 -0
  117. package/lib/vendor/blamejs/examples/wiki/package.json +18 -0
  118. package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.png +0 -0
  119. package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.svg +129 -0
  120. package/lib/vendor/blamejs/examples/wiki/public/robots.txt +5 -0
  121. package/lib/vendor/blamejs/examples/wiki/public/vendor/MANIFEST.json +30 -0
  122. package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.css +1 -0
  123. package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.js +15 -0
  124. package/lib/vendor/blamejs/examples/wiki/public/wiki.css +1250 -0
  125. package/lib/vendor/blamejs/examples/wiki/routes/admin.js +366 -0
  126. package/lib/vendor/blamejs/examples/wiki/routes/integration.js +230 -0
  127. package/lib/vendor/blamejs/examples/wiki/routes/pages.js +266 -0
  128. package/lib/vendor/blamejs/examples/wiki/scripts/backfill-module-metadata.js +214 -0
  129. package/lib/vendor/blamejs/examples/wiki/seeders/prod/0001-default-pages.js +35 -0
  130. package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/_index.js +34 -0
  131. package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/api.js +76 -0
  132. package/lib/vendor/blamejs/examples/wiki/server.js +129 -0
  133. package/lib/vendor/blamejs/examples/wiki/site.config.js +197 -0
  134. package/lib/vendor/blamejs/examples/wiki/snippets/README.md +38 -0
  135. package/lib/vendor/blamejs/examples/wiki/snippets/auth/password-hash.example.js +15 -0
  136. package/lib/vendor/blamejs/examples/wiki/src/editor.js +103 -0
  137. package/lib/vendor/blamejs/examples/wiki/src/wiki.js +349 -0
  138. package/lib/vendor/blamejs/examples/wiki/test/AUDIT.md +155 -0
  139. package/lib/vendor/blamejs/examples/wiki/test/codebase-patterns.test.js +594 -0
  140. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +741 -0
  141. package/lib/vendor/blamejs/examples/wiki/test/find-missing-pages.js +254 -0
  142. package/lib/vendor/blamejs/examples/wiki/test/integration.js +391 -0
  143. package/lib/vendor/blamejs/examples/wiki/test/validate-cli-snapshot.js +379 -0
  144. package/lib/vendor/blamejs/examples/wiki/test/validate-env-snapshot.js +346 -0
  145. package/lib/vendor/blamejs/examples/wiki/test/validate-nav-coverage.js +212 -0
  146. package/lib/vendor/blamejs/examples/wiki/test/validate-site-coverage.js +252 -0
  147. package/lib/vendor/blamejs/examples/wiki/test/validate-source-comment-blocks.js +107 -0
  148. package/lib/vendor/blamejs/examples/wiki/views/_layout.html +115 -0
  149. package/lib/vendor/blamejs/examples/wiki/views/admin/api-keys.html +51 -0
  150. package/lib/vendor/blamejs/examples/wiki/views/admin/dashboard.html +22 -0
  151. package/lib/vendor/blamejs/examples/wiki/views/admin/edit.html +17 -0
  152. package/lib/vendor/blamejs/examples/wiki/views/home.html +85 -0
  153. package/lib/vendor/blamejs/examples/wiki/views/login.html +18 -0
  154. package/lib/vendor/blamejs/examples/wiki/views/page.html +5 -0
  155. package/lib/vendor/blamejs/examples/wiki/views/partials/nav.html +13 -0
  156. package/lib/vendor/blamejs/examples/wiki/views/search.html +19 -0
  157. package/lib/vendor/blamejs/examples/wiki/wiki.config.js +15 -0
  158. package/lib/vendor/blamejs/fuzz/README.md +137 -0
  159. package/lib/vendor/blamejs/fuzz/_expected.js +35 -0
  160. package/lib/vendor/blamejs/fuzz/guard-agent-registry.fuzz.js +22 -0
  161. package/lib/vendor/blamejs/fuzz/guard-csv.fuzz.js +16 -0
  162. package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/01-basic.csv +3 -0
  163. package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/02-formula.csv +1 -0
  164. package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/03-hyperlink.csv +1 -0
  165. package/lib/vendor/blamejs/fuzz/guard-dsn.fuzz.js +22 -0
  166. package/lib/vendor/blamejs/fuzz/guard-email.fuzz.js +16 -0
  167. package/lib/vendor/blamejs/fuzz/guard-email_seed_corpus/01-basic.eml +5 -0
  168. package/lib/vendor/blamejs/fuzz/guard-envelope.fuzz.js +24 -0
  169. package/lib/vendor/blamejs/fuzz/guard-event-bus-payload.fuzz.js +24 -0
  170. package/lib/vendor/blamejs/fuzz/guard-event-bus-topic.fuzz.js +20 -0
  171. package/lib/vendor/blamejs/fuzz/guard-html.fuzz.js +16 -0
  172. package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/01-basic.html +1 -0
  173. package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/02-script.html +1 -0
  174. package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/03-event.html +1 -0
  175. package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/04-jsurl.html +1 -0
  176. package/lib/vendor/blamejs/fuzz/guard-idempotency-key.fuzz.js +20 -0
  177. package/lib/vendor/blamejs/fuzz/guard-imap-command.fuzz.js +35 -0
  178. package/lib/vendor/blamejs/fuzz/guard-jmap.fuzz.js +41 -0
  179. package/lib/vendor/blamejs/fuzz/guard-json.fuzz.js +16 -0
  180. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/01-basic.json +1 -0
  181. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/02-proto.json +1 -0
  182. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/03-dupkey.json +1 -0
  183. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/04-nan.json +1 -0
  184. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/05-bom.json +1 -0
  185. package/lib/vendor/blamejs/fuzz/guard-list-id.fuzz.js +21 -0
  186. package/lib/vendor/blamejs/fuzz/guard-list-unsubscribe.fuzz.js +25 -0
  187. package/lib/vendor/blamejs/fuzz/guard-mail-compose.fuzz.js +22 -0
  188. package/lib/vendor/blamejs/fuzz/guard-mail-move.fuzz.js +22 -0
  189. package/lib/vendor/blamejs/fuzz/guard-mail-query.fuzz.js +27 -0
  190. package/lib/vendor/blamejs/fuzz/guard-mail-reply.fuzz.js +23 -0
  191. package/lib/vendor/blamejs/fuzz/guard-mail-sieve.fuzz.js +36 -0
  192. package/lib/vendor/blamejs/fuzz/guard-managesieve-command.fuzz.js +26 -0
  193. package/lib/vendor/blamejs/fuzz/guard-markdown.fuzz.js +16 -0
  194. package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/01-basic.md +2 -0
  195. package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/02-jsurl.md +1 -0
  196. package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/03-jsimg.md +1 -0
  197. package/lib/vendor/blamejs/fuzz/guard-message-id.fuzz.js +26 -0
  198. package/lib/vendor/blamejs/fuzz/guard-pop3-command.fuzz.js +23 -0
  199. package/lib/vendor/blamejs/fuzz/guard-posture-chain.fuzz.js +22 -0
  200. package/lib/vendor/blamejs/fuzz/guard-saga-config.fuzz.js +32 -0
  201. package/lib/vendor/blamejs/fuzz/guard-smtp-command.fuzz.js +27 -0
  202. package/lib/vendor/blamejs/fuzz/guard-snapshot-envelope.fuzz.js +22 -0
  203. package/lib/vendor/blamejs/fuzz/guard-stream-args.fuzz.js +22 -0
  204. package/lib/vendor/blamejs/fuzz/guard-svg.fuzz.js +16 -0
  205. package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/01-basic.svg +1 -0
  206. package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/02-script.svg +1 -0
  207. package/lib/vendor/blamejs/fuzz/guard-tenant-id.fuzz.js +20 -0
  208. package/lib/vendor/blamejs/fuzz/guard-trace-context.fuzz.js +30 -0
  209. package/lib/vendor/blamejs/fuzz/guard-xml.fuzz.js +16 -0
  210. package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/01-basic.xml +1 -0
  211. package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/02-xxe.xml +1 -0
  212. package/lib/vendor/blamejs/fuzz/guard-yaml.fuzz.js +16 -0
  213. package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/01-basic.yaml +2 -0
  214. package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/02-anchor.yaml +2 -0
  215. package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/03-norway.yaml +1 -0
  216. package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/04-multidoc.yaml +4 -0
  217. package/lib/vendor/blamejs/fuzz/parsers__safe-ini.fuzz.js +16 -0
  218. package/lib/vendor/blamejs/fuzz/parsers__safe-ini_seed_corpus/01-basic.ini +2 -0
  219. package/lib/vendor/blamejs/fuzz/parsers__safe-toml.fuzz.js +16 -0
  220. package/lib/vendor/blamejs/fuzz/parsers__safe-toml_seed_corpus/01-basic.toml +4 -0
  221. package/lib/vendor/blamejs/fuzz/parsers__safe-xml.fuzz.js +16 -0
  222. package/lib/vendor/blamejs/fuzz/parsers__safe-xml_seed_corpus/01-basic.xml +1 -0
  223. package/lib/vendor/blamejs/fuzz/parsers__safe-yaml.fuzz.js +16 -0
  224. package/lib/vendor/blamejs/fuzz/parsers__safe-yaml_seed_corpus/01-basic.yaml +4 -0
  225. package/lib/vendor/blamejs/fuzz/safe-decompress.fuzz.js +49 -0
  226. package/lib/vendor/blamejs/fuzz/safe-dns.fuzz.js +29 -0
  227. package/lib/vendor/blamejs/fuzz/safe-ical.fuzz.js +16 -0
  228. package/lib/vendor/blamejs/fuzz/safe-icap.fuzz.js +42 -0
  229. package/lib/vendor/blamejs/fuzz/safe-json.fuzz.js +25 -0
  230. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/01-object.txt +1 -0
  231. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/02-array.txt +1 -0
  232. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/03-string.txt +1 -0
  233. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/04-proto.txt +1 -0
  234. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/05-deep.txt +1 -0
  235. package/lib/vendor/blamejs/fuzz/safe-jsonpath.fuzz.js +16 -0
  236. package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/01-basic.txt +1 -0
  237. package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/02-filter.txt +1 -0
  238. package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/03-deepscan.txt +1 -0
  239. package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/04-slice.txt +1 -0
  240. package/lib/vendor/blamejs/fuzz/safe-mime.fuzz.js +27 -0
  241. package/lib/vendor/blamejs/fuzz/safe-mount-info.fuzz.js +33 -0
  242. package/lib/vendor/blamejs/fuzz/safe-sieve.fuzz.js +28 -0
  243. package/lib/vendor/blamejs/fuzz/safe-smtp.fuzz.js +64 -0
  244. package/lib/vendor/blamejs/fuzz/safe-url.fuzz.js +16 -0
  245. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/01-basic.txt +1 -0
  246. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/02-userinfo.txt +1 -0
  247. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/03-dangerous.txt +1 -0
  248. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/04-data.txt +1 -0
  249. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/05-ipv6.txt +1 -0
  250. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/06-idn.txt +1 -0
  251. package/lib/vendor/blamejs/fuzz/safe-vcard.fuzz.js +16 -0
  252. package/lib/vendor/blamejs/index.js +678 -0
  253. package/lib/vendor/blamejs/keys/release-pqc-pub.json +7 -0
  254. package/lib/vendor/blamejs/lib/_test/crypto-fixtures.js +67 -0
  255. package/lib/vendor/blamejs/lib/a2a-tasks.js +598 -0
  256. package/lib/vendor/blamejs/lib/a2a.js +407 -0
  257. package/lib/vendor/blamejs/lib/acme.js +1448 -0
  258. package/lib/vendor/blamejs/lib/agent-audit.js +45 -0
  259. package/lib/vendor/blamejs/lib/agent-event-bus.js +382 -0
  260. package/lib/vendor/blamejs/lib/agent-idempotency.js +497 -0
  261. package/lib/vendor/blamejs/lib/agent-orchestrator.js +717 -0
  262. package/lib/vendor/blamejs/lib/agent-posture-chain.js +366 -0
  263. package/lib/vendor/blamejs/lib/agent-saga.js +321 -0
  264. package/lib/vendor/blamejs/lib/agent-snapshot.js +676 -0
  265. package/lib/vendor/blamejs/lib/agent-stream.js +269 -0
  266. package/lib/vendor/blamejs/lib/agent-tenant.js +632 -0
  267. package/lib/vendor/blamejs/lib/agent-trace.js +281 -0
  268. package/lib/vendor/blamejs/lib/ai-adverse-decision.js +184 -0
  269. package/lib/vendor/blamejs/lib/ai-content-detect.js +268 -0
  270. package/lib/vendor/blamejs/lib/ai-input.js +201 -0
  271. package/lib/vendor/blamejs/lib/ai-model-manifest.js +363 -0
  272. package/lib/vendor/blamejs/lib/ai-pref.js +340 -0
  273. package/lib/vendor/blamejs/lib/api-key.js +721 -0
  274. package/lib/vendor/blamejs/lib/api-snapshot.js +458 -0
  275. package/lib/vendor/blamejs/lib/app-shutdown.js +557 -0
  276. package/lib/vendor/blamejs/lib/app.js +365 -0
  277. package/lib/vendor/blamejs/lib/archive.js +547 -0
  278. package/lib/vendor/blamejs/lib/arg-parser.js +697 -0
  279. package/lib/vendor/blamejs/lib/argon2-builtin.js +173 -0
  280. package/lib/vendor/blamejs/lib/asn1-der.js +424 -0
  281. package/lib/vendor/blamejs/lib/asyncapi-bindings.js +160 -0
  282. package/lib/vendor/blamejs/lib/asyncapi-traits.js +143 -0
  283. package/lib/vendor/blamejs/lib/asyncapi.js +575 -0
  284. package/lib/vendor/blamejs/lib/atomic-file.js +1023 -0
  285. package/lib/vendor/blamejs/lib/audit-chain.js +266 -0
  286. package/lib/vendor/blamejs/lib/audit-daily-review.js +389 -0
  287. package/lib/vendor/blamejs/lib/audit-sign.js +751 -0
  288. package/lib/vendor/blamejs/lib/audit-tools.js +1113 -0
  289. package/lib/vendor/blamejs/lib/audit.js +1671 -0
  290. package/lib/vendor/blamejs/lib/auth/aal.js +169 -0
  291. package/lib/vendor/blamejs/lib/auth/access-lock.js +220 -0
  292. package/lib/vendor/blamejs/lib/auth/acr-vocabulary.js +265 -0
  293. package/lib/vendor/blamejs/lib/auth/ato-kill-switch.js +112 -0
  294. package/lib/vendor/blamejs/lib/auth/auth-time-tracker.js +111 -0
  295. package/lib/vendor/blamejs/lib/auth/bot-challenge.js +573 -0
  296. package/lib/vendor/blamejs/lib/auth/ciba.js +637 -0
  297. package/lib/vendor/blamejs/lib/auth/dpop.js +516 -0
  298. package/lib/vendor/blamejs/lib/auth/elevation-grant.js +306 -0
  299. package/lib/vendor/blamejs/lib/auth/fal.js +229 -0
  300. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +681 -0
  301. package/lib/vendor/blamejs/lib/auth/jwt-external.js +519 -0
  302. package/lib/vendor/blamejs/lib/auth/jwt.js +430 -0
  303. package/lib/vendor/blamejs/lib/auth/lockout.js +449 -0
  304. package/lib/vendor/blamejs/lib/auth/oauth.js +2141 -0
  305. package/lib/vendor/blamejs/lib/auth/oid4vci.js +657 -0
  306. package/lib/vendor/blamejs/lib/auth/oid4vp.js +531 -0
  307. package/lib/vendor/blamejs/lib/auth/openid-federation.js +600 -0
  308. package/lib/vendor/blamejs/lib/auth/passkey.js +676 -0
  309. package/lib/vendor/blamejs/lib/auth/password.js +693 -0
  310. package/lib/vendor/blamejs/lib/auth/saml.js +2109 -0
  311. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-disclosure.js +95 -0
  312. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +225 -0
  313. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +197 -0
  314. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +728 -0
  315. package/lib/vendor/blamejs/lib/auth/status-list.js +272 -0
  316. package/lib/vendor/blamejs/lib/auth/step-up-policy.js +335 -0
  317. package/lib/vendor/blamejs/lib/auth/step-up.js +454 -0
  318. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +505 -0
  319. package/lib/vendor/blamejs/lib/auth-header.js +148 -0
  320. package/lib/vendor/blamejs/lib/backup/bundle.js +265 -0
  321. package/lib/vendor/blamejs/lib/backup/crypto.js +176 -0
  322. package/lib/vendor/blamejs/lib/backup/index.js +1001 -0
  323. package/lib/vendor/blamejs/lib/backup/manifest.js +443 -0
  324. package/lib/vendor/blamejs/lib/boot-gates.js +174 -0
  325. package/lib/vendor/blamejs/lib/breach-deadline.js +272 -0
  326. package/lib/vendor/blamejs/lib/break-glass.js +1753 -0
  327. package/lib/vendor/blamejs/lib/budr.js +205 -0
  328. package/lib/vendor/blamejs/lib/bundler.js +461 -0
  329. package/lib/vendor/blamejs/lib/cache-redis.js +256 -0
  330. package/lib/vendor/blamejs/lib/cache-status.js +288 -0
  331. package/lib/vendor/blamejs/lib/cache.js +1331 -0
  332. package/lib/vendor/blamejs/lib/calendar.js +1240 -0
  333. package/lib/vendor/blamejs/lib/canonical-json.js +143 -0
  334. package/lib/vendor/blamejs/lib/cdn-cache-control.js +473 -0
  335. package/lib/vendor/blamejs/lib/cert.js +763 -0
  336. package/lib/vendor/blamejs/lib/chain-writer.js +259 -0
  337. package/lib/vendor/blamejs/lib/circuit-breaker.js +101 -0
  338. package/lib/vendor/blamejs/lib/cli-helpers.js +237 -0
  339. package/lib/vendor/blamejs/lib/cli.js +2328 -0
  340. package/lib/vendor/blamejs/lib/client-hints.js +318 -0
  341. package/lib/vendor/blamejs/lib/cloud-events.js +277 -0
  342. package/lib/vendor/blamejs/lib/cluster-provider-db.js +317 -0
  343. package/lib/vendor/blamejs/lib/cluster-storage.js +351 -0
  344. package/lib/vendor/blamejs/lib/cluster.js +1017 -0
  345. package/lib/vendor/blamejs/lib/cms-codec.js +826 -0
  346. package/lib/vendor/blamejs/lib/codepoint-class.js +262 -0
  347. package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +190 -0
  348. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +205 -0
  349. package/lib/vendor/blamejs/lib/compliance-ai-act-risk.js +189 -0
  350. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +200 -0
  351. package/lib/vendor/blamejs/lib/compliance-ai-act.js +821 -0
  352. package/lib/vendor/blamejs/lib/compliance-eaa.js +204 -0
  353. package/lib/vendor/blamejs/lib/compliance-sanctions-aliases.js +167 -0
  354. package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +206 -0
  355. package/lib/vendor/blamejs/lib/compliance-sanctions-fuzzy.js +297 -0
  356. package/lib/vendor/blamejs/lib/compliance-sanctions.js +569 -0
  357. package/lib/vendor/blamejs/lib/compliance.js +1558 -0
  358. package/lib/vendor/blamejs/lib/config-drift.js +426 -0
  359. package/lib/vendor/blamejs/lib/config.js +446 -0
  360. package/lib/vendor/blamejs/lib/consent.js +369 -0
  361. package/lib/vendor/blamejs/lib/constants.js +209 -0
  362. package/lib/vendor/blamejs/lib/content-credentials.js +704 -0
  363. package/lib/vendor/blamejs/lib/cookies.js +560 -0
  364. package/lib/vendor/blamejs/lib/cra-report.js +299 -0
  365. package/lib/vendor/blamejs/lib/credential-hash.js +394 -0
  366. package/lib/vendor/blamejs/lib/crypto-field.js +1017 -0
  367. package/lib/vendor/blamejs/lib/crypto-hpke-pq.js +187 -0
  368. package/lib/vendor/blamejs/lib/crypto-hpke.js +256 -0
  369. package/lib/vendor/blamejs/lib/crypto.js +1908 -0
  370. package/lib/vendor/blamejs/lib/csp.js +271 -0
  371. package/lib/vendor/blamejs/lib/csv.js +418 -0
  372. package/lib/vendor/blamejs/lib/daemon.js +481 -0
  373. package/lib/vendor/blamejs/lib/dark-patterns.js +488 -0
  374. package/lib/vendor/blamejs/lib/data-act.js +328 -0
  375. package/lib/vendor/blamejs/lib/db-collection.js +587 -0
  376. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +267 -0
  377. package/lib/vendor/blamejs/lib/db-declare-view.js +420 -0
  378. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +333 -0
  379. package/lib/vendor/blamejs/lib/db-query.js +802 -0
  380. package/lib/vendor/blamejs/lib/db-role-context.js +50 -0
  381. package/lib/vendor/blamejs/lib/db-schema.js +322 -0
  382. package/lib/vendor/blamejs/lib/db.js +3111 -0
  383. package/lib/vendor/blamejs/lib/dbsc.js +299 -0
  384. package/lib/vendor/blamejs/lib/ddl-change-control.js +523 -0
  385. package/lib/vendor/blamejs/lib/deprecate.js +377 -0
  386. package/lib/vendor/blamejs/lib/dev.js +405 -0
  387. package/lib/vendor/blamejs/lib/dora.js +402 -0
  388. package/lib/vendor/blamejs/lib/dr-runbook.js +368 -0
  389. package/lib/vendor/blamejs/lib/dsr.js +1188 -0
  390. package/lib/vendor/blamejs/lib/dual-control.js +526 -0
  391. package/lib/vendor/blamejs/lib/early-hints.js +212 -0
  392. package/lib/vendor/blamejs/lib/error-page.js +420 -0
  393. package/lib/vendor/blamejs/lib/events.js +214 -0
  394. package/lib/vendor/blamejs/lib/external-db-migrate.js +659 -0
  395. package/lib/vendor/blamejs/lib/external-db.js +1877 -0
  396. package/lib/vendor/blamejs/lib/fapi2.js +394 -0
  397. package/lib/vendor/blamejs/lib/fda-21cfr11.js +395 -0
  398. package/lib/vendor/blamejs/lib/fdx.js +370 -0
  399. package/lib/vendor/blamejs/lib/fedcm.js +264 -0
  400. package/lib/vendor/blamejs/lib/file-type.js +360 -0
  401. package/lib/vendor/blamejs/lib/file-upload.js +1256 -0
  402. package/lib/vendor/blamejs/lib/flag-cache.js +136 -0
  403. package/lib/vendor/blamejs/lib/flag-evaluation-context.js +135 -0
  404. package/lib/vendor/blamejs/lib/flag-providers.js +279 -0
  405. package/lib/vendor/blamejs/lib/flag-targeting.js +210 -0
  406. package/lib/vendor/blamejs/lib/flag.js +346 -0
  407. package/lib/vendor/blamejs/lib/forms.js +525 -0
  408. package/lib/vendor/blamejs/lib/framework-error.js +724 -0
  409. package/lib/vendor/blamejs/lib/framework-schema.js +845 -0
  410. package/lib/vendor/blamejs/lib/framework-sha1-hibp.js +34 -0
  411. package/lib/vendor/blamejs/lib/fsm.js +469 -0
  412. package/lib/vendor/blamejs/lib/gate-contract.js +1661 -0
  413. package/lib/vendor/blamejs/lib/gdpr-ropa.js +261 -0
  414. package/lib/vendor/blamejs/lib/graphql-federation.js +234 -0
  415. package/lib/vendor/blamejs/lib/guard-agent-registry.js +179 -0
  416. package/lib/vendor/blamejs/lib/guard-all.js +555 -0
  417. package/lib/vendor/blamejs/lib/guard-archive.js +901 -0
  418. package/lib/vendor/blamejs/lib/guard-auth.js +451 -0
  419. package/lib/vendor/blamejs/lib/guard-cidr.js +676 -0
  420. package/lib/vendor/blamejs/lib/guard-csv.js +1176 -0
  421. package/lib/vendor/blamejs/lib/guard-domain.js +814 -0
  422. package/lib/vendor/blamejs/lib/guard-dsn.js +382 -0
  423. package/lib/vendor/blamejs/lib/guard-email.js +951 -0
  424. package/lib/vendor/blamejs/lib/guard-envelope.js +294 -0
  425. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +217 -0
  426. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +150 -0
  427. package/lib/vendor/blamejs/lib/guard-filename.js +956 -0
  428. package/lib/vendor/blamejs/lib/guard-graphql.js +731 -0
  429. package/lib/vendor/blamejs/lib/guard-html-wcag-aria.js +164 -0
  430. package/lib/vendor/blamejs/lib/guard-html-wcag-forms.js +144 -0
  431. package/lib/vendor/blamejs/lib/guard-html-wcag-tables.js +154 -0
  432. package/lib/vendor/blamejs/lib/guard-html-wcag-tagwalk.js +44 -0
  433. package/lib/vendor/blamejs/lib/guard-html-wcag.js +470 -0
  434. package/lib/vendor/blamejs/lib/guard-html.js +1209 -0
  435. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +151 -0
  436. package/lib/vendor/blamejs/lib/guard-image.js +584 -0
  437. package/lib/vendor/blamejs/lib/guard-imap-command.js +337 -0
  438. package/lib/vendor/blamejs/lib/guard-jmap.js +321 -0
  439. package/lib/vendor/blamejs/lib/guard-json.js +935 -0
  440. package/lib/vendor/blamejs/lib/guard-jsonpath.js +512 -0
  441. package/lib/vendor/blamejs/lib/guard-jwt.js +772 -0
  442. package/lib/vendor/blamejs/lib/guard-list-id.js +318 -0
  443. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +412 -0
  444. package/lib/vendor/blamejs/lib/guard-mail-compose.js +282 -0
  445. package/lib/vendor/blamejs/lib/guard-mail-move.js +202 -0
  446. package/lib/vendor/blamejs/lib/guard-mail-query.js +310 -0
  447. package/lib/vendor/blamejs/lib/guard-mail-reply.js +172 -0
  448. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +207 -0
  449. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +566 -0
  450. package/lib/vendor/blamejs/lib/guard-markdown.js +768 -0
  451. package/lib/vendor/blamejs/lib/guard-message-id.js +267 -0
  452. package/lib/vendor/blamejs/lib/guard-mime.js +609 -0
  453. package/lib/vendor/blamejs/lib/guard-oauth.js +650 -0
  454. package/lib/vendor/blamejs/lib/guard-pdf.js +569 -0
  455. package/lib/vendor/blamejs/lib/guard-pop3-command.js +317 -0
  456. package/lib/vendor/blamejs/lib/guard-posture-chain.js +201 -0
  457. package/lib/vendor/blamejs/lib/guard-regex.js +632 -0
  458. package/lib/vendor/blamejs/lib/guard-saga-config.js +157 -0
  459. package/lib/vendor/blamejs/lib/guard-shell.js +522 -0
  460. package/lib/vendor/blamejs/lib/guard-smtp-command.js +594 -0
  461. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +168 -0
  462. package/lib/vendor/blamejs/lib/guard-stream-args.js +166 -0
  463. package/lib/vendor/blamejs/lib/guard-svg.js +1163 -0
  464. package/lib/vendor/blamejs/lib/guard-template.js +490 -0
  465. package/lib/vendor/blamejs/lib/guard-tenant-id.js +138 -0
  466. package/lib/vendor/blamejs/lib/guard-time.js +586 -0
  467. package/lib/vendor/blamejs/lib/guard-trace-context.js +172 -0
  468. package/lib/vendor/blamejs/lib/guard-uuid.js +548 -0
  469. package/lib/vendor/blamejs/lib/guard-xml.js +666 -0
  470. package/lib/vendor/blamejs/lib/guard-yaml.js +726 -0
  471. package/lib/vendor/blamejs/lib/hal.js +125 -0
  472. package/lib/vendor/blamejs/lib/handlers.js +350 -0
  473. package/lib/vendor/blamejs/lib/honeytoken.js +168 -0
  474. package/lib/vendor/blamejs/lib/html-balance.js +347 -0
  475. package/lib/vendor/blamejs/lib/http-client-cache.js +923 -0
  476. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +519 -0
  477. package/lib/vendor/blamejs/lib/http-client.js +2152 -0
  478. package/lib/vendor/blamejs/lib/http-message-signature.js +589 -0
  479. package/lib/vendor/blamejs/lib/http2-teardown.js +34 -0
  480. package/lib/vendor/blamejs/lib/i18n-messageformat.js +398 -0
  481. package/lib/vendor/blamejs/lib/i18n.js +931 -0
  482. package/lib/vendor/blamejs/lib/iab-mspa.js +257 -0
  483. package/lib/vendor/blamejs/lib/iab-tcf.js +461 -0
  484. package/lib/vendor/blamejs/lib/importmap-integrity.js +90 -0
  485. package/lib/vendor/blamejs/lib/inbox.js +435 -0
  486. package/lib/vendor/blamejs/lib/incident-report.js +314 -0
  487. package/lib/vendor/blamejs/lib/ip-utils.js +102 -0
  488. package/lib/vendor/blamejs/lib/jobs.js +185 -0
  489. package/lib/vendor/blamejs/lib/jose-jwe-experimental.js +228 -0
  490. package/lib/vendor/blamejs/lib/jsonapi.js +230 -0
  491. package/lib/vendor/blamejs/lib/keychain.js +865 -0
  492. package/lib/vendor/blamejs/lib/lazy-require.js +48 -0
  493. package/lib/vendor/blamejs/lib/legal-hold.js +374 -0
  494. package/lib/vendor/blamejs/lib/local-db-thin.js +321 -0
  495. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +369 -0
  496. package/lib/vendor/blamejs/lib/log-stream-local.js +146 -0
  497. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +410 -0
  498. package/lib/vendor/blamejs/lib/log-stream-otlp.js +286 -0
  499. package/lib/vendor/blamejs/lib/log-stream-syslog.js +310 -0
  500. package/lib/vendor/blamejs/lib/log-stream-webhook.js +199 -0
  501. package/lib/vendor/blamejs/lib/log-stream.js +584 -0
  502. package/lib/vendor/blamejs/lib/log.js +625 -0
  503. package/lib/vendor/blamejs/lib/lro.js +200 -0
  504. package/lib/vendor/blamejs/lib/mail-agent.js +786 -0
  505. package/lib/vendor/blamejs/lib/mail-arc-sign.js +417 -0
  506. package/lib/vendor/blamejs/lib/mail-arf.js +343 -0
  507. package/lib/vendor/blamejs/lib/mail-auth.js +2144 -0
  508. package/lib/vendor/blamejs/lib/mail-bimi.js +1047 -0
  509. package/lib/vendor/blamejs/lib/mail-bounce.js +955 -0
  510. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +1286 -0
  511. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +789 -0
  512. package/lib/vendor/blamejs/lib/mail-crypto.js +108 -0
  513. package/lib/vendor/blamejs/lib/mail-dav.js +1224 -0
  514. package/lib/vendor/blamejs/lib/mail-deploy.js +1119 -0
  515. package/lib/vendor/blamejs/lib/mail-dkim.js +1250 -0
  516. package/lib/vendor/blamejs/lib/mail-greylist.js +448 -0
  517. package/lib/vendor/blamejs/lib/mail-helo.js +473 -0
  518. package/lib/vendor/blamejs/lib/mail-journal.js +435 -0
  519. package/lib/vendor/blamejs/lib/mail-mdn.js +424 -0
  520. package/lib/vendor/blamejs/lib/mail-rbl.js +392 -0
  521. package/lib/vendor/blamejs/lib/mail-require-tls.js +198 -0
  522. package/lib/vendor/blamejs/lib/mail-scan.js +502 -0
  523. package/lib/vendor/blamejs/lib/mail-send-deliver.js +629 -0
  524. package/lib/vendor/blamejs/lib/mail-server-imap.js +1858 -0
  525. package/lib/vendor/blamejs/lib/mail-server-jmap.js +1565 -0
  526. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +908 -0
  527. package/lib/vendor/blamejs/lib/mail-server-mx.js +969 -0
  528. package/lib/vendor/blamejs/lib/mail-server-pop3.js +915 -0
  529. package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +315 -0
  530. package/lib/vendor/blamejs/lib/mail-server-registry.js +378 -0
  531. package/lib/vendor/blamejs/lib/mail-server-submission.js +1396 -0
  532. package/lib/vendor/blamejs/lib/mail-server-tls.js +445 -0
  533. package/lib/vendor/blamejs/lib/mail-sieve.js +557 -0
  534. package/lib/vendor/blamejs/lib/mail-spam-score.js +284 -0
  535. package/lib/vendor/blamejs/lib/mail-srs.js +248 -0
  536. package/lib/vendor/blamejs/lib/mail-store-fts.js +394 -0
  537. package/lib/vendor/blamejs/lib/mail-store.js +929 -0
  538. package/lib/vendor/blamejs/lib/mail-unsubscribe.js +400 -0
  539. package/lib/vendor/blamejs/lib/mail.js +1971 -0
  540. package/lib/vendor/blamejs/lib/mcp-tool-registry.js +473 -0
  541. package/lib/vendor/blamejs/lib/mcp.js +950 -0
  542. package/lib/vendor/blamejs/lib/metrics.js +1503 -0
  543. package/lib/vendor/blamejs/lib/middleware/age-gate.js +177 -0
  544. package/lib/vendor/blamejs/lib/middleware/ai-act-disclosure.js +203 -0
  545. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +981 -0
  546. package/lib/vendor/blamejs/lib/middleware/assetlinks.js +137 -0
  547. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +171 -0
  548. package/lib/vendor/blamejs/lib/middleware/attach-user.js +220 -0
  549. package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +293 -0
  550. package/lib/vendor/blamejs/lib/middleware/body-parser.js +1519 -0
  551. package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +183 -0
  552. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +217 -0
  553. package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +122 -0
  554. package/lib/vendor/blamejs/lib/middleware/compose-pipeline.js +355 -0
  555. package/lib/vendor/blamejs/lib/middleware/compression.js +489 -0
  556. package/lib/vendor/blamejs/lib/middleware/cookies.js +130 -0
  557. package/lib/vendor/blamejs/lib/middleware/cors.js +386 -0
  558. package/lib/vendor/blamejs/lib/middleware/csp-nonce.js +388 -0
  559. package/lib/vendor/blamejs/lib/middleware/csp-report.js +167 -0
  560. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +499 -0
  561. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +243 -0
  562. package/lib/vendor/blamejs/lib/middleware/db-role-for.js +304 -0
  563. package/lib/vendor/blamejs/lib/middleware/dpop.js +402 -0
  564. package/lib/vendor/blamejs/lib/middleware/error-handler.js +69 -0
  565. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +168 -0
  566. package/lib/vendor/blamejs/lib/middleware/flag-context.js +110 -0
  567. package/lib/vendor/blamejs/lib/middleware/gpc.js +153 -0
  568. package/lib/vendor/blamejs/lib/middleware/headers.js +242 -0
  569. package/lib/vendor/blamejs/lib/middleware/health.js +438 -0
  570. package/lib/vendor/blamejs/lib/middleware/host-allowlist.js +189 -0
  571. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +964 -0
  572. package/lib/vendor/blamejs/lib/middleware/index.js +183 -0
  573. package/lib/vendor/blamejs/lib/middleware/nel.js +214 -0
  574. package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +237 -0
  575. package/lib/vendor/blamejs/lib/middleware/no-cache.js +106 -0
  576. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +177 -0
  577. package/lib/vendor/blamejs/lib/middleware/protected-resource-metadata.js +277 -0
  578. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +556 -0
  579. package/lib/vendor/blamejs/lib/middleware/request-id.js +79 -0
  580. package/lib/vendor/blamejs/lib/middleware/request-log.js +205 -0
  581. package/lib/vendor/blamejs/lib/middleware/require-aal.js +138 -0
  582. package/lib/vendor/blamejs/lib/middleware/require-auth.js +144 -0
  583. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +290 -0
  584. package/lib/vendor/blamejs/lib/middleware/require-content-type.js +113 -0
  585. package/lib/vendor/blamejs/lib/middleware/require-methods.js +97 -0
  586. package/lib/vendor/blamejs/lib/middleware/require-mtls.js +212 -0
  587. package/lib/vendor/blamejs/lib/middleware/require-step-up.js +226 -0
  588. package/lib/vendor/blamejs/lib/middleware/scim-server.js +375 -0
  589. package/lib/vendor/blamejs/lib/middleware/security-headers.js +285 -0
  590. package/lib/vendor/blamejs/lib/middleware/security-txt.js +170 -0
  591. package/lib/vendor/blamejs/lib/middleware/span-http-server.js +280 -0
  592. package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +323 -0
  593. package/lib/vendor/blamejs/lib/middleware/sse.js +200 -0
  594. package/lib/vendor/blamejs/lib/middleware/trace-log-correlation.js +167 -0
  595. package/lib/vendor/blamejs/lib/middleware/trace-propagate.js +148 -0
  596. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +749 -0
  597. package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +164 -0
  598. package/lib/vendor/blamejs/lib/migration-files.js +37 -0
  599. package/lib/vendor/blamejs/lib/migrations.js +385 -0
  600. package/lib/vendor/blamejs/lib/mime-parse.js +198 -0
  601. package/lib/vendor/blamejs/lib/money.js +699 -0
  602. package/lib/vendor/blamejs/lib/mtls-ca.js +572 -0
  603. package/lib/vendor/blamejs/lib/mtls-engine-default.js +501 -0
  604. package/lib/vendor/blamejs/lib/network-byte-quota.js +308 -0
  605. package/lib/vendor/blamejs/lib/network-dns-resolver.js +533 -0
  606. package/lib/vendor/blamejs/lib/network-dns.js +1930 -0
  607. package/lib/vendor/blamejs/lib/network-heartbeat.js +425 -0
  608. package/lib/vendor/blamejs/lib/network-nts.js +574 -0
  609. package/lib/vendor/blamejs/lib/network-proxy.js +265 -0
  610. package/lib/vendor/blamejs/lib/network-smtp-policy.js +836 -0
  611. package/lib/vendor/blamejs/lib/network-tls.js +3126 -0
  612. package/lib/vendor/blamejs/lib/network.js +346 -0
  613. package/lib/vendor/blamejs/lib/nis2-report.js +181 -0
  614. package/lib/vendor/blamejs/lib/nist-crosswalk.js +293 -0
  615. package/lib/vendor/blamejs/lib/nonce-store.js +177 -0
  616. package/lib/vendor/blamejs/lib/notify.js +683 -0
  617. package/lib/vendor/blamejs/lib/ntp-check.js +458 -0
  618. package/lib/vendor/blamejs/lib/numeric-bounds.js +111 -0
  619. package/lib/vendor/blamejs/lib/numeric-checks.js +40 -0
  620. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +349 -0
  621. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +488 -0
  622. package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +351 -0
  623. package/lib/vendor/blamejs/lib/object-store/gcs.js +515 -0
  624. package/lib/vendor/blamejs/lib/object-store/http-put.js +153 -0
  625. package/lib/vendor/blamejs/lib/object-store/http-request.js +38 -0
  626. package/lib/vendor/blamejs/lib/object-store/index.js +197 -0
  627. package/lib/vendor/blamejs/lib/object-store/local.js +163 -0
  628. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +1133 -0
  629. package/lib/vendor/blamejs/lib/object-store/sigv4.js +957 -0
  630. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +420 -0
  631. package/lib/vendor/blamejs/lib/observability-tracer.js +395 -0
  632. package/lib/vendor/blamejs/lib/observability.js +720 -0
  633. package/lib/vendor/blamejs/lib/openapi-paths-builder.js +248 -0
  634. package/lib/vendor/blamejs/lib/openapi-schema-walk.js +192 -0
  635. package/lib/vendor/blamejs/lib/openapi-security.js +169 -0
  636. package/lib/vendor/blamejs/lib/openapi-yaml.js +154 -0
  637. package/lib/vendor/blamejs/lib/openapi.js +489 -0
  638. package/lib/vendor/blamejs/lib/otel-export.js +278 -0
  639. package/lib/vendor/blamejs/lib/outbox.js +547 -0
  640. package/lib/vendor/blamejs/lib/pagination.js +542 -0
  641. package/lib/vendor/blamejs/lib/parsers/index.js +91 -0
  642. package/lib/vendor/blamejs/lib/parsers/safe-env.js +642 -0
  643. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +293 -0
  644. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +784 -0
  645. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +390 -0
  646. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +1015 -0
  647. package/lib/vendor/blamejs/lib/permissions.js +793 -0
  648. package/lib/vendor/blamejs/lib/pick.js +105 -0
  649. package/lib/vendor/blamejs/lib/pqc-agent.js +351 -0
  650. package/lib/vendor/blamejs/lib/pqc-gate.js +279 -0
  651. package/lib/vendor/blamejs/lib/pqc-software.js +271 -0
  652. package/lib/vendor/blamejs/lib/problem-details.js +482 -0
  653. package/lib/vendor/blamejs/lib/process-spawn.js +196 -0
  654. package/lib/vendor/blamejs/lib/promise-pool.js +162 -0
  655. package/lib/vendor/blamejs/lib/protobuf-encoder.js +190 -0
  656. package/lib/vendor/blamejs/lib/protocol-dispatcher.js +161 -0
  657. package/lib/vendor/blamejs/lib/public-suffix.js +403 -0
  658. package/lib/vendor/blamejs/lib/pubsub-cluster.js +154 -0
  659. package/lib/vendor/blamejs/lib/pubsub-redis.js +167 -0
  660. package/lib/vendor/blamejs/lib/pubsub.js +463 -0
  661. package/lib/vendor/blamejs/lib/queue-local.js +476 -0
  662. package/lib/vendor/blamejs/lib/queue-redis.js +745 -0
  663. package/lib/vendor/blamejs/lib/queue-sqs.js +319 -0
  664. package/lib/vendor/blamejs/lib/queue.js +1016 -0
  665. package/lib/vendor/blamejs/lib/redact.js +1007 -0
  666. package/lib/vendor/blamejs/lib/redis-client.js +520 -0
  667. package/lib/vendor/blamejs/lib/render.js +285 -0
  668. package/lib/vendor/blamejs/lib/request-helpers.js +767 -0
  669. package/lib/vendor/blamejs/lib/resource-access-lock.js +116 -0
  670. package/lib/vendor/blamejs/lib/restore-bundle.js +340 -0
  671. package/lib/vendor/blamejs/lib/restore-rollback.js +365 -0
  672. package/lib/vendor/blamejs/lib/restore.js +409 -0
  673. package/lib/vendor/blamejs/lib/retention.js +640 -0
  674. package/lib/vendor/blamejs/lib/retry.js +523 -0
  675. package/lib/vendor/blamejs/lib/router.js +1289 -0
  676. package/lib/vendor/blamejs/lib/safe-async.js +1184 -0
  677. package/lib/vendor/blamejs/lib/safe-buffer.js +562 -0
  678. package/lib/vendor/blamejs/lib/safe-decompress.js +297 -0
  679. package/lib/vendor/blamejs/lib/safe-dns.js +665 -0
  680. package/lib/vendor/blamejs/lib/safe-ical.js +634 -0
  681. package/lib/vendor/blamejs/lib/safe-icap.js +502 -0
  682. package/lib/vendor/blamejs/lib/safe-json.js +946 -0
  683. package/lib/vendor/blamejs/lib/safe-jsonpath.js +285 -0
  684. package/lib/vendor/blamejs/lib/safe-mime.js +831 -0
  685. package/lib/vendor/blamejs/lib/safe-mount-info.js +306 -0
  686. package/lib/vendor/blamejs/lib/safe-path.js +254 -0
  687. package/lib/vendor/blamejs/lib/safe-redirect.js +106 -0
  688. package/lib/vendor/blamejs/lib/safe-schema.js +1810 -0
  689. package/lib/vendor/blamejs/lib/safe-sieve.js +684 -0
  690. package/lib/vendor/blamejs/lib/safe-smtp.js +185 -0
  691. package/lib/vendor/blamejs/lib/safe-sql.js +363 -0
  692. package/lib/vendor/blamejs/lib/safe-url.js +428 -0
  693. package/lib/vendor/blamejs/lib/safe-vcard.js +473 -0
  694. package/lib/vendor/blamejs/lib/sandbox-worker.js +135 -0
  695. package/lib/vendor/blamejs/lib/sandbox.js +358 -0
  696. package/lib/vendor/blamejs/lib/scheduler.js +827 -0
  697. package/lib/vendor/blamejs/lib/sd-notify.js +269 -0
  698. package/lib/vendor/blamejs/lib/sec-cyber.js +214 -0
  699. package/lib/vendor/blamejs/lib/security-assert.js +395 -0
  700. package/lib/vendor/blamejs/lib/seeders.js +620 -0
  701. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +309 -0
  702. package/lib/vendor/blamejs/lib/self-update.js +804 -0
  703. package/lib/vendor/blamejs/lib/server-timing.js +174 -0
  704. package/lib/vendor/blamejs/lib/session-device-binding.js +431 -0
  705. package/lib/vendor/blamejs/lib/session-stores.js +138 -0
  706. package/lib/vendor/blamejs/lib/session.js +1162 -0
  707. package/lib/vendor/blamejs/lib/slug.js +381 -0
  708. package/lib/vendor/blamejs/lib/sse.js +349 -0
  709. package/lib/vendor/blamejs/lib/ssrf-guard.js +792 -0
  710. package/lib/vendor/blamejs/lib/standard-webhooks.js +183 -0
  711. package/lib/vendor/blamejs/lib/static.js +1249 -0
  712. package/lib/vendor/blamejs/lib/storage.js +1272 -0
  713. package/lib/vendor/blamejs/lib/stream-throttle.js +235 -0
  714. package/lib/vendor/blamejs/lib/structured-fields.js +244 -0
  715. package/lib/vendor/blamejs/lib/subject.js +667 -0
  716. package/lib/vendor/blamejs/lib/tcpa-10dlc.js +175 -0
  717. package/lib/vendor/blamejs/lib/template.js +931 -0
  718. package/lib/vendor/blamejs/lib/tenant-quota.js +545 -0
  719. package/lib/vendor/blamejs/lib/test-harness.js +275 -0
  720. package/lib/vendor/blamejs/lib/testing.js +1185 -0
  721. package/lib/vendor/blamejs/lib/time.js +578 -0
  722. package/lib/vendor/blamejs/lib/tls-exporter.js +239 -0
  723. package/lib/vendor/blamejs/lib/totp.js +318 -0
  724. package/lib/vendor/blamejs/lib/tracing.js +546 -0
  725. package/lib/vendor/blamejs/lib/uuid.js +207 -0
  726. package/lib/vendor/blamejs/lib/validate-opts.js +381 -0
  727. package/lib/vendor/blamejs/lib/vault/index.js +638 -0
  728. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +311 -0
  729. package/lib/vendor/blamejs/lib/vault/passphrase-source.js +198 -0
  730. package/lib/vendor/blamejs/lib/vault/rotate.js +803 -0
  731. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +471 -0
  732. package/lib/vendor/blamejs/lib/vault/wrap.js +296 -0
  733. package/lib/vendor/blamejs/lib/vault-aad.js +259 -0
  734. package/lib/vendor/blamejs/lib/vendor/.vendor-data-pubkey +4 -0
  735. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +161 -0
  736. package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.data.js +68 -0
  737. package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.pem +33 -0
  738. package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.data.js +1325 -0
  739. package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.txt +10002 -0
  740. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +9 -0
  741. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +18 -0
  742. package/lib/vendor/blamejs/lib/vendor/pki.cjs +181 -0
  743. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +16382 -0
  744. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5881 -0
  745. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +328 -0
  746. package/lib/vendor/blamejs/lib/vendor/vendor-data-pubkey.js +16 -0
  747. package/lib/vendor/blamejs/lib/vendor-data.js +520 -0
  748. package/lib/vendor/blamejs/lib/vex.js +630 -0
  749. package/lib/vendor/blamejs/lib/watcher.js +608 -0
  750. package/lib/vendor/blamejs/lib/web-push-vapid.js +322 -0
  751. package/lib/vendor/blamejs/lib/webhook.js +977 -0
  752. package/lib/vendor/blamejs/lib/websocket-channels.js +327 -0
  753. package/lib/vendor/blamejs/lib/websocket.js +1561 -0
  754. package/lib/vendor/blamejs/lib/wiki-concepts.js +338 -0
  755. package/lib/vendor/blamejs/lib/worker-pool.js +464 -0
  756. package/lib/vendor/blamejs/lib/ws-client.js +978 -0
  757. package/lib/vendor/blamejs/lib/xml-c14n.js +506 -0
  758. package/lib/vendor/blamejs/memory/specs/node-26-map-getorinsert-migration.md +164 -0
  759. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +19 -0
  760. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/README.md +88 -0
  761. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/build.sh +26 -0
  762. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/project.yaml +28 -0
  763. package/lib/vendor/blamejs/package.json +81 -0
  764. package/lib/vendor/blamejs/release-notes/v0.0.x.json +310 -0
  765. package/lib/vendor/blamejs/release-notes/v0.1.x.json +1798 -0
  766. package/lib/vendor/blamejs/release-notes/v0.10.x.json +1288 -0
  767. package/lib/vendor/blamejs/release-notes/v0.11.x.json +2551 -0
  768. package/lib/vendor/blamejs/release-notes/v0.12.0.json +64 -0
  769. package/lib/vendor/blamejs/release-notes/v0.12.1.json +32 -0
  770. package/lib/vendor/blamejs/release-notes/v0.12.2.json +45 -0
  771. package/lib/vendor/blamejs/release-notes/v0.2.x.json +706 -0
  772. package/lib/vendor/blamejs/release-notes/v0.3.x.json +786 -0
  773. package/lib/vendor/blamejs/release-notes/v0.4.x.json +588 -0
  774. package/lib/vendor/blamejs/release-notes/v0.5.x.json +390 -0
  775. package/lib/vendor/blamejs/release-notes/v0.6.x.json +1947 -0
  776. package/lib/vendor/blamejs/release-notes/v0.7.x.json +3811 -0
  777. package/lib/vendor/blamejs/release-notes/v0.8.x.json +3318 -0
  778. package/lib/vendor/blamejs/release-notes/v0.9.x.json +2257 -0
  779. package/lib/vendor/blamejs/scripts/build-vendored-sbom.js +325 -0
  780. package/lib/vendor/blamejs/scripts/check-api-snapshot.js +62 -0
  781. package/lib/vendor/blamejs/scripts/check-changelog-extract.js +108 -0
  782. package/lib/vendor/blamejs/scripts/check-pack-against-gitignore.js +83 -0
  783. package/lib/vendor/blamejs/scripts/check-services.js +483 -0
  784. package/lib/vendor/blamejs/scripts/check-vendor-currency.js +349 -0
  785. package/lib/vendor/blamejs/scripts/consolidate-release-notes.js +216 -0
  786. package/lib/vendor/blamejs/scripts/gen-migrating.js +275 -0
  787. package/lib/vendor/blamejs/scripts/generate-changelog-entry.js +577 -0
  788. package/lib/vendor/blamejs/scripts/generate-release-signing-key.js +79 -0
  789. package/lib/vendor/blamejs/scripts/publish-dep-confusion-placeholder.sh +101 -0
  790. package/lib/vendor/blamejs/scripts/refresh-api-snapshot.js +31 -0
  791. package/lib/vendor/blamejs/scripts/refresh-vendor-manifest.js +132 -0
  792. package/lib/vendor/blamejs/scripts/release.js +652 -0
  793. package/lib/vendor/blamejs/scripts/sha3-digest.js +62 -0
  794. package/lib/vendor/blamejs/scripts/sign-release-artifact.js +92 -0
  795. package/lib/vendor/blamejs/scripts/test-integration.js +181 -0
  796. package/lib/vendor/blamejs/scripts/test-wiki-integration.js +126 -0
  797. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +77 -0
  798. package/lib/vendor/blamejs/scripts/vendor-data-gen.js +186 -0
  799. package/lib/vendor/blamejs/scripts/vendor-data-keygen.js +101 -0
  800. package/lib/vendor/blamejs/scripts/vendor-update.sh +278 -0
  801. package/lib/vendor/blamejs/test/00-primitives.js +19075 -0
  802. package/lib/vendor/blamejs/test/10-state.js +622 -0
  803. package/lib/vendor/blamejs/test/20-db.js +561 -0
  804. package/lib/vendor/blamejs/test/30-chain.js +2110 -0
  805. package/lib/vendor/blamejs/test/40-consumers.js +2453 -0
  806. package/lib/vendor/blamejs/test/50-integration.js +486 -0
  807. package/lib/vendor/blamejs/test/_helpers.js +10 -0
  808. package/lib/vendor/blamejs/test/_smoke-worker.js +69 -0
  809. package/lib/vendor/blamejs/test/fixtures/exploit-corpus/corpus.json +368 -0
  810. package/lib/vendor/blamejs/test/fixtures/http-client-stream-payload.txt +2 -0
  811. package/lib/vendor/blamejs/test/fixtures/worker-pool/echo.js +52 -0
  812. package/lib/vendor/blamejs/test/helpers/_codebase-shingle-worker.js +24 -0
  813. package/lib/vendor/blamejs/test/helpers/_codebase-shingle.js +203 -0
  814. package/lib/vendor/blamejs/test/helpers/_shape-match.js +513 -0
  815. package/lib/vendor/blamejs/test/helpers/check.js +36 -0
  816. package/lib/vendor/blamejs/test/helpers/cluster.js +70 -0
  817. package/lib/vendor/blamejs/test/helpers/db.js +143 -0
  818. package/lib/vendor/blamejs/test/helpers/drivers.js +207 -0
  819. package/lib/vendor/blamejs/test/helpers/fs-watch.js +101 -0
  820. package/lib/vendor/blamejs/test/helpers/http.js +14 -0
  821. package/lib/vendor/blamejs/test/helpers/index.js +93 -0
  822. package/lib/vendor/blamejs/test/helpers/json-round-trip.js +120 -0
  823. package/lib/vendor/blamejs/test/helpers/mocks.js +20 -0
  824. package/lib/vendor/blamejs/test/helpers/otel.js +13 -0
  825. package/lib/vendor/blamejs/test/helpers/services.js +380 -0
  826. package/lib/vendor/blamejs/test/helpers/wait.js +206 -0
  827. package/lib/vendor/blamejs/test/integration/cache.test.js +235 -0
  828. package/lib/vendor/blamejs/test/integration/cluster-provider-mysql.test.js +174 -0
  829. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +611 -0
  830. package/lib/vendor/blamejs/test/integration/http-client.test.js +129 -0
  831. package/lib/vendor/blamejs/test/integration/log-stream.test.js +219 -0
  832. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +181 -0
  833. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +152 -0
  834. package/lib/vendor/blamejs/test/integration/mail-smtp.test.js +161 -0
  835. package/lib/vendor/blamejs/test/integration/mtls-ca.test.js +289 -0
  836. package/lib/vendor/blamejs/test/integration/network-dns.test.js +123 -0
  837. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +101 -0
  838. package/lib/vendor/blamejs/test/integration/ntp-check.test.js +89 -0
  839. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +403 -0
  840. package/lib/vendor/blamejs/test/integration/pqc-pkcs8-forward-compat.test.js +271 -0
  841. package/lib/vendor/blamejs/test/integration/pubsub.test.js +137 -0
  842. package/lib/vendor/blamejs/test/integration/queue-redis.test.js +352 -0
  843. package/lib/vendor/blamejs/test/integration/redis-client-tls.test.js +96 -0
  844. package/lib/vendor/blamejs/test/integration/ssrf-guard.test.js +98 -0
  845. package/lib/vendor/blamejs/test/integration/websocket-permessage-deflate.test.js +261 -0
  846. package/lib/vendor/blamejs/test/integration/ws-client-roundtrip.test.js +230 -0
  847. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +211 -0
  848. package/lib/vendor/blamejs/test/layer-0-primitives/a2a.test.js +59 -0
  849. package/lib/vendor/blamejs/test/layer-0-primitives/access-lock.test.js +136 -0
  850. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +219 -0
  851. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +69 -0
  852. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +266 -0
  853. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +262 -0
  854. package/lib/vendor/blamejs/test/layer-0-primitives/agent-orchestrator.test.js +390 -0
  855. package/lib/vendor/blamejs/test/layer-0-primitives/agent-posture-chain.test.js +174 -0
  856. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +279 -0
  857. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +322 -0
  858. package/lib/vendor/blamejs/test/layer-0-primitives/agent-stream.test.js +227 -0
  859. package/lib/vendor/blamejs/test/layer-0-primitives/agent-tenant.test.js +302 -0
  860. package/lib/vendor/blamejs/test/layer-0-primitives/agent-trace.test.js +150 -0
  861. package/lib/vendor/blamejs/test/layer-0-primitives/ai-adverse-decision.test.js +44 -0
  862. package/lib/vendor/blamejs/test/layer-0-primitives/ai-content-detect.test.js +150 -0
  863. package/lib/vendor/blamejs/test/layer-0-primitives/ai-input.test.js +50 -0
  864. package/lib/vendor/blamejs/test/layer-0-primitives/ai-model-manifest.test.js +96 -0
  865. package/lib/vendor/blamejs/test/layer-0-primitives/ai-pref.test.js +76 -0
  866. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +1080 -0
  867. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +311 -0
  868. package/lib/vendor/blamejs/test/layer-0-primitives/archive-zip-stream.test.js +291 -0
  869. package/lib/vendor/blamejs/test/layer-0-primitives/archive.test.js +140 -0
  870. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +267 -0
  871. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +108 -0
  872. package/lib/vendor/blamejs/test/layer-0-primitives/asyncapi.test.js +929 -0
  873. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-conflict-path.test.js +80 -0
  874. package/lib/vendor/blamejs/test/layer-0-primitives/audit-cve-defensive.test.js +176 -0
  875. package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +132 -0
  876. package/lib/vendor/blamejs/test/layer-0-primitives/audit-export-cadf.test.js +97 -0
  877. package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +141 -0
  878. package/lib/vendor/blamejs/test/layer-0-primitives/audit-segregation.test.js +115 -0
  879. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-ml-dsa-65.test.js +163 -0
  880. package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +246 -0
  881. package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge-verifier.test.js +485 -0
  882. package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +331 -0
  883. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +352 -0
  884. package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +572 -0
  885. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password-audit.test.js +61 -0
  886. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-bucket-ops.test.js +258 -0
  887. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +105 -0
  888. package/lib/vendor/blamejs/test/layer-0-primitives/backup-worker.test.js +34 -0
  889. package/lib/vendor/blamejs/test/layer-0-primitives/bearer-auth.test.js +107 -0
  890. package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-chunked-malformed.test.js +131 -0
  891. package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-smuggling.test.js +118 -0
  892. package/lib/vendor/blamejs/test/layer-0-primitives/boot-gates.test.js +85 -0
  893. package/lib/vendor/blamejs/test/layer-0-primitives/breach-deadline.test.js +38 -0
  894. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +861 -0
  895. package/lib/vendor/blamejs/test/layer-0-primitives/budr.test.js +55 -0
  896. package/lib/vendor/blamejs/test/layer-0-primitives/bundler-engine.test.js +209 -0
  897. package/lib/vendor/blamejs/test/layer-0-primitives/cache-status.test.js +129 -0
  898. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +871 -0
  899. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +891 -0
  900. package/lib/vendor/blamejs/test/layer-0-primitives/canonical-json-jcs.test.js +43 -0
  901. package/lib/vendor/blamejs/test/layer-0-primitives/cdn-cache-control.test.js +243 -0
  902. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +550 -0
  903. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +107 -0
  904. package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +147 -0
  905. package/lib/vendor/blamejs/test/layer-0-primitives/cli-audit-verify-chain.test.js +104 -0
  906. package/lib/vendor/blamejs/test/layer-0-primitives/cli-backup.test.js +135 -0
  907. package/lib/vendor/blamejs/test/layer-0-primitives/cli-config-drift.test.js +67 -0
  908. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +75 -0
  909. package/lib/vendor/blamejs/test/layer-0-primitives/cli-file-type.test.js +98 -0
  910. package/lib/vendor/blamejs/test/layer-0-primitives/cli-helpers.test.js +145 -0
  911. package/lib/vendor/blamejs/test/layer-0-primitives/cli-mtls.test.js +133 -0
  912. package/lib/vendor/blamejs/test/layer-0-primitives/cli-password.test.js +97 -0
  913. package/lib/vendor/blamejs/test/layer-0-primitives/cli-restore.test.js +160 -0
  914. package/lib/vendor/blamejs/test/layer-0-primitives/cli-retention.test.js +84 -0
  915. package/lib/vendor/blamejs/test/layer-0-primitives/cli-security.test.js +69 -0
  916. package/lib/vendor/blamejs/test/layer-0-primitives/cli-vault.test.js +142 -0
  917. package/lib/vendor/blamejs/test/layer-0-primitives/client-hints.test.js +133 -0
  918. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +237 -0
  919. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +9600 -0
  920. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +575 -0
  921. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-cascade.test.js +89 -0
  922. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-eaa.test.js +36 -0
  923. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +712 -0
  924. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +278 -0
  925. package/lib/vendor/blamejs/test/layer-0-primitives/config-drift.test.js +97 -0
  926. package/lib/vendor/blamejs/test/layer-0-primitives/config.test.js +424 -0
  927. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +94 -0
  928. package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +357 -0
  929. package/lib/vendor/blamejs/test/layer-0-primitives/cra-report.test.js +31 -0
  930. package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +226 -0
  931. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +86 -0
  932. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-envelope.test.js +85 -0
  933. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +193 -0
  934. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +98 -0
  935. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke-pq.test.js +132 -0
  936. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke.test.js +155 -0
  937. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-mlkem768-x25519.test.js +129 -0
  938. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-namespace-hash.test.js +0 -0
  939. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-random-int.test.js +72 -0
  940. package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +96 -0
  941. package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +401 -0
  942. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +34 -0
  943. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +180 -0
  944. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +210 -0
  945. package/lib/vendor/blamejs/test/layer-0-primitives/daily-byte-quota.test.js +153 -0
  946. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +66 -0
  947. package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +74 -0
  948. package/lib/vendor/blamejs/test/layer-0-primitives/db-collection-extensions.test.js +226 -0
  949. package/lib/vendor/blamejs/test/layer-0-primitives/db-collection.test.js +136 -0
  950. package/lib/vendor/blamejs/test/layer-0-primitives/db-init-extensions.test.js +165 -0
  951. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +150 -0
  952. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-extensions.test.js +191 -0
  953. package/lib/vendor/blamejs/test/layer-0-primitives/db-role-for.test.js +228 -0
  954. package/lib/vendor/blamejs/test/layer-0-primitives/db-vacuum.test.js +55 -0
  955. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +89 -0
  956. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +184 -0
  957. package/lib/vendor/blamejs/test/layer-0-primitives/declare-row-policy.test.js +203 -0
  958. package/lib/vendor/blamejs/test/layer-0-primitives/declare-view.test.js +303 -0
  959. package/lib/vendor/blamejs/test/layer-0-primitives/dns-dnssec-algorithm.test.js +163 -0
  960. package/lib/vendor/blamejs/test/layer-0-primitives/dns-null-mx.test.js +39 -0
  961. package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +165 -0
  962. package/lib/vendor/blamejs/test/layer-0-primitives/dr-runbook.test.js +59 -0
  963. package/lib/vendor/blamejs/test/layer-0-primitives/dsr-state-rules.test.js +55 -0
  964. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +786 -0
  965. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +105 -0
  966. package/lib/vendor/blamejs/test/layer-0-primitives/early-hints.test.js +147 -0
  967. package/lib/vendor/blamejs/test/layer-0-primitives/events.test.js +105 -0
  968. package/lib/vendor/blamejs/test/layer-0-primitives/exploit-replay.test.js +243 -0
  969. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +181 -0
  970. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +190 -0
  971. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-routing.test.js +531 -0
  972. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +118 -0
  973. package/lib/vendor/blamejs/test/layer-0-primitives/fapi2.test.js +89 -0
  974. package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +156 -0
  975. package/lib/vendor/blamejs/test/layer-0-primitives/fdx.test.js +79 -0
  976. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +216 -0
  977. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +434 -0
  978. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +432 -0
  979. package/lib/vendor/blamejs/test/layer-0-primitives/file-type.test.js +81 -0
  980. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +887 -0
  981. package/lib/vendor/blamejs/test/layer-0-primitives/forensic-snapshot.test.js +51 -0
  982. package/lib/vendor/blamejs/test/layer-0-primitives/fsm.test.js +375 -0
  983. package/lib/vendor/blamejs/test/layer-0-primitives/gcs-bucket-ops.test.js +321 -0
  984. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +41 -0
  985. package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +32 -0
  986. package/lib/vendor/blamejs/test/layer-0-primitives/guard-agent-registry.test.js +87 -0
  987. package/lib/vendor/blamejs/test/layer-0-primitives/guard-all.test.js +328 -0
  988. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +339 -0
  989. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +694 -0
  990. package/lib/vendor/blamejs/test/layer-0-primitives/guard-dsn.test.js +296 -0
  991. package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +234 -0
  992. package/lib/vendor/blamejs/test/layer-0-primitives/guard-envelope.test.js +192 -0
  993. package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-payload.test.js +89 -0
  994. package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-topic.test.js +71 -0
  995. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +386 -0
  996. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html-wcag.test.js +859 -0
  997. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +357 -0
  998. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +92 -0
  999. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  1000. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +174 -0
  1001. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +317 -0
  1002. package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-id.test.js +199 -0
  1003. package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-unsubscribe.test.js +214 -0
  1004. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-compose.test.js +111 -0
  1005. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-move.test.js +110 -0
  1006. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-query.test.js +112 -0
  1007. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-reply.test.js +86 -0
  1008. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-sieve.test.js +92 -0
  1009. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +301 -0
  1010. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +265 -0
  1011. package/lib/vendor/blamejs/test/layer-0-primitives/guard-message-id.test.js +0 -0
  1012. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +161 -0
  1013. package/lib/vendor/blamejs/test/layer-0-primitives/guard-posture-chain.test.js +100 -0
  1014. package/lib/vendor/blamejs/test/layer-0-primitives/guard-saga-config.test.js +79 -0
  1015. package/lib/vendor/blamejs/test/layer-0-primitives/guard-smtp-command.test.js +269 -0
  1016. package/lib/vendor/blamejs/test/layer-0-primitives/guard-snapshot-envelope.test.js +89 -0
  1017. package/lib/vendor/blamejs/test/layer-0-primitives/guard-stream-args.test.js +78 -0
  1018. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +288 -0
  1019. package/lib/vendor/blamejs/test/layer-0-primitives/guard-tenant-id.test.js +69 -0
  1020. package/lib/vendor/blamejs/test/layer-0-primitives/guard-trace-context.test.js +102 -0
  1021. package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +202 -0
  1022. package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +203 -0
  1023. package/lib/vendor/blamejs/test/layer-0-primitives/hal.test.js +51 -0
  1024. package/lib/vendor/blamejs/test/layer-0-primitives/honeytoken.test.js +50 -0
  1025. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +37 -0
  1026. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +692 -0
  1027. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +280 -0
  1028. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +225 -0
  1029. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +203 -0
  1030. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +991 -0
  1031. package/lib/vendor/blamejs/test/layer-0-primitives/iab-mspa.test.js +63 -0
  1032. package/lib/vendor/blamejs/test/layer-0-primitives/iab-tcf.test.js +73 -0
  1033. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +612 -0
  1034. package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +56 -0
  1035. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +166 -0
  1036. package/lib/vendor/blamejs/test/layer-0-primitives/incident-report.test.js +29 -0
  1037. package/lib/vendor/blamejs/test/layer-0-primitives/jose-jwe-experimental.test.js +121 -0
  1038. package/lib/vendor/blamejs/test/layer-0-primitives/json-api.test.js +58 -0
  1039. package/lib/vendor/blamejs/test/layer-0-primitives/json-round-trip-helper.test.js +110 -0
  1040. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +159 -0
  1041. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  1042. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +118 -0
  1043. package/lib/vendor/blamejs/test/layer-0-primitives/local-db-thin.test.js +150 -0
  1044. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-cloudwatch.test.js +489 -0
  1045. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp-grpc.test.js +207 -0
  1046. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp.test.js +283 -0
  1047. package/lib/vendor/blamejs/test/layer-0-primitives/lro.test.js +65 -0
  1048. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +417 -0
  1049. package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +208 -0
  1050. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +910 -0
  1051. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +502 -0
  1052. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +680 -0
  1053. package/lib/vendor/blamejs/test/layer-0-primitives/mail-canspam.test.js +128 -0
  1054. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +149 -0
  1055. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +323 -0
  1056. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +297 -0
  1057. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +514 -0
  1058. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy-tlsrpt.test.js +369 -0
  1059. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +199 -0
  1060. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +627 -0
  1061. package/lib/vendor/blamejs/test/layer-0-primitives/mail-feedback-id.test.js +56 -0
  1062. package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +217 -0
  1063. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +283 -0
  1064. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +217 -0
  1065. package/lib/vendor/blamejs/test/layer-0-primitives/mail-mdn.test.js +334 -0
  1066. package/lib/vendor/blamejs/test/layer-0-primitives/mail-rbl.test.js +271 -0
  1067. package/lib/vendor/blamejs/test/layer-0-primitives/mail-require-tls.test.js +128 -0
  1068. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +215 -0
  1069. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +336 -0
  1070. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +732 -0
  1071. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +840 -0
  1072. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +130 -0
  1073. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +285 -0
  1074. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +74 -0
  1075. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +112 -0
  1076. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +229 -0
  1077. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +394 -0
  1078. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +147 -0
  1079. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +151 -0
  1080. package/lib/vendor/blamejs/test/layer-0-primitives/mail-spam-score.test.js +204 -0
  1081. package/lib/vendor/blamejs/test/layer-0-primitives/mail-srs.test.js +152 -0
  1082. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +279 -0
  1083. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +323 -0
  1084. package/lib/vendor/blamejs/test/layer-0-primitives/mail-unsubscribe.test.js +165 -0
  1085. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +439 -0
  1086. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-tool-registry.test.js +202 -0
  1087. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +155 -0
  1088. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-shadow-registry.test.js +112 -0
  1089. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +224 -0
  1090. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-compose-pipeline.test.js +278 -0
  1091. package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +376 -0
  1092. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-paths.test.js +89 -0
  1093. package/lib/vendor/blamejs/test/layer-0-primitives/nel.test.js +200 -0
  1094. package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +106 -0
  1095. package/lib/vendor/blamejs/test/layer-0-primitives/network-byte-quota.test.js +133 -0
  1096. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +372 -0
  1097. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +635 -0
  1098. package/lib/vendor/blamejs/test/layer-0-primitives/network-heartbeat-passive.test.js +128 -0
  1099. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-build-options.test.js +130 -0
  1100. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-ct-inclusion.test.js +179 -0
  1101. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +447 -0
  1102. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +369 -0
  1103. package/lib/vendor/blamejs/test/layer-0-primitives/nis2-report.test.js +21 -0
  1104. package/lib/vendor/blamejs/test/layer-0-primitives/nist-crosswalk.test.js +42 -0
  1105. package/lib/vendor/blamejs/test/layer-0-primitives/no-cache.test.js +98 -0
  1106. package/lib/vendor/blamejs/test/layer-0-primitives/notify.test.js +707 -0
  1107. package/lib/vendor/blamejs/test/layer-0-primitives/numeric-bounds.test.js +142 -0
  1108. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +72 -0
  1109. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +597 -0
  1110. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +190 -0
  1111. package/lib/vendor/blamejs/test/layer-0-primitives/openapi.test.js +877 -0
  1112. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +257 -0
  1113. package/lib/vendor/blamejs/test/layer-0-primitives/pagination.test.js +522 -0
  1114. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +216 -0
  1115. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +324 -0
  1116. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +546 -0
  1117. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +153 -0
  1118. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-software.test.js +94 -0
  1119. package/lib/vendor/blamejs/test/layer-0-primitives/problem-details.test.js +195 -0
  1120. package/lib/vendor/blamejs/test/layer-0-primitives/process-spawn.test.js +62 -0
  1121. package/lib/vendor/blamejs/test/layer-0-primitives/promise-pool.test.js +93 -0
  1122. package/lib/vendor/blamejs/test/layer-0-primitives/protected-resource-metadata.test.js +68 -0
  1123. package/lib/vendor/blamejs/test/layer-0-primitives/protobuf-encoder.test.js +138 -0
  1124. package/lib/vendor/blamejs/test/layer-0-primitives/protocol-dispatcher.test.js +174 -0
  1125. package/lib/vendor/blamejs/test/layer-0-primitives/public-suffix.test.js +197 -0
  1126. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +232 -0
  1127. package/lib/vendor/blamejs/test/layer-0-primitives/queue-dlq-extend-lease.test.js +178 -0
  1128. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +322 -0
  1129. package/lib/vendor/blamejs/test/layer-0-primitives/queue-priority-rate-progress.test.js +266 -0
  1130. package/lib/vendor/blamejs/test/layer-0-primitives/queue-sqs.test.js +300 -0
  1131. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-cluster.test.js +338 -0
  1132. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-registry.test.js +75 -0
  1133. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +246 -0
  1134. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +130 -0
  1135. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +335 -0
  1136. package/lib/vendor/blamejs/test/layer-0-primitives/request-log.test.js +170 -0
  1137. package/lib/vendor/blamejs/test/layer-0-primitives/require-auth-cache-control.test.js +93 -0
  1138. package/lib/vendor/blamejs/test/layer-0-primitives/require-mtls.test.js +34 -0
  1139. package/lib/vendor/blamejs/test/layer-0-primitives/resource-access-lock.test.js +52 -0
  1140. package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +67 -0
  1141. package/lib/vendor/blamejs/test/layer-0-primitives/retry.test.js +535 -0
  1142. package/lib/vendor/blamejs/test/layer-0-primitives/router-cross-origin-redirect.test.js +0 -0
  1143. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +128 -0
  1144. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +163 -0
  1145. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-parallel.test.js +170 -0
  1146. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +248 -0
  1147. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +451 -0
  1148. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +289 -0
  1149. package/lib/vendor/blamejs/test/layer-0-primitives/safe-icap.test.js +206 -0
  1150. package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +104 -0
  1151. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +339 -0
  1152. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mount-info.test.js +180 -0
  1153. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +78 -0
  1154. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sieve.test.js +123 -0
  1155. package/lib/vendor/blamejs/test/layer-0-primitives/safe-smtp.test.js +95 -0
  1156. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-idn-homograph.test.js +77 -0
  1157. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +257 -0
  1158. package/lib/vendor/blamejs/test/layer-0-primitives/saml-slo.test.js +249 -0
  1159. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +228 -0
  1160. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-exactly-once.test.js +238 -0
  1161. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +92 -0
  1162. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +700 -0
  1163. package/lib/vendor/blamejs/test/layer-0-primitives/sd-notify.test.js +67 -0
  1164. package/lib/vendor/blamejs/test/layer-0-primitives/sec-cyber.test.js +85 -0
  1165. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +107 -0
  1166. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +175 -0
  1167. package/lib/vendor/blamejs/test/layer-0-primitives/seeders.test.js +816 -0
  1168. package/lib/vendor/blamejs/test/layer-0-primitives/self-update-standalone-verifier.test.js +168 -0
  1169. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +302 -0
  1170. package/lib/vendor/blamejs/test/layer-0-primitives/server-timing.test.js +93 -0
  1171. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +247 -0
  1172. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +295 -0
  1173. package/lib/vendor/blamejs/test/layer-0-primitives/shape-match.test.js +142 -0
  1174. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +952 -0
  1175. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-multipart-sse.test.js +441 -0
  1176. package/lib/vendor/blamejs/test/layer-0-primitives/slug.test.js +330 -0
  1177. package/lib/vendor/blamejs/test/layer-0-primitives/smtp-policy.test.js +233 -0
  1178. package/lib/vendor/blamejs/test/layer-0-primitives/source-comment-blocks.test.js +105 -0
  1179. package/lib/vendor/blamejs/test/layer-0-primitives/speculation-rules.test.js +319 -0
  1180. package/lib/vendor/blamejs/test/layer-0-primitives/sse.test.js +148 -0
  1181. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +283 -0
  1182. package/lib/vendor/blamejs/test/layer-0-primitives/standard-webhooks.test.js +67 -0
  1183. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +266 -0
  1184. package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +487 -0
  1185. package/lib/vendor/blamejs/test/layer-0-primitives/storage-chunk-scratch.test.js +0 -0
  1186. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +773 -0
  1187. package/lib/vendor/blamejs/test/layer-0-primitives/stream-throttle.test.js +173 -0
  1188. package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +180 -0
  1189. package/lib/vendor/blamejs/test/layer-0-primitives/tcpa-10dlc.test.js +66 -0
  1190. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +89 -0
  1191. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +571 -0
  1192. package/lib/vendor/blamejs/test/layer-0-primitives/test-harness.test.js +190 -0
  1193. package/lib/vendor/blamejs/test/layer-0-primitives/testing-request.test.js +119 -0
  1194. package/lib/vendor/blamejs/test/layer-0-primitives/testing.test.js +522 -0
  1195. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +151 -0
  1196. package/lib/vendor/blamejs/test/layer-0-primitives/tls-exporter.test.js +168 -0
  1197. package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-ct.test.js +275 -0
  1198. package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-verify.test.js +105 -0
  1199. package/lib/vendor/blamejs/test/layer-0-primitives/tls-pinset-drift.test.js +35 -0
  1200. package/lib/vendor/blamejs/test/layer-0-primitives/tls-preferred-groups.test.js +81 -0
  1201. package/lib/vendor/blamejs/test/layer-0-primitives/tracing.test.js +280 -0
  1202. package/lib/vendor/blamejs/test/layer-0-primitives/uuid.test.js +93 -0
  1203. package/lib/vendor/blamejs/test/layer-0-primitives/vault-aad.test.js +277 -0
  1204. package/lib/vendor/blamejs/test/layer-0-primitives/vault-seal-pem-file.test.js +252 -0
  1205. package/lib/vendor/blamejs/test/layer-0-primitives/vendor-data.test.js +149 -0
  1206. package/lib/vendor/blamejs/test/layer-0-primitives/vendor-manifest.test.js +92 -0
  1207. package/lib/vendor/blamejs/test/layer-0-primitives/vex.test.js +661 -0
  1208. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +308 -0
  1209. package/lib/vendor/blamejs/test/layer-0-primitives/web-push-vapid.test.js +144 -0
  1210. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +674 -0
  1211. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-channels.test.js +360 -0
  1212. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool.test.js +302 -0
  1213. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +349 -0
  1214. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +717 -0
  1215. package/lib/vendor/blamejs/test/layer-5-integration/bundler-output.test.js +444 -0
  1216. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +597 -0
  1217. package/lib/vendor/blamejs/test/layer-5-integration/security-chaos.test.js +308 -0
  1218. package/lib/vendor/blamejs/test/smoke.js +431 -0
  1219. package/lib/webhooks.js +305 -0
  1220. package/package.json +43 -0
@@ -0,0 +1,3126 @@
1
+ "use strict";
2
+
3
+ var nodeTls = require("node:tls");
4
+ var nodeFs = require("node:fs");
5
+ var nodePath = require("node:path");
6
+ var net = require("node:net");
7
+ var nodeCrypto = require("node:crypto");
8
+
9
+ var bCrypto = require("./crypto");
10
+ var C = require("./constants");
11
+ var safeBuffer = require("./safe-buffer");
12
+ var validateOpts = require("./validate-opts");
13
+ var lazyRequire = require("./lazy-require");
14
+ var safeAsync = require("./safe-async");
15
+ var { defineClass } = require("./framework-error");
16
+
17
+ var TlsTrustError = defineClass("TlsTrustError", { alwaysPermanent: true });
18
+ var NetworkTlsError = defineClass("NetworkTlsError", { alwaysPermanent: true });
19
+
20
+ var observability = lazyRequire(function () { return require("./observability"); });
21
+ var audit = lazyRequire(function () { return require("./audit"); });
22
+ var networkDns = lazyRequire(function () { return require("./network-dns"); });
23
+ var asn1 = require("./asn1-der");
24
+
25
+ // STATE.tlsKeyShares is initialized to the default PQC group list at
26
+ // module load — operator setKeyShares() overrides; resetKeyShares()
27
+ // restores the default. Empty array means "fall back to Node's TLS
28
+ // default groups" (operator opt-out).
29
+ var STATE = {
30
+ cas: [],
31
+ systemTrust: false,
32
+ baselineFingerprints: null,
33
+ tlsKeyShares: ["X25519MLKEM768", "SecP256r1MLKEM768", "SecP384r1MLKEM1024", "X25519"],
34
+ };
35
+
36
+ function _normalizePem(pem) {
37
+ if (Buffer.isBuffer(pem)) pem = pem.toString("utf8");
38
+ if (typeof pem !== "string") {
39
+ throw new TlsTrustError("tls/bad-ca", "CA must be a PEM string or path, got " + typeof pem);
40
+ }
41
+ return pem.replace(/\r\n/g, "\n").trim();
42
+ }
43
+
44
+ function _splitPemBundle(pem) {
45
+ var blocks = [];
46
+ var lines = pem.split("\n");
47
+ var current = null;
48
+ for (var i = 0; i < lines.length; i++) {
49
+ var line = lines[i];
50
+ if (line.indexOf("-----BEGIN CERTIFICATE-----") === 0) {
51
+ current = [line];
52
+ } else if (current) {
53
+ current.push(line);
54
+ if (line.indexOf("-----END CERTIFICATE-----") === 0) {
55
+ blocks.push(current.join("\n"));
56
+ current = null;
57
+ }
58
+ }
59
+ }
60
+ return blocks;
61
+ }
62
+
63
+ function _certMetadata(pem) {
64
+ try {
65
+ var x = new nodeCrypto.X509Certificate(pem);
66
+ return {
67
+ subject: x.subject,
68
+ issuer: x.issuer,
69
+ validFrom: x.validFrom,
70
+ validTo: x.validTo,
71
+ fingerprint256: x.fingerprint256,
72
+ serialNumber: x.serialNumber,
73
+ isSelfSigned: x.subject === x.issuer,
74
+ };
75
+ } catch (e) {
76
+ throw new TlsTrustError("tls/bad-ca-pem", "CA PEM not parseable: " + e.message);
77
+ }
78
+ }
79
+
80
+ function _isPathLike(s) {
81
+ if (s.indexOf("-----BEGIN") !== -1) return false;
82
+ if (s.length > C.BYTES.kib(1)) return false;
83
+ if (safeBuffer.hasCrlf(s)) return false;
84
+ return true;
85
+ }
86
+
87
+ // CodeQL js/file-system-race defense — fd-based read binds the size +
88
+ // content measurement to the inode the fd holds open. The cert path is
89
+ // operator-supplied (tls.addCa) but routing through openSync + fstatSync
90
+ // + readSync narrows the race window vs the prior statSync + readFileSync
91
+ // shape, where an attacker who could swap the file in-between could
92
+ // short-circuit the PEM marker check downstream.
93
+ function _readPathFile(p) {
94
+ var fd = nodeFs.openSync(p, "r");
95
+ try {
96
+ var fstat = nodeFs.fstatSync(fd);
97
+ var buf = Buffer.alloc(fstat.size);
98
+ var read = 0;
99
+ while (read < fstat.size) {
100
+ var n = nodeFs.readSync(fd, buf, read, fstat.size - read, null);
101
+ if (n === 0) break;
102
+ read += n;
103
+ }
104
+ return buf.slice(0, read).toString("utf8");
105
+ } finally {
106
+ try { nodeFs.closeSync(fd); } catch (_c) { /* close best-effort */ }
107
+ }
108
+ }
109
+
110
+ function _readPath(p) {
111
+ var stat = nodeFs.statSync(p);
112
+ if (stat.isDirectory()) {
113
+ var files = nodeFs.readdirSync(p)
114
+ .filter(function (f) { return /\.(pem|crt|cer)$/i.test(f); })
115
+ .sort();
116
+ return files.map(function (f) { return _readPathFile(nodePath.join(p, f)); }).join("\n");
117
+ }
118
+ return _readPathFile(p);
119
+ }
120
+
121
+ function addCa(pemOrPath, opts) {
122
+ opts = opts || {};
123
+ validateOpts(opts, ["label", "audit"], "tls.addCa");
124
+ var raw = pemOrPath;
125
+ if (typeof pemOrPath === "string" && _isPathLike(pemOrPath)) {
126
+ var stat;
127
+ try { stat = nodeFs.statSync(pemOrPath); } catch (_e) {
128
+ throw new TlsTrustError("tls/empty-pem", "tls.addCa: input has no PEM marker and is not a readable path: " +
129
+ pemOrPath);
130
+ }
131
+ raw = _readPath(pemOrPath);
132
+ if (!stat) raw = "";
133
+ }
134
+ raw = _normalizePem(raw);
135
+ var blocks = _splitPemBundle(raw);
136
+ if (blocks.length === 0) {
137
+ throw new TlsTrustError("tls/empty-pem", "no CERTIFICATE blocks found in PEM input");
138
+ }
139
+ var added = [];
140
+ for (var i = 0; i < blocks.length; i++) {
141
+ var meta = _certMetadata(blocks[i]);
142
+ STATE.cas.push({ pem: blocks[i], meta: meta, label: opts.label || null, addedAt: Date.now() });
143
+ added.push(meta);
144
+ }
145
+ _emitAuditAdd(added, opts);
146
+ _emitObs("network.tls.ca.added", { count: added.length });
147
+ return added;
148
+ }
149
+
150
+ function addCaBundle(p, opts) {
151
+ return addCa(p, opts);
152
+ }
153
+
154
+ function useSystemTrust(enable) {
155
+ STATE.systemTrust = enable !== false;
156
+ _emitObs("network.tls.system_trust.set", { enabled: STATE.systemTrust });
157
+ }
158
+
159
+ function isSystemTrustEnabled() { return !!STATE.systemTrust; }
160
+
161
+ function getTrustStore() {
162
+ return STATE.cas.map(function (entry) {
163
+ return {
164
+ label: entry.label,
165
+ addedAt: entry.addedAt,
166
+ subject: entry.meta.subject,
167
+ issuer: entry.meta.issuer,
168
+ validFrom: entry.meta.validFrom,
169
+ validTo: entry.meta.validTo,
170
+ fingerprint256: entry.meta.fingerprint256,
171
+ serialNumber: entry.meta.serialNumber,
172
+ isSelfSigned: entry.meta.isSelfSigned,
173
+ };
174
+ });
175
+ }
176
+
177
+ function _emitAuditRemove(metaList, reason) {
178
+ var sink;
179
+ try { sink = audit(); } catch (_e) { sink = null; }
180
+ if (!sink || typeof sink.safeEmit !== "function") return;
181
+ for (var i = 0; i < metaList.length; i++) {
182
+ var m = metaList[i];
183
+ try {
184
+ sink.safeEmit({
185
+ action: "network.tls.ca.removed",
186
+ outcome: "success",
187
+ metadata: {
188
+ subject: m.subject,
189
+ issuer: m.issuer,
190
+ fingerprint256: m.fingerprint256,
191
+ validFrom: m.validFrom,
192
+ validTo: m.validTo,
193
+ isSelfSigned: m.isSelfSigned,
194
+ label: m.label,
195
+ reason: reason || "operator",
196
+ },
197
+ });
198
+ } catch (_e) { /* audit best-effort — never break the caller */ }
199
+ }
200
+ }
201
+
202
+ function removeCa(fingerprint256, opts) {
203
+ if (typeof fingerprint256 !== "string" || fingerprint256.length === 0) {
204
+ throw new TlsTrustError("tls/bad-fingerprint", "tls.removeCa: fingerprint256 must be a non-empty string");
205
+ }
206
+ var fp = fingerprint256.toUpperCase();
207
+ var removed = [];
208
+ STATE.cas = STATE.cas.filter(function (entry) {
209
+ var entryFp = (entry.meta.fingerprint256 || "").toUpperCase();
210
+ if (entryFp === fp) {
211
+ removed.push(Object.assign({ label: entry.label }, entry.meta));
212
+ return false;
213
+ }
214
+ return true;
215
+ });
216
+ if (removed.length === 0) return 0;
217
+ if (!opts || opts.audit !== false) _emitAuditRemove(removed, "operator-remove");
218
+ _emitObs("network.tls.ca.removed", { count: removed.length, reason: "operator" });
219
+ return removed.length;
220
+ }
221
+
222
+ function removeCaByLabel(label, opts) {
223
+ if (typeof label !== "string" || label.length === 0) {
224
+ throw new TlsTrustError("tls/bad-label", "tls.removeCaByLabel: label must be a non-empty string");
225
+ }
226
+ var removed = [];
227
+ STATE.cas = STATE.cas.filter(function (entry) {
228
+ if (entry.label === label) {
229
+ removed.push(Object.assign({ label: entry.label }, entry.meta));
230
+ return false;
231
+ }
232
+ return true;
233
+ });
234
+ if (removed.length === 0) return 0;
235
+ if (!opts || opts.audit !== false) _emitAuditRemove(removed, "operator-remove-by-label");
236
+ _emitObs("network.tls.ca.removed", { count: removed.length, reason: "label" });
237
+ return removed.length;
238
+ }
239
+
240
+ function clearAll(opts) {
241
+ if (STATE.cas.length === 0) return 0;
242
+ var removed = STATE.cas.map(function (e) { return Object.assign({ label: e.label }, e.meta); });
243
+ STATE.cas = [];
244
+ if (!opts || opts.audit !== false) _emitAuditRemove(removed, "operator-clear-all");
245
+ _emitObs("network.tls.ca.cleared", { count: removed.length });
246
+ return removed.length;
247
+ }
248
+
249
+ function purgeExpired(opts) {
250
+ var nowMs = Date.now();
251
+ var removed = [];
252
+ STATE.cas = STATE.cas.filter(function (entry) {
253
+ var validToMs = entry.meta.validTo ? Date.parse(entry.meta.validTo) : NaN;
254
+ if (isFinite(validToMs) && validToMs < nowMs) {
255
+ removed.push(Object.assign({ label: entry.label }, entry.meta));
256
+ return false;
257
+ }
258
+ return true;
259
+ });
260
+ if (removed.length === 0) return 0;
261
+ if (!opts || opts.audit !== false) _emitAuditRemove(removed, "expired");
262
+ _emitObs("network.tls.ca.purged_expired", { count: removed.length });
263
+ return removed.length;
264
+ }
265
+
266
+ function expiringSoon(windowMs) {
267
+ if (typeof windowMs !== "number" || !isFinite(windowMs) || windowMs < 0) {
268
+ throw new TlsTrustError("tls/bad-window", "tls.expiringSoon: windowMs must be a non-negative finite number");
269
+ }
270
+ var threshold = Date.now() + windowMs;
271
+ return STATE.cas.filter(function (entry) {
272
+ var validToMs = entry.meta.validTo ? Date.parse(entry.meta.validTo) : NaN;
273
+ return isFinite(validToMs) && validToMs <= threshold;
274
+ }).map(function (entry) {
275
+ return Object.assign({ label: entry.label }, entry.meta);
276
+ });
277
+ }
278
+
279
+ // expiryMonitor — periodic check that emits audit + observability
280
+ // events when any CA in the trust store falls inside the expiry
281
+ // window. Returns a handle with .stop() for graceful shutdown.
282
+ //
283
+ // var mon = b.network.tls.expiryMonitor({
284
+ // intervalMs: C.TIME.hours(6),
285
+ // windowMs: C.TIME.days(30),
286
+ // onExpiring: function (rows) { /* operator hook — alerts */ },
287
+ // });
288
+ // ...
289
+ // mon.stop();
290
+ //
291
+ // Audit emissions:
292
+ // network.tls.ca.expiry_check — every check, reports total + expiring count
293
+ // network.tls.ca.expiring — when expiringSoon(windowMs) > 0
294
+ //
295
+ // Observability event: network.tls.ca.expiring counter labeled with
296
+ // the count.
297
+ function expiryMonitor(opts) {
298
+ opts = opts || {};
299
+ var intervalMs = opts.intervalMs;
300
+ var windowMs = opts.windowMs;
301
+ var auditOn = opts.audit !== false;
302
+ if (typeof intervalMs !== "number" || !isFinite(intervalMs) || intervalMs <= 0) {
303
+ throw new TlsTrustError("tls/bad-interval",
304
+ "tls.expiryMonitor: intervalMs must be a positive finite number");
305
+ }
306
+ if (typeof windowMs !== "number" || !isFinite(windowMs) || windowMs <= 0) {
307
+ throw new TlsTrustError("tls/bad-window",
308
+ "tls.expiryMonitor: windowMs must be a positive finite number");
309
+ }
310
+
311
+ function _tick() {
312
+ var rows;
313
+ try { rows = expiringSoon(windowMs); }
314
+ catch (_e) { return; }
315
+ if (auditOn) {
316
+ try {
317
+ audit().safeEmit({
318
+ action: "network.tls.ca.expiry_check",
319
+ outcome: rows.length > 0 ? "warn" : "ok",
320
+ metadata: { total: STATE.cas.length, expiring: rows.length, windowMs: windowMs },
321
+ });
322
+ } catch (_e) { /* drop-silent */ }
323
+ }
324
+ if (rows.length > 0) {
325
+ try { observability().safeEvent("network.tls.ca.expiring", rows.length, {}); }
326
+ catch (_e) { /* drop-silent */ }
327
+ if (auditOn) {
328
+ try {
329
+ audit().safeEmit({
330
+ action: "network.tls.ca.expiring",
331
+ outcome: "success",
332
+ metadata: {
333
+ count: rows.length,
334
+ labels: rows.map(function (r) { return r.label; }),
335
+ earliestValidTo: rows.reduce(function (acc, r) {
336
+ var ms = r.validTo ? Date.parse(r.validTo) : Infinity;
337
+ return ms < acc ? ms : acc;
338
+ }, Infinity),
339
+ },
340
+ });
341
+ } catch (_e) { /* drop-silent */ }
342
+ }
343
+ if (typeof opts.onExpiring === "function") {
344
+ try { opts.onExpiring(rows); } catch (_e) { /* operator hook */ }
345
+ }
346
+ }
347
+ }
348
+
349
+ var handle = safeAsync.repeating(_tick, intervalMs, { name: "tls-expiry-monitor" });
350
+ return {
351
+ stop: function () { if (handle) { handle.stop(); handle = null; } },
352
+ };
353
+ }
354
+
355
+ function captureBaselineFingerprints() {
356
+ STATE.baselineFingerprints = STATE.cas.map(function (e) { return e.meta.fingerprint256; });
357
+ }
358
+
359
+ // pinsetDriftMonitor — periodic check that emits audit + observability
360
+ // events when the trust-store fingerprint set drifts from the captured
361
+ // baseline. Different intent from expiryMonitor: this fires when a
362
+ // CA is added or removed (by operator config-flip OR by a tampered
363
+ // MANIFEST / vendor refresh), not when an existing one approaches
364
+ // validity expiry.
365
+ //
366
+ // b.network.tls.captureBaselineFingerprints(); // at boot
367
+ // var mon = b.network.tls.pinsetDriftMonitor({
368
+ // intervalMs: C.TIME.minutes(15),
369
+ // onDrift: function (drift) { /* operator hook */ },
370
+ // });
371
+ //
372
+ // Audit emissions:
373
+ // network.tls.pinset.drift_check — every check, ok / warn
374
+ // network.tls.pinset.drifted — when added.length || removed.length
375
+ function pinsetDriftMonitor(opts) {
376
+ opts = opts || {};
377
+ var intervalMs = opts.intervalMs;
378
+ var auditOn = opts.audit !== false;
379
+ if (typeof intervalMs !== "number" || !isFinite(intervalMs) || intervalMs <= 0) {
380
+ throw new TlsTrustError("tls/bad-interval",
381
+ "tls.pinsetDriftMonitor: intervalMs must be a positive finite number");
382
+ }
383
+ function _tick() {
384
+ var drift;
385
+ try { drift = detectBaselineDrift(); }
386
+ catch (_e) { return; }
387
+ if (drift === null) return; // baseline not captured; nothing to compare
388
+ if (auditOn) {
389
+ try {
390
+ audit().safeEmit({
391
+ action: "network.tls.pinset.drift_check",
392
+ outcome: drift.drifted ? "warn" : "ok",
393
+ metadata: { added: drift.added.length, removed: drift.removed.length },
394
+ });
395
+ } catch (_e) { /* drop-silent */ }
396
+ }
397
+ if (drift.drifted) {
398
+ try { observability().safeEvent("network.tls.pinset.drifted", 1, {}); }
399
+ catch (_e) { /* drop-silent */ }
400
+ if (auditOn) {
401
+ try {
402
+ audit().safeEmit({
403
+ action: "network.tls.pinset.drifted",
404
+ outcome: "failure",
405
+ metadata: { added: drift.added, removed: drift.removed },
406
+ });
407
+ } catch (_e) { /* drop-silent */ }
408
+ }
409
+ if (typeof opts.onDrift === "function") {
410
+ try { opts.onDrift(drift); } catch (_e) { /* operator hook */ }
411
+ }
412
+ }
413
+ }
414
+ var handle = safeAsync.repeating(_tick, intervalMs, { name: "tls-pinset-drift-monitor" });
415
+ return {
416
+ stop: function () { if (handle) { handle.stop(); handle = null; } },
417
+ };
418
+ }
419
+
420
+ function detectBaselineDrift() {
421
+ if (!STATE.baselineFingerprints) return null;
422
+ var current = STATE.cas.map(function (e) { return e.meta.fingerprint256; });
423
+ var added = current.filter(function (fp) { return STATE.baselineFingerprints.indexOf(fp) === -1; });
424
+ var removed = STATE.baselineFingerprints.filter(function (fp) { return current.indexOf(fp) === -1; });
425
+ return { added: added, removed: removed, drifted: added.length > 0 || removed.length > 0 };
426
+ }
427
+
428
+ function applyToContext(opts) {
429
+ opts = opts || {};
430
+ validateOpts(opts, ["base"], "tls.applyToContext");
431
+ var base = Object.assign({}, opts.base || {});
432
+ var caStrings = STATE.cas.map(function (e) { return e.pem; });
433
+ if (STATE.systemTrust) {
434
+ var rootCAs = nodeTls.rootCertificates;
435
+ if (Array.isArray(rootCAs)) {
436
+ caStrings = caStrings.concat(rootCAs);
437
+ }
438
+ }
439
+ if (caStrings.length > 0) base.ca = caStrings;
440
+ // PQC TLS handshake — apply the operator-configured key-share groups
441
+ // (default ["X25519MLKEM768", "X25519"]) so https.Server / https.Agent
442
+ // negotiate the hybrid KEM with peers that support it and fall back
443
+ // to classical X25519 with peers that don't. Operators who explicitly
444
+ // pass `groups` in their base config keep the override.
445
+ if (base.groups === undefined && STATE.tlsKeyShares.length > 0) {
446
+ base.groups = STATE.tlsKeyShares.join(":");
447
+ }
448
+ return base;
449
+ }
450
+
451
+ // ---- PQC TLS key shares (RFC draft-ietf-tls-hybrid-design) ----
452
+ //
453
+ // b.network.tls.pqc.setKeyShares(["X25519MLKEM768", "X25519"]) — set the
454
+ // TLS 1.3 key-share groups the framework's https.Server / https.Agent
455
+ // will advertise. The first listed group is the priority; the peer
456
+ // picks the first mutually supported entry. Hybrid groups
457
+ // (X25519MLKEM768) negotiate post-quantum + classical in one
458
+ // handshake so forward-secrecy survives both classical-CRQC and
459
+ // future quantum cryptanalysis.
460
+ //
461
+ // getKeyShares() → string[] (current)
462
+ // setKeyShares(["X25519MLKEM768", "X25519"]) → string[] (after)
463
+ // resetKeyShares() → restores default
464
+
465
+ // RFC 9794 (PQ TLS Hybrid Key Exchange) named-group ordering. The
466
+ // preferred groups (the first the peer mutually supports wins) put the
467
+ // IANA-registered hybrid named groups ahead of the classical fallback:
468
+ //
469
+ // X25519MLKEM768 — codepoint 0x11EC, RFC 9794 default hybrid
470
+ // SecP256r1MLKEM768 — codepoint 0x11EB, RFC 9794 optional hybrid
471
+ // (NIST-curve fallback for FIPS-mandated peers
472
+ // that refuse X25519)
473
+ // SecP384r1MLKEM1024 — draft-kwiatkowski-tls-ecdhe-mlkem-02 codepoint
474
+ // 0x11ED; highest-PQC hybrid; only ML-KEM-1024
475
+ // offering for FIPS-mandated peers wanting
476
+ // CNSA-2.0-aligned key strength
477
+ // X25519 — classical fallback (modern non-PQC peers)
478
+ //
479
+ // Operators FIPS-mandated to a NIST curve set `setKeyShares([
480
+ // "SecP256r1MLKEM768", "SecP384r1MLKEM1024" ])` and drop the X25519-
481
+ // based groups. Operators on legacy peers without any PQC support set
482
+ // `setKeyShares(["X25519"])` to opt out of the hybrid groups entirely.
483
+ var DEFAULT_PQC_KEY_SHARES = Object.freeze([
484
+ "X25519MLKEM768",
485
+ "SecP256r1MLKEM768",
486
+ "SecP384r1MLKEM1024",
487
+ "X25519",
488
+ ]);
489
+
490
+ function _validateKeyShare(name) {
491
+ if (typeof name !== "string" || name.length === 0 || name.length > C.BYTES.bytes(64)) { // bound
492
+ throw new TlsTrustError("tls/bad-key-share",
493
+ "tls.pqc.setKeyShares: each entry must be a non-empty string up to 64 chars");
494
+ }
495
+ // RFC draft-ietf-tls-hybrid-design + IANA TLS Group Registry only
496
+ // emit alphanumeric + underscore identifiers. Refuse `:` (the join
497
+ // separator) outright so an operator can't smuggle a second entry
498
+ // through one slot.
499
+ if (!/^[A-Za-z0-9_]+$/.test(name)) {
500
+ throw new TlsTrustError("tls/bad-key-share",
501
+ "tls.pqc.setKeyShares: '" + name + "' has illegal characters " +
502
+ "(must match [A-Za-z0-9_]+)");
503
+ }
504
+ }
505
+
506
+ function setKeyShares(list) {
507
+ if (!Array.isArray(list) || list.length === 0) {
508
+ throw new TlsTrustError("tls/bad-key-shares",
509
+ "tls.pqc.setKeyShares: must be a non-empty array of group names");
510
+ }
511
+ for (var i = 0; i < list.length; i += 1) _validateKeyShare(list[i]);
512
+ STATE.tlsKeyShares = list.slice();
513
+ return getKeyShares();
514
+ }
515
+
516
+ function getKeyShares() { return STATE.tlsKeyShares.slice(); }
517
+
518
+ function resetKeyShares() {
519
+ STATE.tlsKeyShares = DEFAULT_PQC_KEY_SHARES.slice();
520
+ return getKeyShares();
521
+ }
522
+
523
+ // preferredGroups — RFC 9794 alias surface for the named-group list.
524
+ // `set(list)` overrides the default ordering; `get()` reads the active
525
+ // list; `reset()` restores the framework default. The setKeyShares /
526
+ // getKeyShares / resetKeyShares names are kept as the lower-level
527
+ // alias under `b.network.tls.pqc.*`.
528
+ var preferredGroups = Object.freeze({
529
+ set: setKeyShares,
530
+ get: getKeyShares,
531
+ reset: resetKeyShares,
532
+ DEFAULT: DEFAULT_PQC_KEY_SHARES,
533
+ });
534
+
535
+ var pqc = Object.freeze({
536
+ setKeyShares: setKeyShares,
537
+ getKeyShares: getKeyShares,
538
+ resetKeyShares: resetKeyShares,
539
+ DEFAULT_KEY_SHARES: DEFAULT_PQC_KEY_SHARES,
540
+ });
541
+
542
+ function getCaPems() {
543
+ return STATE.cas.map(function (e) { return e.pem; });
544
+ }
545
+
546
+ // b.network.tls.buildOptions(opts) — assemble a plain options object
547
+ // suitable for tls.connect / new https.Agent(...) / https.request,
548
+ // pre-populated with the framework's PQC group preference + TLSv1.3
549
+ // floor. Operators that build their own outbound transport (custom
550
+ // https.Agent, raw tls.connect for protocol clients other than HTTP)
551
+ // route through this primitive so the same posture lands everywhere.
552
+ //
553
+ // Throws NetworkTlsError("network-tls/bad-tls-options") on invalid
554
+ // shape (config-time entry point — operator catches typo at boot).
555
+ //
556
+ // buildOptions({ ecdhCurve, groups, cert, key, ca, minVersion, sni })
557
+ // returns { minVersion, ecdhCurve, groups, cert, key, ca, servername }
558
+ //
559
+ // `ca` accepts a PEM string OR Buffer OR Array<string|Buffer>; arrays
560
+ // are concatenated with `\n` so Node's TLS layer parses every block.
561
+ function _normalizeCaInput(ca) {
562
+ if (ca === undefined || ca === null) return undefined;
563
+ if (Buffer.isBuffer(ca)) return ca.toString("utf8");
564
+ if (typeof ca === "string") return ca;
565
+ if (!Array.isArray(ca)) {
566
+ throw new NetworkTlsError("network-tls/bad-tls-options",
567
+ "buildOptions: ca must be a PEM string, Buffer, or array thereof");
568
+ }
569
+ var parts = [];
570
+ for (var i = 0; i < ca.length; i += 1) {
571
+ var entry = ca[i];
572
+ if (Buffer.isBuffer(entry)) parts.push(entry.toString("utf8"));
573
+ else if (typeof entry === "string") parts.push(entry);
574
+ else {
575
+ throw new NetworkTlsError("network-tls/bad-tls-options",
576
+ "buildOptions: ca[" + i + "] must be a PEM string or Buffer");
577
+ }
578
+ }
579
+ return parts.join("\n");
580
+ }
581
+
582
+ function buildOptions(opts) {
583
+ opts = opts || {};
584
+ if (typeof opts !== "object" || Array.isArray(opts)) {
585
+ throw new NetworkTlsError("network-tls/bad-tls-options",
586
+ "buildOptions: opts must be a plain object");
587
+ }
588
+ validateOpts(opts,
589
+ ["ecdhCurve", "groups", "cert", "key", "ca", "minVersion", "sni"],
590
+ "network.tls.buildOptions");
591
+ var out = {};
592
+ // TLS-1.3 floor — matches the framework's locked posture in
593
+ // pqc-agent. Operators may pass minVersion: "TLSv1.3" explicitly;
594
+ // anything else fails closed.
595
+ var minV = opts.minVersion === undefined ? "TLSv1.3" : opts.minVersion;
596
+ if (minV !== "TLSv1.3") {
597
+ throw new NetworkTlsError("network-tls/bad-tls-options",
598
+ "buildOptions: minVersion must be 'TLSv1.3' (got " +
599
+ JSON.stringify(opts.minVersion) + ") — framework posture is " +
600
+ "TLS-1.3-only outbound; construct tls.connect opts directly to " +
601
+ "negotiate weaker protocol versions.");
602
+ }
603
+ out.minVersion = minV;
604
+
605
+ // PQC group preference. Caller may narrow (drop a group) but not
606
+ // widen — every requested group must appear in the framework
607
+ // preferred list. Both `groups` (RFC 9794 alias) and `ecdhCurve`
608
+ // (Node TLS option) are accepted; `groups` wins when both supplied.
609
+ var requested = null;
610
+ if (Array.isArray(opts.groups)) {
611
+ requested = opts.groups.slice();
612
+ } else if (typeof opts.groups === "string" && opts.groups.length > 0) {
613
+ requested = opts.groups.split(":");
614
+ } else if (typeof opts.ecdhCurve === "string" && opts.ecdhCurve.length > 0) {
615
+ requested = opts.ecdhCurve.split(":");
616
+ } else if (opts.groups !== undefined || opts.ecdhCurve !== undefined) {
617
+ throw new NetworkTlsError("network-tls/bad-tls-options",
618
+ "buildOptions: groups must be string or string[], ecdhCurve must be string");
619
+ }
620
+ var preferred = STATE.tlsKeyShares.length > 0
621
+ ? STATE.tlsKeyShares.slice()
622
+ : DEFAULT_PQC_KEY_SHARES.slice();
623
+ var resolved;
624
+ if (requested === null) {
625
+ resolved = preferred;
626
+ } else {
627
+ if (requested.length === 0) {
628
+ throw new NetworkTlsError("network-tls/bad-tls-options",
629
+ "buildOptions: groups/ecdhCurve must list at least one named group");
630
+ }
631
+ for (var rgi = 0; rgi < requested.length; rgi += 1) {
632
+ if (typeof requested[rgi] !== "string" || requested[rgi].length === 0) {
633
+ throw new NetworkTlsError("network-tls/bad-tls-options",
634
+ "buildOptions: groups[" + rgi + "] must be a non-empty string");
635
+ }
636
+ if (preferred.indexOf(requested[rgi]) === -1) {
637
+ throw new NetworkTlsError("network-tls/bad-tls-options",
638
+ "buildOptions: group '" + requested[rgi] + "' is not in the " +
639
+ "framework preferred list (" + preferred.join(":") + "); " +
640
+ "construct tls.connect opts directly to negotiate weaker groups.");
641
+ }
642
+ }
643
+ resolved = requested;
644
+ }
645
+ var resolvedStr = resolved.join(":");
646
+ out.ecdhCurve = resolvedStr;
647
+ out.groups = resolvedStr;
648
+
649
+ // cert / key — pass-through with light shape check. Both are
650
+ // typically PEM strings or Buffers; arrays are valid for cert
651
+ // bundles per Node's tls API, so allow array<string|Buffer>.
652
+ if (opts.cert !== undefined) {
653
+ if (!(typeof opts.cert === "string" || Buffer.isBuffer(opts.cert) ||
654
+ Array.isArray(opts.cert))) {
655
+ throw new NetworkTlsError("network-tls/bad-tls-options",
656
+ "buildOptions: cert must be a string, Buffer, or array thereof");
657
+ }
658
+ out.cert = opts.cert;
659
+ }
660
+ if (opts.key !== undefined) {
661
+ if (!(typeof opts.key === "string" || Buffer.isBuffer(opts.key) ||
662
+ Array.isArray(opts.key))) {
663
+ throw new NetworkTlsError("network-tls/bad-tls-options",
664
+ "buildOptions: key must be a string, Buffer, or array thereof");
665
+ }
666
+ out.key = opts.key;
667
+ }
668
+ if (opts.ca !== undefined) out.ca = _normalizeCaInput(opts.ca);
669
+
670
+ // SNI override — Node spells this `servername`.
671
+ if (opts.sni !== undefined) {
672
+ validateOpts.requireNonEmptyString(opts.sni, "buildOptions: sni",
673
+ NetworkTlsError, "network-tls/bad-tls-options");
674
+ out.servername = opts.sni;
675
+ }
676
+ return out;
677
+ }
678
+
679
+ function _emitAuditAdd(metaList, opts) {
680
+ if (opts.audit === false) return;
681
+ var sink;
682
+ try { sink = audit(); } catch (_e) { sink = null; }
683
+ if (!sink || typeof sink.safeEmit !== "function") return;
684
+ for (var i = 0; i < metaList.length; i++) {
685
+ var m = metaList[i];
686
+ try {
687
+ sink.safeEmit({
688
+ action: "network.tls.ca.added",
689
+ outcome: "success",
690
+ metadata: {
691
+ subject: m.subject,
692
+ issuer: m.issuer,
693
+ fingerprint256: m.fingerprint256,
694
+ validFrom: m.validFrom,
695
+ validTo: m.validTo,
696
+ isSelfSigned: m.isSelfSigned,
697
+ label: opts.label || null,
698
+ },
699
+ });
700
+ } catch (_e) { /* audit best-effort — never break the caller */ }
701
+ }
702
+ }
703
+
704
+ function _emitObs(name, fields) {
705
+ try { observability().emit(name, fields || {}); } catch (_e) { /* obs best-effort */ }
706
+ }
707
+
708
+ function _resetForTest() {
709
+ STATE.cas = [];
710
+ STATE.systemTrust = false;
711
+ STATE.baselineFingerprints = null;
712
+ STATE.tlsKeyShares = DEFAULT_PQC_KEY_SHARES.slice();
713
+ }
714
+
715
+ // ---- OCSP / OCSP-stapling wrappers around node:tls ----------------
716
+ //
717
+ // node:tls exposes two OCSP affordances:
718
+ // - tls.connect({ requestOCSP: true }) → emits 'OCSPResponse' event
719
+ // - https.createServer({ ... requestOCSP }) → server-side stapling
720
+ //
721
+ // b.network.tls.ocsp wraps these. The names reflect what the wrapper
722
+ // actually does at this stage:
723
+ //
724
+ // - ocsp.connect(opts) — connect with requestOCSP:true; resolve
725
+ // with { authorized, ocspBytes, peerCert }.
726
+ // - ocsp.requireStapled(opts) — refuse if peer doesn't staple an
727
+ // OCSP response (presence + non-empty
728
+ // byte check). DOES NOT verify the OCSP
729
+ // response signature against the issuer
730
+ // cert — that requires DER OCSPResponse
731
+ // parsing which lands in the next patch
732
+ // alongside the ASN.1 DER helper. The
733
+ // honest name keeps the surface from
734
+ // claiming "good" while only checking
735
+ // stapling.
736
+ //
737
+ // node:tls validates the cert chain itself; OCSP staple validation is
738
+ // the application's job once the response bytes are received.
739
+
740
+ function _connectAndCheckOcsp(opts, requireStapled) {
741
+ return new Promise(function (resolve, reject) {
742
+ var connectOpts = Object.assign({}, opts, { requestOCSP: true });
743
+ var sock;
744
+ try {
745
+ sock = nodeTls.connect(connectOpts);
746
+ } catch (e) {
747
+ reject(new TlsTrustError("tls/connect-failed",
748
+ "tls.connect threw: " + ((e && e.message) || String(e))));
749
+ return;
750
+ }
751
+ var ocspResponseSeen = false;
752
+ sock.on("OCSPResponse", function (response) {
753
+ ocspResponseSeen = true;
754
+ if (!response || response.length === 0) {
755
+ if (requireStapled) {
756
+ sock.destroy();
757
+ reject(new TlsTrustError("tls/ocsp-empty",
758
+ "OCSP response was empty and requireStapled is set"));
759
+ return;
760
+ }
761
+ }
762
+ // Operator can post-process the DER OCSPResponse via the resolved
763
+ // callback; the framework doesn't parse the ASN.1 itself.
764
+ sock.once("secureConnect", function () {
765
+ var rv = {
766
+ authorized: sock.authorized,
767
+ ocspBytes: response || null,
768
+ peerCert: sock.getPeerCertificate(true),
769
+ };
770
+ sock.destroy();
771
+ resolve(rv);
772
+ });
773
+ });
774
+ sock.on("secureConnect", function () {
775
+ // 'OCSPResponse' fires BEFORE 'secureConnect' when the server
776
+ // replied with stapled OCSP. If we got here without seeing an
777
+ // OCSPResponse event AND requireStapled is set, refuse.
778
+ if (!ocspResponseSeen) {
779
+ if (requireStapled) {
780
+ sock.destroy();
781
+ reject(new TlsTrustError("tls/ocsp-not-stapled",
782
+ "TLS peer did not staple an OCSP response and requireStapled is set"));
783
+ return;
784
+ }
785
+ var rv = {
786
+ authorized: sock.authorized,
787
+ ocspBytes: null,
788
+ peerCert: sock.getPeerCertificate(true),
789
+ };
790
+ sock.destroy();
791
+ resolve(rv);
792
+ }
793
+ });
794
+ sock.on("error", function (e) { reject(e); });
795
+ });
796
+ }
797
+
798
+ // ---- OCSP response parser (RFC 6960) ----
799
+ //
800
+ // Decodes a DER OCSPResponse into:
801
+ // {
802
+ // status: "successful" | "malformedRequest" | "internalError" |
803
+ // "tryLater" | "sigRequired" | "unauthorized",
804
+ // basic: { // present when status === "successful"
805
+ // tbsResponseDataDer: Buffer, // the bytes signed
806
+ // signatureAlgorithmOid: string,
807
+ // signature: Buffer,
808
+ // responses: [{ certIdSerialHex, certStatus, thisUpdate, nextUpdate }, ...],
809
+ // }
810
+ // }
811
+ //
812
+ // Cherry-picks the fields the framework needs to verify the response —
813
+ // the signed bytes (tbsResponseData) + the signature + each response
814
+ // entry's status. Out of scope: ResponderID / extensions / nonce
815
+ // validation (operators relying on those wire their own parser).
816
+
817
+ var OID_BASIC_OCSP_RESPONSE = "1.3.6.1.5.5.7.48.1.1";
818
+ // OCSP nonce extension — id-pkix-ocsp-nonce.
819
+ var OID_OCSP_NONCE = "1.3.6.1.5.5.7.48.1.2";
820
+ var OID_SHA1 = "1.3.14.3.2.26"; // allow:raw-byte-literal — SHA-1 algorithm OID arc
821
+ var OID_RSA_SHA256 = "1.2.840.113549.1.1.11";
822
+ var OID_RSA_SHA384 = "1.2.840.113549.1.1.12";
823
+ var OID_RSA_SHA512 = "1.2.840.113549.1.1.13";
824
+ var OID_ECDSA_SHA256 = "1.2.840.10045.4.3.2";
825
+ var OID_ECDSA_SHA384 = "1.2.840.10045.4.3.3";
826
+ var OID_ECDSA_SHA512 = "1.2.840.10045.4.3.4";
827
+
828
+ function _parseTime(node) {
829
+ // Parse UTCTime ("YYMMDDhhmmssZ") or GeneralizedTime
830
+ // ("YYYYMMDDhhmmssZ") into ms-since-epoch.
831
+ var s = node.value.toString("ascii");
832
+ var year, month, day, hour, min, sec;
833
+ if (s.length === 13 && s.charAt(12) === "Z") { // allow:raw-byte-literal — UTCTime length per X.690
834
+ // UTCTime YYMMDDhhmmssZ — 50+ → 19xx, else 20xx (RFC 5280 §4.1.2.5).
835
+ year = parseInt(s.slice(0, 2), 10);
836
+ year += year >= 50 ? 1900 : 2000; // allow:raw-byte-literal allow:raw-time-literal — RFC 5280 century pivot, calendar years
837
+ month = parseInt(s.slice(2, 4), 10);
838
+ day = parseInt(s.slice(4, 6), 10);
839
+ hour = parseInt(s.slice(6, 8), 10); // allow:raw-byte-literal — UTCTime hour-byte offsets
840
+ min = parseInt(s.slice(8, 10), 10); // allow:raw-byte-literal — UTCTime minute-byte offsets
841
+ sec = parseInt(s.slice(10, 12), 10);
842
+ } else if (s.length >= 15 && s.charAt(s.length - 1) === "Z") { // allow:raw-byte-literal — GeneralizedTime length per X.690
843
+ // GeneralizedTime YYYYMMDDhhmmssZ.
844
+ year = parseInt(s.slice(0, 4), 10);
845
+ month = parseInt(s.slice(4, 6), 10);
846
+ day = parseInt(s.slice(6, 8), 10); // allow:raw-byte-literal — GeneralizedTime day-byte offsets
847
+ hour = parseInt(s.slice(8, 10), 10); // allow:raw-byte-literal — GeneralizedTime hour-byte offsets
848
+ min = parseInt(s.slice(10, 12), 10);
849
+ sec = parseInt(s.slice(12, 14), 10);
850
+ } else {
851
+ throw new TlsTrustError("tls/ocsp-bad-time",
852
+ "OCSP time field is not UTCTime or GeneralizedTime: " + JSON.stringify(s));
853
+ }
854
+ return Date.UTC(year, month - 1, day, hour, min, sec);
855
+ }
856
+
857
+ var OCSP_RESPONSE_STATUS = {
858
+ 0: "successful",
859
+ 1: "malformedRequest",
860
+ 2: "internalError",
861
+ 3: "tryLater",
862
+ // 4 reserved
863
+ 5: "sigRequired",
864
+ 6: "unauthorized",
865
+ };
866
+
867
+ function parseOcspResponse(der) {
868
+ if (!Buffer.isBuffer(der) || der.length === 0) {
869
+ throw new TlsTrustError("tls/ocsp-bad-input",
870
+ "parseOcspResponse: expected non-empty Buffer");
871
+ }
872
+ var top = asn1.readNode(der); // OCSPResponse SEQUENCE
873
+ if (top.tag !== asn1.TAG.SEQUENCE) {
874
+ throw new TlsTrustError("tls/ocsp-bad-shape", "OCSPResponse is not a SEQUENCE");
875
+ }
876
+ var topChildren = asn1.readSequence(top.value);
877
+ if (topChildren.length === 0) {
878
+ throw new TlsTrustError("tls/ocsp-bad-shape", "OCSPResponse has no responseStatus");
879
+ }
880
+ var statusInt = asn1.readUnsignedInt(topChildren[0]);
881
+ var status = OCSP_RESPONSE_STATUS[statusInt] || ("unknown:" + statusInt);
882
+ if (status !== "successful") {
883
+ return { status: status };
884
+ }
885
+ // responseBytes [0] EXPLICIT ResponseBytes
886
+ if (topChildren.length < 2) {
887
+ throw new TlsTrustError("tls/ocsp-bad-shape",
888
+ "successful OCSP response missing responseBytes");
889
+ }
890
+ var responseBytes = asn1.unwrapExplicit(topChildren[1], 0); // [0] EXPLICIT
891
+ if (responseBytes.tag !== asn1.TAG.SEQUENCE) {
892
+ throw new TlsTrustError("tls/ocsp-bad-shape", "responseBytes is not a SEQUENCE");
893
+ }
894
+ var rbChildren = asn1.readSequence(responseBytes.value);
895
+ if (rbChildren.length < 2) {
896
+ throw new TlsTrustError("tls/ocsp-bad-shape",
897
+ "responseBytes missing responseType or response");
898
+ }
899
+ var responseTypeOid = asn1.readOid(rbChildren[0]);
900
+ if (responseTypeOid !== OID_BASIC_OCSP_RESPONSE) {
901
+ throw new TlsTrustError("tls/ocsp-unsupported-response-type",
902
+ "OCSP responseType is not id-pkix-ocsp-basic: " + responseTypeOid);
903
+ }
904
+ // The OCTET STRING wraps a DER BasicOCSPResponse.
905
+ var basicDer = asn1.readOctetString(rbChildren[1]);
906
+ var basic = asn1.readNode(basicDer);
907
+ if (basic.tag !== asn1.TAG.SEQUENCE) {
908
+ throw new TlsTrustError("tls/ocsp-bad-shape",
909
+ "BasicOCSPResponse is not a SEQUENCE");
910
+ }
911
+ var basicChildren = asn1.readSequence(basic.value);
912
+ if (basicChildren.length < 3) { // allow:raw-byte-literal — minimum BasicOCSPResponse fields (tbs + alg + sig)
913
+ throw new TlsTrustError("tls/ocsp-bad-shape",
914
+ "BasicOCSPResponse needs tbsResponseData + signatureAlgorithm + signature");
915
+ }
916
+ var tbsNode = basicChildren[0];
917
+ var sigAlgChildren = asn1.readSequence(basicChildren[1].value);
918
+ var sigAlgOid = asn1.readOid(sigAlgChildren[0]);
919
+ var signatureBytes = asn1.readBitString(basicChildren[2]);
920
+
921
+ // Slice the tbsResponseData bytes (header + value) — that's what the
922
+ // signature covers per RFC 6960 §4.2.1. tbsResponseData is the FIRST
923
+ // child of BasicOCSPResponse; its bytes start at basic.valueStart
924
+ // within the raw basicDer buffer (offset 0).
925
+ var basicValueStart = basicDer.length - basic.value.length;
926
+ var tbsDer = basicDer.slice(basicValueStart, basicValueStart + tbsNode.totalLength);
927
+
928
+ // Walk responseData (SEQUENCE) for the per-cert responses.
929
+ var rdChildren = asn1.readSequence(tbsNode.value);
930
+ // Find the SEQUENCE of SingleResponse — it's the LAST SEQUENCE before
931
+ // optional [1] EXPLICIT extensions. Per RFC 6960:
932
+ // ResponseData ::= SEQUENCE {
933
+ // version [0] EXPLICIT Version DEFAULT v1,
934
+ // responderID ResponderID,
935
+ // producedAt GeneralizedTime,
936
+ // responses SEQUENCE OF SingleResponse,
937
+ // responseExtensions [1] EXPLICIT Extensions OPTIONAL
938
+ // }
939
+ // ResponderID is itself a CHOICE (byName [1] / byKey [2]), then a
940
+ // GeneralizedTime, then the responses SEQUENCE-OF.
941
+ var responsesNode = null;
942
+ var responseExtensionsNode = null;
943
+ for (var rdi = rdChildren.length - 1; rdi >= 0; rdi -= 1) {
944
+ var ch = rdChildren[rdi];
945
+ if (ch.tag === asn1.TAG.SEQUENCE && ch.tagClass === asn1.TAG_CLASS.UNIVERSAL) {
946
+ responsesNode = ch;
947
+ break;
948
+ }
949
+ if (ch.tagClass === asn1.TAG_CLASS.CONTEXT_SPECIFIC && ch.tag === 1) { // [1] EXPLICIT responseExtensions
950
+ responseExtensionsNode = asn1.readNode(ch.value, 0);
951
+ }
952
+ }
953
+ if (!responsesNode) {
954
+ throw new TlsTrustError("tls/ocsp-bad-shape",
955
+ "ResponseData missing responses SEQUENCE OF");
956
+ }
957
+ // Walk responseExtensions for the OCSP nonce (RFC 8954 / RFC 6960
958
+ // §4.4.1). Returns the raw nonce bytes when present, or null.
959
+ var responseNonce = null;
960
+ if (responseExtensionsNode && responseExtensionsNode.tag === asn1.TAG.SEQUENCE) {
961
+ var extKids = asn1.readSequence(responseExtensionsNode.value);
962
+ for (var ei = 0; ei < extKids.length; ei += 1) {
963
+ var ext = extKids[ei];
964
+ if (ext.tag !== asn1.TAG.SEQUENCE) continue;
965
+ var extChildren = asn1.readSequence(ext.value);
966
+ if (extChildren.length === 0) continue;
967
+ var extOid;
968
+ try { extOid = asn1.readOid(extChildren[0]); }
969
+ catch (_e3) { continue; }
970
+ if (extOid !== OID_OCSP_NONCE) continue;
971
+ var extnValue = asn1.readOctetString(extChildren[extChildren.length - 1]);
972
+ // RFC 8954 §2.1 — the nonce extension value is the raw bytes
973
+ // wrapped in an OCTET STRING (the value here). RFC 6960 §4.4.1
974
+ // historically wrapped the nonce in another OCTET STRING; tolerate
975
+ // both shapes.
976
+ try {
977
+ var inner = asn1.readNode(extnValue);
978
+ if (inner.tag === asn1.TAG.OCTET_STRING) {
979
+ responseNonce = inner.value;
980
+ } else {
981
+ responseNonce = extnValue;
982
+ }
983
+ } catch (_e4) {
984
+ responseNonce = extnValue;
985
+ }
986
+ break;
987
+ }
988
+ }
989
+ var singleResponses = asn1.readSequence(responsesNode.value);
990
+ var responses = [];
991
+ for (var sri = 0; sri < singleResponses.length; sri += 1) {
992
+ var sr = asn1.readSequence(singleResponses[sri].value);
993
+ if (sr.length < 3) continue; // allow:raw-byte-literal — minimum SingleResponse fields
994
+ // sr[0] = certID SEQUENCE, sr[1] = certStatus CHOICE, sr[2] = thisUpdate.
995
+ var certIdChildren = asn1.readSequence(sr[0].value);
996
+ // certID = SEQUENCE { hashAlgorithm, issuerNameHash, issuerKeyHash, serialNumber }
997
+ var serialHex = certIdChildren.length >= 4
998
+ ? certIdChildren[3].value.toString("hex")
999
+ : null;
1000
+ var certStatus;
1001
+ var statusNode = sr[1];
1002
+ if (statusNode.tagClass === asn1.TAG_CLASS.CONTEXT_SPECIFIC) {
1003
+ certStatus = statusNode.tag === 0 ? "good" :
1004
+ statusNode.tag === 1 ? "revoked" :
1005
+ statusNode.tag === 2 ? "unknown" : "unknown";
1006
+ } else if (statusNode.tag === asn1.TAG.NULL) {
1007
+ certStatus = "good";
1008
+ } else {
1009
+ certStatus = "unknown";
1010
+ }
1011
+ var thisUpdate = _parseTime(sr[2]);
1012
+ var nextUpdate = null;
1013
+ if (sr.length >= 4 && sr[3].tagClass === asn1.TAG_CLASS.CONTEXT_SPECIFIC && sr[3].tag === 0) {
1014
+ nextUpdate = _parseTime(asn1.readNode(sr[3].value, 0));
1015
+ }
1016
+ responses.push({
1017
+ certIdSerialHex: serialHex,
1018
+ certStatus: certStatus,
1019
+ thisUpdate: thisUpdate,
1020
+ nextUpdate: nextUpdate,
1021
+ });
1022
+ }
1023
+
1024
+ return {
1025
+ status: status,
1026
+ basic: {
1027
+ tbsResponseDataDer: tbsDer,
1028
+ signatureAlgorithmOid: sigAlgOid,
1029
+ signature: signatureBytes,
1030
+ responses: responses,
1031
+ nonce: responseNonce,
1032
+ },
1033
+ };
1034
+ }
1035
+
1036
+ function _verifyOcspSignature(parsed, issuerPem) {
1037
+ if (!parsed || !parsed.basic) {
1038
+ throw new TlsTrustError("tls/ocsp-not-successful",
1039
+ "OCSP response status is not 'successful' (got " +
1040
+ (parsed && parsed.status) + ")");
1041
+ }
1042
+ var algOid = parsed.basic.signatureAlgorithmOid;
1043
+ var nodeAlgo = algOid === OID_RSA_SHA256 ? "sha256" :
1044
+ algOid === OID_RSA_SHA384 ? "sha384" :
1045
+ algOid === OID_RSA_SHA512 ? "sha512" :
1046
+ algOid === OID_ECDSA_SHA256 ? "sha256" :
1047
+ algOid === OID_ECDSA_SHA384 ? "sha384" :
1048
+ algOid === OID_ECDSA_SHA512 ? "sha512" : null;
1049
+ if (nodeAlgo === null) {
1050
+ throw new TlsTrustError("tls/ocsp-unsupported-sig-alg",
1051
+ "OCSP signatureAlgorithm OID '" + algOid + "' is not supported by the verifier");
1052
+ }
1053
+ var keyObj;
1054
+ try { keyObj = nodeCrypto.createPublicKey(issuerPem); }
1055
+ catch (e) {
1056
+ throw new TlsTrustError("tls/ocsp-bad-issuer-key",
1057
+ "issuer public key parse failed: " + ((e && e.message) || String(e)));
1058
+ }
1059
+ // ECDSA OCSP signatures use DER-encoded ECDSA-Sig-Value (the ASN.1
1060
+ // shape that node:crypto.verify accepts by default — no dsaEncoding
1061
+ // option needed).
1062
+ var verified;
1063
+ try {
1064
+ verified = nodeCrypto.verify(nodeAlgo, parsed.basic.tbsResponseDataDer, keyObj,
1065
+ parsed.basic.signature);
1066
+ } catch (e) {
1067
+ throw new TlsTrustError("tls/ocsp-verify-threw",
1068
+ "OCSP signature verify threw: " + ((e && e.message) || String(e)));
1069
+ }
1070
+ return verified;
1071
+ }
1072
+
1073
+ // Operator-side OCSP response evaluator. Takes the DER bytes (from
1074
+ // `ocsp.requireStapled` or any other source) plus the issuer cert PEM
1075
+ // and returns a structured outcome:
1076
+ // { ok, status, certStatus, thisUpdate, nextUpdate, signatureValid, errors }
1077
+ function evaluateOcspResponse(ocspDer, opts) {
1078
+ opts = opts || {};
1079
+ var issuerPem = opts.issuerPem;
1080
+ if (!issuerPem) {
1081
+ throw new TlsTrustError("tls/ocsp-missing-issuer",
1082
+ "evaluateOcspResponse requires opts.issuerPem (PEM of the cert that signed the OCSP response — typically the leaf's CA OR a delegated id-kp-OCSPSigning responder cert)");
1083
+ }
1084
+ var parsed;
1085
+ try { parsed = parseOcspResponse(ocspDer); }
1086
+ catch (e) {
1087
+ return { ok: false, status: "parse-error",
1088
+ errors: [(e && e.message) || String(e)] };
1089
+ }
1090
+ if (parsed.status !== "successful") {
1091
+ return { ok: false, status: parsed.status, errors: ["responseStatus=" + parsed.status] };
1092
+ }
1093
+ var sigOk = false;
1094
+ try { sigOk = _verifyOcspSignature(parsed, issuerPem); }
1095
+ catch (e) {
1096
+ return { ok: false, status: parsed.status,
1097
+ signatureValid: false,
1098
+ errors: [(e && e.message) || String(e)] };
1099
+ }
1100
+ if (!sigOk) {
1101
+ return { ok: false, status: parsed.status, signatureValid: false,
1102
+ errors: ["OCSP signature did not verify against the issuer key"] };
1103
+ }
1104
+ // Look up the requested cert serial in the responses; "good" wins.
1105
+ var serial = opts.serialHex || (parsed.basic.responses[0] && parsed.basic.responses[0].certIdSerialHex);
1106
+ var match = null;
1107
+ for (var i = 0; i < parsed.basic.responses.length; i += 1) {
1108
+ var r = parsed.basic.responses[i];
1109
+ if (!serial || r.certIdSerialHex === serial) { match = r; break; }
1110
+ }
1111
+ if (!match) {
1112
+ return { ok: false, status: parsed.status, signatureValid: true,
1113
+ errors: ["OCSP response has no entry for the requested cert serial"] };
1114
+ }
1115
+ // Optional nonce echo verification (RFC 8954 / RFC 6960 §4.4.1).
1116
+ // When opts.expectedNonce is supplied, the response MUST carry an
1117
+ // OCSP nonce extension equal to the expected bytes — defends against
1118
+ // replay of a stale "good" response captured before revocation.
1119
+ var nonceCheck = "n/a";
1120
+ if (opts.expectedNonce !== undefined && opts.expectedNonce !== null) {
1121
+ if (!Buffer.isBuffer(opts.expectedNonce)) {
1122
+ return { ok: false, status: parsed.status, signatureValid: true,
1123
+ errors: ["evaluateOcspResponse: opts.expectedNonce must be a Buffer when supplied"] };
1124
+ }
1125
+ if (!parsed.basic.nonce) {
1126
+ return { ok: false, status: parsed.status, signatureValid: true,
1127
+ errors: ["OCSP response missing nonce extension (expected for replay defense)"] };
1128
+ }
1129
+ // Constant-time compare — module-wide consistency with the
1130
+ // Merkle-root / NTS-cookie / cert-fingerprint paths that already
1131
+ // use timingSafeEqual. Buffer.equals is constant-time on equal-
1132
+ // length inputs but fast-paths on length mismatch; not security-
1133
+ // critical here (the OCSP response is CA-signed and signature
1134
+ // already verified) but matches the project discipline.
1135
+ // (Audit 2026-05-11.)
1136
+ if (!bCrypto.timingSafeEqual(parsed.basic.nonce, opts.expectedNonce)) {
1137
+ return { ok: false, status: parsed.status, signatureValid: true,
1138
+ errors: ["OCSP nonce mismatch — possible replay or wrong responder"] };
1139
+ }
1140
+ nonceCheck = "matched";
1141
+ } else if (parsed.basic.nonce) {
1142
+ nonceCheck = "present-not-checked";
1143
+ }
1144
+ // RFC 6960 §4.2.2.1 — time-window enforcement. A "good" response is
1145
+ // valid only between thisUpdate and nextUpdate (with operator-tunable
1146
+ // skew). Without this check a stapled response is replayable forever:
1147
+ // an attacker captures a pre-revocation "good" reply, the cert later
1148
+ // gets revoked, the attacker keeps presenting the cached "good" and
1149
+ // the framework keeps accepting it. requireGood postures depend on
1150
+ // freshness — reject expired or future-dated responses outright.
1151
+ var clockSkewMs = typeof opts.clockSkewMs === "number" && opts.clockSkewMs >= 0 // allow:numeric-opt-Infinity — operator-supplied skew, default 5 min if absent or invalid
1152
+ ? opts.clockSkewMs : C.TIME.minutes(5);
1153
+ var now = typeof opts.now === "number" ? opts.now : Date.now();
1154
+ var thisUpdateMs = match.thisUpdate ? Date.parse(match.thisUpdate) : NaN;
1155
+ var nextUpdateMs = match.nextUpdate ? Date.parse(match.nextUpdate) : NaN;
1156
+ if (!isFinite(thisUpdateMs)) {
1157
+ return { ok: false, status: parsed.status, signatureValid: true,
1158
+ certStatus: match.certStatus,
1159
+ thisUpdate: match.thisUpdate, nextUpdate: match.nextUpdate,
1160
+ nonce: nonceCheck,
1161
+ errors: ["OCSP response missing thisUpdate (RFC 6960 §4.2.2.1)"] };
1162
+ }
1163
+ if (thisUpdateMs - clockSkewMs > now) {
1164
+ return { ok: false, status: parsed.status, signatureValid: true,
1165
+ certStatus: match.certStatus,
1166
+ thisUpdate: match.thisUpdate, nextUpdate: match.nextUpdate,
1167
+ nonce: nonceCheck,
1168
+ errors: ["OCSP thisUpdate is in the future (RFC 6960 §4.2.2.1 — possible clock skew or response replay)"] };
1169
+ }
1170
+ if (isFinite(nextUpdateMs) && nextUpdateMs + clockSkewMs < now) {
1171
+ return { ok: false, status: parsed.status, signatureValid: true,
1172
+ certStatus: match.certStatus,
1173
+ thisUpdate: match.thisUpdate, nextUpdate: match.nextUpdate,
1174
+ nonce: nonceCheck,
1175
+ errors: ["OCSP response is past nextUpdate (RFC 6960 §4.2.2.1 — stale response, possible replay)"] };
1176
+ }
1177
+ return {
1178
+ ok: match.certStatus === "good",
1179
+ status: parsed.status,
1180
+ certStatus: match.certStatus,
1181
+ thisUpdate: match.thisUpdate,
1182
+ nextUpdate: match.nextUpdate,
1183
+ signatureValid: true,
1184
+ nonce: nonceCheck,
1185
+ errors: match.certStatus === "good" ? [] :
1186
+ ["certStatus=" + match.certStatus],
1187
+ };
1188
+ }
1189
+
1190
+ // ---- OCSPRequest builder (RFC 6960 §4.1 + RFC 8954 nonce ext) ----
1191
+ //
1192
+ // Constructs a DER-encoded OCSPRequest for a single (leafCertDer,
1193
+ // issuerCertDer) pair, optionally with an RFC 8954 nonce extension.
1194
+ // Operators send the returned `requestDer` to the OCSP responder URL
1195
+ // (e.g. via b.httpClient with `Content-Type: application/ocsp-request`)
1196
+ // and pass `nonce` to `ocsp.evaluate(responseDer, { expectedNonce })`
1197
+ // to defend against replay attacks.
1198
+ //
1199
+ // Nonce DEFAULT ON — defense in depth. RFC 6960 §4.4.1 marks nonce
1200
+ // optional and some public responders (notably Let's Encrypt's) ignore
1201
+ // it; operators explicitly targeting those responders opt out via
1202
+ // `opts.nonce: false`. The framework default is RFC 8954 with 16 random
1203
+ // bytes (RFC 8954 §2.1 floor; ceiling 32).
1204
+
1205
+ function _extractIssuerNameDerAndKeyBitString(certDer) {
1206
+ // From the leaf cert's tbsCertificate, pull the issuer Name (DER) +
1207
+ // the issuer's SubjectPublicKey BIT STRING content. For OCSP CertID,
1208
+ // RFC 6960 §4.1.1 specifies hash(issuerName) and hash(issuerKey).
1209
+ // This helper operates on the ISSUER cert (not the leaf): the issuer's
1210
+ // Name and SubjectPublicKey are what get hashed.
1211
+ var top = asn1.readNode(certDer);
1212
+ if (top.tag !== asn1.TAG.SEQUENCE) {
1213
+ throw new TlsTrustError("tls/ocsp-bad-issuer-cert", "issuer cert is not a SEQUENCE");
1214
+ }
1215
+ var children = asn1.readSequence(top.value);
1216
+ if (children.length === 0) {
1217
+ throw new TlsTrustError("tls/ocsp-bad-issuer-cert", "issuer cert has no children");
1218
+ }
1219
+ var tbs = children[0];
1220
+ if (tbs.tag !== asn1.TAG.SEQUENCE) {
1221
+ throw new TlsTrustError("tls/ocsp-bad-issuer-cert", "tbsCertificate is not a SEQUENCE");
1222
+ }
1223
+ var tbsKids = asn1.readSequence(tbs.value);
1224
+ // Skip optional [0] EXPLICIT version, then serialNumber, signature,
1225
+ // then issuer (the cert's own subject in a self-signed CA, or its
1226
+ // issuer field for a sub-CA — we just want THIS cert's subject).
1227
+ var idx = 0;
1228
+ if (tbsKids.length > 0 &&
1229
+ tbsKids[0].tagClass === asn1.TAG_CLASS.CONTEXT_SPECIFIC &&
1230
+ tbsKids[0].tag === 0) { // allow:raw-byte-literal — X.509 [0] EXPLICIT version tag
1231
+ idx = 1;
1232
+ }
1233
+ // After version: serialNumber, signature, issuer, validity, subject, SPKI.
1234
+ var subjectIdx = idx + 4; // allow:raw-byte-literal — X.509 TBSCertificate field count
1235
+ var spkiIdx = idx + 5; // allow:raw-byte-literal — X.509 TBSCertificate field count
1236
+ if (spkiIdx >= tbsKids.length) {
1237
+ throw new TlsTrustError("tls/ocsp-bad-issuer-cert", "issuer cert lacks SPKI field");
1238
+ }
1239
+ var subject = tbsKids[subjectIdx];
1240
+ var spki = tbsKids[spkiIdx];
1241
+ // Within SPKI: SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING }
1242
+ var spkiKids = asn1.readSequence(spki.value);
1243
+ if (spkiKids.length < 2) { // allow:raw-byte-literal — minimum SPKI fields
1244
+ throw new TlsTrustError("tls/ocsp-bad-issuer-cert", "SPKI missing subjectPublicKey BIT STRING");
1245
+ }
1246
+ var keyBytes = asn1.readBitString(spkiKids[1]);
1247
+ return {
1248
+ issuerNameDer: subject.raw, // the DER of the Name SEQUENCE (header + value)
1249
+ issuerKey: keyBytes,
1250
+ };
1251
+ }
1252
+
1253
+ function _extractLeafSerial(leafCertDer) {
1254
+ var top = asn1.readNode(leafCertDer);
1255
+ if (top.tag !== asn1.TAG.SEQUENCE) {
1256
+ throw new TlsTrustError("tls/ocsp-bad-leaf-cert", "leaf cert is not a SEQUENCE");
1257
+ }
1258
+ var children = asn1.readSequence(top.value);
1259
+ var tbs = children[0];
1260
+ var tbsKids = asn1.readSequence(tbs.value);
1261
+ var idx = 0;
1262
+ if (tbsKids.length > 0 &&
1263
+ tbsKids[0].tagClass === asn1.TAG_CLASS.CONTEXT_SPECIFIC &&
1264
+ tbsKids[0].tag === 0) { // allow:raw-byte-literal — X.509 [0] EXPLICIT version tag
1265
+ idx = 1;
1266
+ }
1267
+ // serialNumber is the next field after the optional version.
1268
+ return tbsKids[idx].value;
1269
+ }
1270
+
1271
+ function buildOcspRequest(opts) {
1272
+ opts = opts || {};
1273
+ if (!Buffer.isBuffer(opts.leafCertDer)) {
1274
+ throw new TlsTrustError("tls/ocsp-bad-input",
1275
+ "buildRequest: opts.leafCertDer must be a Buffer (peer cert raw DER)");
1276
+ }
1277
+ if (!Buffer.isBuffer(opts.issuerCertDer)) {
1278
+ throw new TlsTrustError("tls/ocsp-bad-input",
1279
+ "buildRequest: opts.issuerCertDer must be a Buffer (issuer cert raw DER)");
1280
+ }
1281
+ var iss = _extractIssuerNameDerAndKeyBitString(opts.issuerCertDer);
1282
+ var serial = _extractLeafSerial(opts.leafCertDer);
1283
+ // CertID hashes — SHA-1 per RFC 6960 §4.1.1 (the only universally
1284
+ // supported algorithm; SHA-256 in OCSP requests is RFC 6960 §4.3
1285
+ // optional and many responders reject). The hash isn't security-
1286
+ // critical here — it's a name/key lookup, not an integrity check —
1287
+ // but operator compliance dashboards alerting on "anywhere in the
1288
+ // framework that touches SHA-1" need a signal. Emit an audit row
1289
+ // on every OCSP request build so the algorithm choice is visible
1290
+ // in the chain.
1291
+ var nameHash = nodeCrypto.createHash("sha1").update(iss.issuerNameDer).digest();
1292
+ var keyHash = nodeCrypto.createHash("sha1").update(iss.issuerKey).digest();
1293
+ setImmediate(function () {
1294
+ try {
1295
+ var auditMod = require("./audit"); // allow:inline-require — circular-load defense (audit imports network-tls)
1296
+ auditMod.safeEmit({
1297
+ action: "network.tls.ocsp.certid_built",
1298
+ outcome: "success",
1299
+ metadata: { hashAlgorithm: "sha1", note: "RFC 6960 §4.1.1 — non-security-critical lookup hash" },
1300
+ });
1301
+ } catch (_e) { /* drop-silent */ }
1302
+ });
1303
+ // hashAlgorithm AlgorithmIdentifier ::= SEQUENCE { algorithm OID, NULL }
1304
+ var algId = asn1.writeSequence([asn1.writeOid(OID_SHA1), asn1.writeNull()]);
1305
+ var certId = asn1.writeSequence([
1306
+ algId,
1307
+ asn1.writeOctetString(nameHash),
1308
+ asn1.writeOctetString(keyHash),
1309
+ asn1.writeInteger(serial),
1310
+ ]);
1311
+ var requestNode = asn1.writeSequence([certId]);
1312
+ var requestList = asn1.writeSequence([requestNode]);
1313
+ var nonceBytes = null;
1314
+ var tbsChildren = [requestList];
1315
+ // Default ON per the framework security-defaults-on rule. Operators
1316
+ // talking to a responder that ignores nonces opt out via nonce: false.
1317
+ var includeNonce = opts.nonce !== false;
1318
+ if (includeNonce) {
1319
+ var nonceLen = typeof opts.nonceLen === "number" ? opts.nonceLen : 16; // allow:raw-byte-literal — RFC 8954 §2.1 nonce length floor
1320
+ if (nonceLen < 1 || nonceLen > 32) { // allow:raw-byte-literal — RFC 8954 §2.1 nonce length ceiling
1321
+ throw new TlsTrustError("tls/ocsp-bad-nonce-len",
1322
+ "nonce length out of RFC 8954 range (1..32)");
1323
+ }
1324
+ nonceBytes = nodeCrypto.randomBytes(nonceLen);
1325
+ // Extension ::= SEQUENCE { extnID OID, critical BOOL DEFAULT FALSE, extnValue OCTET STRING }
1326
+ // For nonce, extnValue is OCTET STRING wrapping the raw nonce bytes (RFC 8954 §2.1 — outer OCTET STRING only).
1327
+ var nonceExt = asn1.writeSequence([
1328
+ asn1.writeOid(OID_OCSP_NONCE),
1329
+ asn1.writeOctetString(nonceBytes),
1330
+ ]);
1331
+ var extensions = asn1.writeSequence([nonceExt]);
1332
+ tbsChildren.push(asn1.writeContextExplicit(2, extensions)); // [2] EXPLICIT requestExtensions
1333
+ }
1334
+ var tbs = asn1.writeSequence(tbsChildren);
1335
+ var requestDer = asn1.writeSequence([tbs]);
1336
+ return { requestDer: requestDer, nonce: nonceBytes };
1337
+ }
1338
+
1339
+ var ocsp = Object.freeze({
1340
+ // Connect with OCSP requested. Returns { authorized, ocspBytes,
1341
+ // peerCert }. requireStapled: true makes empty / not-stapled responses
1342
+ // refuse instead of resolve. NOTE: requireStapled does NOT verify the
1343
+ // OCSP response signature — pair it with evaluateOcspResponse(bytes,
1344
+ // { issuerPem }) for full verification, OR use requireGood below.
1345
+ connect: function (opts) {
1346
+ return _connectAndCheckOcsp(opts || {}, false);
1347
+ },
1348
+ requireStapled: function (opts) {
1349
+ return _connectAndCheckOcsp(opts || {}, true);
1350
+ },
1351
+ // requireGood: connect + parse + verify signature + check certStatus.
1352
+ // Operator passes opts.issuerPem (the cert that signed the OCSP
1353
+ // response — typically the leaf's CA OR a delegated OCSP responder
1354
+ // cert). Throws TlsTrustError on any failure (no-staple, parse error,
1355
+ // signature mismatch, certStatus=revoked/unknown).
1356
+ requireGood: async function (opts) {
1357
+ opts = opts || {};
1358
+ if (!opts.issuerPem) {
1359
+ throw new TlsTrustError("tls/ocsp-missing-issuer",
1360
+ "ocsp.requireGood requires opts.issuerPem (PEM of the OCSP-signing cert)");
1361
+ }
1362
+ var rv = await _connectAndCheckOcsp(opts, true);
1363
+ if (!rv.ocspBytes || rv.ocspBytes.length === 0) {
1364
+ throw new TlsTrustError("tls/ocsp-empty",
1365
+ "OCSP response was empty");
1366
+ }
1367
+ var evald = evaluateOcspResponse(rv.ocspBytes, {
1368
+ issuerPem: opts.issuerPem,
1369
+ serialHex: opts.serialHex || null,
1370
+ });
1371
+ if (!evald.ok) {
1372
+ throw new TlsTrustError("tls/ocsp-not-good",
1373
+ "OCSP evaluation failed: " + evald.errors.join("; "));
1374
+ }
1375
+ return Object.assign({}, rv, { ocspEvaluation: evald });
1376
+ },
1377
+ parseResponse: parseOcspResponse,
1378
+ evaluate: evaluateOcspResponse,
1379
+ // buildRequest — construct a DER-encoded OCSPRequest for a single
1380
+ // (leafCertDer, issuerCertDer) pair. RFC 8954 nonce extension is ON
1381
+ // by default (16 random bytes; opts.nonceLen overrides within RFC
1382
+ // 8954's 1..32 range; opts.nonce: false opts out for responders that
1383
+ // ignore nonces). Returns { requestDer, nonce }; pass `nonce` to
1384
+ // evaluate({ expectedNonce }).
1385
+ buildRequest: buildOcspRequest,
1386
+ // inspectMustStaple — read the RFC 7633 TLS Feature extension on a
1387
+ // peer cert. Returns { mustStaple, features }. mustStaple === true
1388
+ // when status_request (5) is in the feature list; the cert is then
1389
+ // contractually required to ship an OCSP staple on every connection.
1390
+ inspectMustStaple: function (rawDer) {
1391
+ if (!Buffer.isBuffer(rawDer)) {
1392
+ throw new TlsTrustError("tls/ocsp-bad-input",
1393
+ "ocsp.inspectMustStaple: rawDer must be a Buffer (cert.raw)");
1394
+ }
1395
+ return _extractTlsFeatureExtensionFromCert(rawDer);
1396
+ },
1397
+ // requireMustStaple(peerCert, opts) — operator predicate. Refuses
1398
+ // when the cert advertises must-staple but no OCSP staple was
1399
+ // delivered (opts.ocspBytes empty/missing). When the cert does NOT
1400
+ // advertise must-staple, the predicate returns null (operator opted
1401
+ // in by setting opts.enforceUnconditional to also require staples
1402
+ // on certs that don't carry the extension).
1403
+ requireMustStaple: function (opts) {
1404
+ opts = opts || {};
1405
+ var enforceUnconditional = opts.enforceUnconditional === true;
1406
+ return function (peerCert, ctx) {
1407
+ if (!peerCert || !peerCert.raw) {
1408
+ return new TlsTrustError("tls/ocsp-no-cert",
1409
+ "requireMustStaple: peer cert.raw missing");
1410
+ }
1411
+ var feat = _extractTlsFeatureExtensionFromCert(peerCert.raw);
1412
+ var stapled = ctx && Buffer.isBuffer(ctx.ocspBytes) && ctx.ocspBytes.length > 0;
1413
+ if (feat.mustStaple && !stapled) {
1414
+ return new TlsTrustError("tls/ocsp-must-staple-violated",
1415
+ "cert advertises must-staple (RFC 7633) but no OCSP staple was delivered");
1416
+ }
1417
+ if (!feat.mustStaple && enforceUnconditional && !stapled) {
1418
+ return new TlsTrustError("tls/ocsp-staple-required",
1419
+ "operator policy requires OCSP staple but server did not provide one");
1420
+ }
1421
+ return null;
1422
+ };
1423
+ },
1424
+ });
1425
+
1426
+ // ---- Certificate Transparency (RFC 6962 + RFC 9162) SCT verifier --
1427
+ //
1428
+ // CT requires every TLS server certificate to carry at least 2 Signed
1429
+ // Certificate Timestamps (SCTs) from approved logs. Modern browsers
1430
+ // (Chrome / Safari) refuse certificates without sufficient SCTs.
1431
+ //
1432
+ // node:tls surfaces SCTs via TLSSocket.getPeerX509Certificate() →
1433
+ // X509Certificate.raw (the DER cert). The SCTs sit inside the cert as
1434
+ // the OCSP-aware extension OID 1.3.6.1.4.1.11129.2.4.2.
1435
+ //
1436
+ // b.network.tls.ct.verify(cert, opts) checks that the cert has at
1437
+ // least `minScts` SCTs and that each SCT references a log in
1438
+ // `approvedLogs`. Full SCT-signature verification against the log's
1439
+ // pubkey is OUT of scope for this patch — that requires log-pubkey
1440
+ // distribution + ASN.1 SCT parsing. The framework provides the
1441
+ // SCT-presence + log-id check; signature verification is a follow-up
1442
+ // when the ASN.1 dependency lands.
1443
+
1444
+ // SCT extension OID per RFC 6962 §3.3.
1445
+ var OID_CT_SCT_LIST = "1.3.6.1.4.1.11129.2.4.2";
1446
+
1447
+ // Walk a DER X.509 cert and locate the SCT extension's OCTET STRING
1448
+ // content. Returns { sctListRaw } or { sctListRaw: null } when no SCT
1449
+ // extension is present.
1450
+ function _extractSctExtensionFromCert(certDer) {
1451
+ // Tolerant of malformed cert buffers — return null sctListRaw when
1452
+ // the ASN.1 walk fails. Callers (parseScts / verifyScts) treat that
1453
+ // as "no SCT extension" rather than throwing on broken input.
1454
+ var top;
1455
+ try { top = asn1.readNode(certDer); }
1456
+ catch (_e) { return { sctListRaw: null }; }
1457
+ if (top.tag !== asn1.TAG.SEQUENCE) return { sctListRaw: null };
1458
+ var children;
1459
+ try { children = asn1.readSequence(top.value); }
1460
+ catch (_e) { return { sctListRaw: null }; }
1461
+ if (children.length === 0) return { sctListRaw: null };
1462
+ // Cert ::= SEQUENCE { tbsCertificate, signatureAlgorithm, signature }
1463
+ var tbs = children[0];
1464
+ if (tbs.tag !== asn1.TAG.SEQUENCE) return { sctListRaw: null };
1465
+ // tbsCertificate ::= SEQUENCE { ..., extensions [3] EXPLICIT ... }
1466
+ var tbsChildren;
1467
+ try { tbsChildren = asn1.readSequence(tbs.value); }
1468
+ catch (_e) { return { sctListRaw: null }; }
1469
+ var extensionsNode = null;
1470
+ for (var i = 0; i < tbsChildren.length; i += 1) {
1471
+ var ch = tbsChildren[i];
1472
+ if (ch.tagClass === asn1.TAG_CLASS.CONTEXT_SPECIFIC && ch.tag === 3) { // allow:raw-byte-literal — X.509 [3] EXPLICIT extensions tag
1473
+ extensionsNode = asn1.readNode(ch.value, 0);
1474
+ break;
1475
+ }
1476
+ }
1477
+ if (!extensionsNode || extensionsNode.tag !== asn1.TAG.SEQUENCE) {
1478
+ return { sctListRaw: null };
1479
+ }
1480
+ var extensions = asn1.readSequence(extensionsNode.value);
1481
+ for (var e = 0; e < extensions.length; e += 1) {
1482
+ var ext = extensions[e]; // Extension ::= SEQUENCE { extnID OID, critical BOOL OPTIONAL, extnValue OCTET STRING }
1483
+ if (ext.tag !== asn1.TAG.SEQUENCE) continue;
1484
+ var extChildren = asn1.readSequence(ext.value);
1485
+ if (extChildren.length === 0) continue;
1486
+ var extOid = asn1.readOid(extChildren[0]);
1487
+ if (extOid !== OID_CT_SCT_LIST) continue;
1488
+ // The last child is the OCTET STRING extnValue. Per RFC 6962 §3.3
1489
+ // that OCTET STRING wraps a SECOND OCTET STRING which contains the
1490
+ // raw SignedCertificateTimestampList (TLS-encoded).
1491
+ var extnValueOuter = asn1.readOctetString(extChildren[extChildren.length - 1]);
1492
+ var inner = asn1.readNode(extnValueOuter);
1493
+ if (inner.tag !== asn1.TAG.OCTET_STRING) {
1494
+ throw new TlsTrustError("tls/ct-bad-extension",
1495
+ "SCT extension extnValue does not wrap a second OCTET STRING");
1496
+ }
1497
+ return { sctListRaw: inner.value };
1498
+ }
1499
+ return { sctListRaw: null };
1500
+ }
1501
+
1502
+ // TLS Feature extension OID per RFC 7633 §6. The extension value is
1503
+ // SEQUENCE OF INTEGER; the integer 5 == status_request == "must-staple".
1504
+ var OID_TLS_FEATURE = "1.3.6.1.5.5.7.1.24";
1505
+ var TLS_FEATURE_STATUS_REQUEST = 5;
1506
+
1507
+ // Walk a DER X.509 cert and return the TLS Feature extension's
1508
+ // integer list. Returns { mustStaple, features }. Tolerant of
1509
+ // malformed cert input — mirrors _extractSctExtensionFromCert's
1510
+ // try/catch tolerance.
1511
+ function _extractTlsFeatureExtensionFromCert(certDer) {
1512
+ var none = { mustStaple: false, features: [] };
1513
+ var top;
1514
+ try { top = asn1.readNode(certDer); }
1515
+ catch (_e) { return none; }
1516
+ if (top.tag !== asn1.TAG.SEQUENCE) return none;
1517
+ var children;
1518
+ try { children = asn1.readSequence(top.value); }
1519
+ catch (_e) { return none; }
1520
+ if (children.length === 0) return none;
1521
+ var tbs = children[0];
1522
+ if (tbs.tag !== asn1.TAG.SEQUENCE) return none;
1523
+ var tbsChildren;
1524
+ try { tbsChildren = asn1.readSequence(tbs.value); }
1525
+ catch (_e) { return none; }
1526
+ var extensionsNode = null;
1527
+ for (var i = 0; i < tbsChildren.length; i += 1) {
1528
+ var ch = tbsChildren[i];
1529
+ if (ch.tagClass === asn1.TAG_CLASS.CONTEXT_SPECIFIC && ch.tag === 3) { // allow:raw-byte-literal — X.509 [3] EXPLICIT extensions tag
1530
+ extensionsNode = asn1.readNode(ch.value, 0);
1531
+ break;
1532
+ }
1533
+ }
1534
+ if (!extensionsNode || extensionsNode.tag !== asn1.TAG.SEQUENCE) return none;
1535
+ var extensions = asn1.readSequence(extensionsNode.value);
1536
+ for (var e = 0; e < extensions.length; e += 1) {
1537
+ var ext = extensions[e];
1538
+ if (ext.tag !== asn1.TAG.SEQUENCE) continue;
1539
+ var extChildren = asn1.readSequence(ext.value);
1540
+ if (extChildren.length === 0) continue;
1541
+ var extOid;
1542
+ try { extOid = asn1.readOid(extChildren[0]); }
1543
+ catch (_e2) { continue; }
1544
+ if (extOid !== OID_TLS_FEATURE) continue;
1545
+ var extnValue = asn1.readOctetString(extChildren[extChildren.length - 1]);
1546
+ // extnValue wraps SEQUENCE OF INTEGER.
1547
+ var seq;
1548
+ try { seq = asn1.readNode(extnValue); }
1549
+ catch (_e3) { return none; }
1550
+ if (seq.tag !== asn1.TAG.SEQUENCE) return none;
1551
+ var feats = asn1.readSequence(seq.value);
1552
+ var ints = [];
1553
+ var mustStaple = false;
1554
+ for (var f = 0; f < feats.length; f += 1) {
1555
+ try {
1556
+ var n = asn1.readUnsignedInt(feats[f]);
1557
+ ints.push(n);
1558
+ if (n === TLS_FEATURE_STATUS_REQUEST) mustStaple = true;
1559
+ } catch (_e4) { /* ignore non-integer entries */ }
1560
+ }
1561
+ return { mustStaple: mustStaple, features: ints };
1562
+ }
1563
+ return none;
1564
+ }
1565
+
1566
+ // Parse the TLS-encoded SignedCertificateTimestampList (RFC 6962 §3.3).
1567
+ // Format: 2-byte length + concatenation of individual SCTs, each
1568
+ // itself prefixed by a 2-byte length.
1569
+ function _parseSctList(sctListRaw) {
1570
+ if (!Buffer.isBuffer(sctListRaw) || sctListRaw.length < 2) { // allow:raw-byte-literal — outer 2-byte length prefix
1571
+ throw new TlsTrustError("tls/ct-bad-list",
1572
+ "SCT list shorter than the outer length prefix");
1573
+ }
1574
+ var totalLen = sctListRaw.readUInt16BE(0);
1575
+ if (totalLen + 2 !== sctListRaw.length) { // allow:raw-byte-literal — outer length prefix
1576
+ throw new TlsTrustError("tls/ct-bad-list",
1577
+ "SCT list outer length " + totalLen + " does not match buffer " +
1578
+ (sctListRaw.length - 2));
1579
+ }
1580
+ var pos = 2; // allow:raw-byte-literal — past the outer prefix
1581
+ var scts = [];
1582
+ while (pos < sctListRaw.length) {
1583
+ var sctLen = sctListRaw.readUInt16BE(pos);
1584
+ pos += 2;
1585
+ if (pos + sctLen > sctListRaw.length) {
1586
+ throw new TlsTrustError("tls/ct-bad-list",
1587
+ "SCT[" + scts.length + "] declared length " + sctLen +
1588
+ " extends past the list buffer");
1589
+ }
1590
+ var sctBytes = sctListRaw.slice(pos, pos + sctLen);
1591
+ scts.push(_parseSct(sctBytes));
1592
+ pos += sctLen;
1593
+ }
1594
+ return scts;
1595
+ }
1596
+
1597
+ // Per RFC 6962 §3.2 — a single SCT:
1598
+ // sct_version (1 byte) — 0 = v1
1599
+ // id (LogID) (32 bytes) — SHA-256 of log's pubkey
1600
+ // timestamp (8 bytes) — uint64 ms since epoch
1601
+ // ct_extensions (2-byte len + N) — usually empty
1602
+ // signature DigitallySigned (hash + sig algo + 2-byte len + N)
1603
+ function _parseSct(sctBuf) {
1604
+ if (sctBuf.length < 1 + 32 + 8 + 2 + 4) { // allow:raw-byte-literal — minimum SCT v1 byte total
1605
+ throw new TlsTrustError("tls/ct-sct-too-short",
1606
+ "SCT is shorter than the minimum v1 layout (" + sctBuf.length + " bytes)");
1607
+ }
1608
+ var version = sctBuf[0];
1609
+ if (version !== 0) {
1610
+ throw new TlsTrustError("tls/ct-sct-bad-version",
1611
+ "SCT version is not 0 (v1): got " + version);
1612
+ }
1613
+ var logId = sctBuf.slice(1, 1 + 32); // allow:raw-byte-literal — RFC 6962 32-byte LogID
1614
+ var timestamp = Number(sctBuf.readBigUInt64BE(1 + 32)); // allow:raw-byte-literal — past LogID
1615
+ var extLen = sctBuf.readUInt16BE(1 + 32 + 8); // allow:raw-byte-literal — past LogID + timestamp
1616
+ var pos = 1 + 32 + 8 + 2; // allow:raw-byte-literal — past extLen field
1617
+ var extensions = sctBuf.slice(pos, pos + extLen);
1618
+ pos += extLen;
1619
+ if (pos + 4 > sctBuf.length) { // allow:raw-byte-literal — DigitallySigned header (hash + alg + len)
1620
+ throw new TlsTrustError("tls/ct-sct-truncated",
1621
+ "SCT truncated before DigitallySigned");
1622
+ }
1623
+ var hashAlgo = sctBuf[pos];
1624
+ var sigAlgo = sctBuf[pos + 1];
1625
+ pos += 2; // allow:raw-byte-literal — past hash+alg pair
1626
+ var sigLen = sctBuf.readUInt16BE(pos);
1627
+ pos += 2; // allow:raw-byte-literal — past sig length
1628
+ if (pos + sigLen !== sctBuf.length) {
1629
+ throw new TlsTrustError("tls/ct-sct-truncated",
1630
+ "SCT signature length " + sigLen + " does not match remaining bytes " +
1631
+ (sctBuf.length - pos));
1632
+ }
1633
+ var signature = sctBuf.slice(pos, pos + sigLen);
1634
+ return {
1635
+ version: version,
1636
+ logId: logId,
1637
+ logIdHex: logId.toString("hex"),
1638
+ timestamp: timestamp,
1639
+ extensions: extensions,
1640
+ hashAlgo: hashAlgo, // RFC 5246 HashAlgorithm enum (4=sha256, 5=sha384, 6=sha512)
1641
+ sigAlgo: sigAlgo, // RFC 5246 SignatureAlgorithm enum (1=rsa, 3=ecdsa)
1642
+ signature: signature,
1643
+ };
1644
+ }
1645
+
1646
+ // Build the canonical signed-entry per RFC 6962 §3.2 for X.509
1647
+ // pre-cert-free chains (issued cert path):
1648
+ // sct_version (1) || signature_type (1=certificate_timestamp) ||
1649
+ // timestamp (8) || entry_type (0=x509_entry) ||
1650
+ // signed_entry (3-byte length || ASN.1 cert without SCT extension) ||
1651
+ // ct_extensions (2-byte length || N)
1652
+ function _buildSctSignedEntry(certWithoutSctDer, sct) {
1653
+ var head = Buffer.alloc(1 + 1 + 8 + 2); // allow:raw-byte-literal — fixed-shape header bytes
1654
+ head[0] = sct.version;
1655
+ head[1] = 0; // signature_type = certificate_timestamp
1656
+ head.writeBigUInt64BE(BigInt(sct.timestamp), 2); // allow:raw-byte-literal — past version+sig-type
1657
+ head.writeUInt16BE(0, 10); // allow:raw-byte-literal — entry_type = x509_entry (2 bytes; high byte = 0, low byte = 0)
1658
+ // signed_entry: 3-byte length prefix + cert DER.
1659
+ var lenBytes = Buffer.alloc(3); // allow:raw-byte-literal — RFC 6962 24-bit length prefix
1660
+ lenBytes[0] = (certWithoutSctDer.length >> 16) & 0xff; // allow:raw-byte-literal — base-256 length high byte
1661
+ lenBytes[1] = (certWithoutSctDer.length >> 8) & 0xff; // allow:raw-byte-literal — base-256 length mid byte
1662
+ lenBytes[2] = certWithoutSctDer.length & 0xff; // allow:raw-byte-literal — base-256 length low byte
1663
+ // ct_extensions: 2-byte length + bytes.
1664
+ var extHead = Buffer.alloc(2); // allow:raw-byte-literal — RFC 6962 2-byte ct_extensions length prefix
1665
+ extHead.writeUInt16BE(sct.extensions.length, 0);
1666
+ return Buffer.concat([head, lenBytes, certWithoutSctDer, extHead, sct.extensions]);
1667
+ }
1668
+
1669
+ // Strip the SCT extension from a DER cert + return the rebuilt cert
1670
+ // bytes for SCT signing per RFC 6962 §3.2. The strip is byte-precise:
1671
+ // walk the TBSCertificate extensions list, drop the SCT extension,
1672
+ // and re-encode just enough of the chain to reproduce the original
1673
+ // shape minus that one extension. This is non-trivial because the
1674
+ // tbsCertificate length, certificate length, and signature-bytes
1675
+ // boundaries all shift.
1676
+ //
1677
+ // Simpler: rebuild only the tbsCertificate extensions SEQUENCE without
1678
+ // the SCT entry, recompute lengths above it, and replace the cert's
1679
+ // SignedCertificate (BIT STRING) with the original's signature too —
1680
+ // but that's incorrect since the original signature was computed over
1681
+ // the WITH-SCT TBS. The CT log signed an entry built from the
1682
+ // without-SCT pre-issuance shape, NOT the issued cert's tbs.
1683
+ //
1684
+ // Per RFC 6962 §3.1, log servers receive a "TBSCertificate" minus the
1685
+ // SCT extension from the CA. The signed_entry the framework
1686
+ // reconstructs is that pre-extension TBSCertificate. We compute it by
1687
+ // removing the SCT extension at the byte level and rebuilding all
1688
+ // outer length prefixes.
1689
+ function _stripSctExtensionFromCert(certDer) {
1690
+ var top = asn1.readNode(certDer);
1691
+ if (top.tag !== asn1.TAG.SEQUENCE) {
1692
+ throw new TlsTrustError("tls/ct-bad-cert", "Certificate is not a SEQUENCE");
1693
+ }
1694
+ var topChildren = asn1.readSequence(top.value);
1695
+ var tbs = topChildren[0];
1696
+ if (tbs.tag !== asn1.TAG.SEQUENCE) {
1697
+ throw new TlsTrustError("tls/ct-bad-cert", "tbsCertificate is not a SEQUENCE");
1698
+ }
1699
+ // Walk tbsCertificate to find the [3] EXPLICIT extensions wrapper.
1700
+ var tbsChildren = asn1.readSequence(tbs.value);
1701
+ var newTbsChildrenBytes = [];
1702
+ var foundExtensions = false;
1703
+ for (var i = 0; i < tbsChildren.length; i += 1) {
1704
+ var ch = tbsChildren[i];
1705
+ if (ch.tagClass === asn1.TAG_CLASS.CONTEXT_SPECIFIC && ch.tag === 3) { // allow:raw-byte-literal — [3] EXPLICIT extensions tag
1706
+ foundExtensions = true;
1707
+ // Inner SEQUENCE OF Extensions.
1708
+ var inner = asn1.readNode(ch.value, 0);
1709
+ var extList = asn1.readSequence(inner.value);
1710
+ var keptExtBytes = [];
1711
+ for (var j = 0; j < extList.length; j += 1) {
1712
+ var ext = extList[j];
1713
+ var extBytes = ext.value;
1714
+ var extDescChildren = asn1.readSequence(ext.value);
1715
+ if (extDescChildren.length > 0) {
1716
+ try {
1717
+ var oid = asn1.readOid(extDescChildren[0]);
1718
+ if (oid === OID_CT_SCT_LIST) continue; // drop the SCT extension
1719
+ } catch (_e) { /* not an OID — keep the extension as-is */ }
1720
+ }
1721
+ // Re-encode this extension verbatim (we have the original bytes).
1722
+ var origExt = certDer.slice(0, 0); // placeholder; we rebuild from the parsed node below
1723
+ void origExt;
1724
+ keptExtBytes.push(_encodeAsn1(asn1.TAG.SEQUENCE, true, extBytes));
1725
+ void extBytes;
1726
+ }
1727
+ var newExtSeq = _encodeAsn1(asn1.TAG.SEQUENCE, true, Buffer.concat(keptExtBytes));
1728
+ var newExplicit3 = _encodeContextExplicit(3, newExtSeq);
1729
+ newTbsChildrenBytes.push(newExplicit3);
1730
+ } else {
1731
+ // Re-encode the original child verbatim by slicing its bytes from
1732
+ // the parent's value buffer.
1733
+ var childDer = _encodeAsn1FromNode(ch);
1734
+ newTbsChildrenBytes.push(childDer);
1735
+ }
1736
+ }
1737
+ if (!foundExtensions) {
1738
+ // Cert has no extensions at all — caller's SCT lookup would have
1739
+ // returned no SCT bytes, so this path shouldn't run. Surface anyway.
1740
+ throw new TlsTrustError("tls/ct-no-extensions",
1741
+ "cert has no extensions to strip from");
1742
+ }
1743
+ var newTbsValue = Buffer.concat(newTbsChildrenBytes);
1744
+ var newTbs = _encodeAsn1(asn1.TAG.SEQUENCE, true, newTbsValue);
1745
+ return newTbs;
1746
+ }
1747
+
1748
+ // Minimal DER encoder helpers — enough to rebuild a TBS without the
1749
+ // SCT extension. Tag class is universal for SEQUENCE; constructed
1750
+ // flag wired explicitly.
1751
+ function _encodeLength(len) {
1752
+ if (len < 0x80) return Buffer.from([len]); // allow:raw-byte-literal — DER short-form length threshold
1753
+ var tmp = [];
1754
+ var n = len;
1755
+ while (n > 0) {
1756
+ tmp.unshift(n & 0xff); // allow:raw-byte-literal — base-256 byte
1757
+ n = n >>> 8; // allow:raw-byte-literal — byte shift
1758
+ }
1759
+ return Buffer.concat([Buffer.from([0x80 | tmp.length]), Buffer.from(tmp)]); // allow:raw-byte-literal — DER long-form length flag
1760
+ }
1761
+ function _encodeAsn1(tag, constructed, value) {
1762
+ var tagByte = (constructed ? 0x20 : 0x00) | tag; // allow:raw-byte-literal — DER constructed bit + universal tag
1763
+ return Buffer.concat([Buffer.from([tagByte]), _encodeLength(value.length), value]);
1764
+ }
1765
+ function _encodeContextExplicit(num, value) {
1766
+ // Context-specific class (10) + constructed (20) | tag.
1767
+ var tagByte = 0xa0 | num; // allow:raw-byte-literal — DER context-specific + constructed
1768
+ return Buffer.concat([Buffer.from([tagByte]), _encodeLength(value.length), value]);
1769
+ }
1770
+ function _encodeAsn1FromNode(node) {
1771
+ // Re-encode a parsed node verbatim by replaying the tag + length +
1772
+ // value. Universal-class shortcut: if class is universal, set the
1773
+ // tag byte from the universal table; if constructed, set the bit.
1774
+ // Context-specific / application / private classes get their bytes
1775
+ // restored directly. This works for the simple shapes we walk.
1776
+ var tagByte;
1777
+ if (node.tagClass === asn1.TAG_CLASS.UNIVERSAL) {
1778
+ tagByte = (node.constructed ? 0x20 : 0x00) | (node.tag & 0x1f); // allow:raw-byte-literal — DER constructed bit + universal tag
1779
+ } else {
1780
+ var classBits = (node.tagClass & 0x03) << 6; // allow:raw-byte-literal — DER tag-class bits
1781
+ tagByte = classBits | (node.constructed ? 0x20 : 0x00) | (node.tag & 0x1f); // allow:raw-byte-literal — DER constructed bit + low-tag
1782
+ }
1783
+ return Buffer.concat([Buffer.from([tagByte]), _encodeLength(node.value.length), node.value]);
1784
+ }
1785
+
1786
+ // SCT signature verification per RFC 6962 §3.2. opts.logKeys maps
1787
+ // log_id (hex) → PEM public key. Operators populate from the Chrome
1788
+ // CT log list (https://www.gstatic.com/ct/log_list/v3/log_list.json
1789
+ // or equivalent) — log keys rotate, so the framework does NOT bake
1790
+ // them in; that drift is the operator's to manage.
1791
+ function verifyScts(certDer, opts) {
1792
+ opts = opts || {};
1793
+ if (!Buffer.isBuffer(certDer)) {
1794
+ throw new TlsTrustError("tls/ct-bad-input",
1795
+ "verifyScts: certDer must be a Buffer");
1796
+ }
1797
+ var logKeys = opts.logKeys || {};
1798
+ var minScts = typeof opts.minScts === "number" ? opts.minScts : 2; // allow:raw-byte-literal — Chrome CT policy min-2-SCTs
1799
+ var ext = _extractSctExtensionFromCert(certDer);
1800
+ if (!ext.sctListRaw) {
1801
+ return { ok: false, reason: "no-sct-extension", scts: [] };
1802
+ }
1803
+ var scts;
1804
+ try { scts = _parseSctList(ext.sctListRaw); }
1805
+ catch (e) {
1806
+ return { ok: false, reason: "parse-error",
1807
+ error: (e && e.message) || String(e), scts: [] };
1808
+ }
1809
+ // Strip the SCT extension to compute the signed-entry per §3.2.
1810
+ var stripped;
1811
+ try { stripped = _stripSctExtensionFromCert(certDer); }
1812
+ catch (e) {
1813
+ return { ok: false, reason: "strip-failed",
1814
+ error: (e && e.message) || String(e), scts: scts };
1815
+ }
1816
+ var verifiedCount = 0;
1817
+ var perSctResults = [];
1818
+ for (var s = 0; s < scts.length; s += 1) {
1819
+ var sct = scts[s];
1820
+ var pem = logKeys[sct.logIdHex];
1821
+ if (!pem) {
1822
+ perSctResults.push({ logIdHex: sct.logIdHex, verified: false,
1823
+ reason: "log-key-missing" });
1824
+ continue;
1825
+ }
1826
+ var signedEntry;
1827
+ try { signedEntry = _buildSctSignedEntry(stripped, sct); }
1828
+ catch (e) {
1829
+ perSctResults.push({ logIdHex: sct.logIdHex, verified: false,
1830
+ reason: "build-entry-failed",
1831
+ error: (e && e.message) || String(e) });
1832
+ continue;
1833
+ }
1834
+ var nodeAlgo = sct.hashAlgo === 4 ? "sha256" : // allow:raw-byte-literal — TLS 1.2 HashAlgorithm enum sha256
1835
+ sct.hashAlgo === 5 ? "sha384" : // allow:raw-byte-literal — TLS 1.2 HashAlgorithm enum sha384
1836
+ sct.hashAlgo === 6 ? "sha512" : // allow:raw-byte-literal — TLS 1.2 HashAlgorithm enum sha512
1837
+ null;
1838
+ if (nodeAlgo === null) {
1839
+ perSctResults.push({ logIdHex: sct.logIdHex, verified: false,
1840
+ reason: "unsupported-hash-algo", hashAlgo: sct.hashAlgo });
1841
+ continue;
1842
+ }
1843
+ var keyObj;
1844
+ try { keyObj = nodeCrypto.createPublicKey(pem); }
1845
+ catch (e) {
1846
+ perSctResults.push({ logIdHex: sct.logIdHex, verified: false,
1847
+ reason: "log-key-parse-failed",
1848
+ error: (e && e.message) || String(e) });
1849
+ continue;
1850
+ }
1851
+ // RFC 6962 §2.1.4 — log-key SignatureAndHashAlgorithm pair must
1852
+ // match the SCT's signatureAlgorithm. signatureAlgo enum 1=RSA,
1853
+ // 3=ECDSA. Cross-check against the actual log-key type so a
1854
+ // malformed log-keys map can't silently accept SCTs signed
1855
+ // under one algorithm against a key registered under another.
1856
+ var keyType = keyObj.asymmetricKeyType;
1857
+ var sctSigAlgo = sct.signatureAlgo;
1858
+ var algoOk = (sctSigAlgo === 1 && keyType === "rsa") || // allow:raw-byte-literal — TLS 1.2 SignatureAlgorithm rsa
1859
+ (sctSigAlgo === 3 && (keyType === "ec" || keyType === "ecdsa")); // allow:raw-byte-literal — TLS 1.2 SignatureAlgorithm ecdsa
1860
+ if (!algoOk) {
1861
+ perSctResults.push({ logIdHex: sct.logIdHex, verified: false,
1862
+ reason: "log-key-algo-mismatch",
1863
+ sctSignatureAlgo: sctSigAlgo, logKeyType: keyType });
1864
+ continue;
1865
+ }
1866
+ var verified;
1867
+ try { verified = nodeCrypto.verify(nodeAlgo, signedEntry, keyObj, sct.signature); }
1868
+ catch (e) {
1869
+ perSctResults.push({ logIdHex: sct.logIdHex, verified: false,
1870
+ reason: "verify-threw",
1871
+ error: (e && e.message) || String(e) });
1872
+ continue;
1873
+ }
1874
+ perSctResults.push({ logIdHex: sct.logIdHex, verified: verified });
1875
+ if (verified) verifiedCount += 1;
1876
+ }
1877
+ return {
1878
+ ok: verifiedCount >= minScts,
1879
+ reason: verifiedCount >= minScts ? null : "insufficient-verified",
1880
+ minScts: minScts,
1881
+ verifiedCount: verifiedCount,
1882
+ totalScts: scts.length,
1883
+ scts: perSctResults,
1884
+ };
1885
+ }
1886
+
1887
+ // ---- RFC 9162 §2.1 Merkle tree primitives ----
1888
+ //
1889
+ // CT v2 (RFC 9162) inclusion + consistency proofs operate on a binary
1890
+ // Merkle tree with the following node hashes (RFC 9162 §2.1.1):
1891
+ //
1892
+ // MTH(empty) = SHA-256("") — empty tree
1893
+ // MTH({d}) = SHA-256(0x00 || d) — leaf
1894
+ // MTH(D) = SHA-256(0x01 || MTH(D[0:k]) || MTH(D[k:n])) — internal
1895
+ //
1896
+ // SHA-256 is the algorithm RFC 9162 mandates; the framework's PQC-first
1897
+ // posture does not apply here because the algorithm is wire-defined
1898
+ // by the CT log itself and changing it would break interop with every
1899
+ // public log. A future SHA3-flavoured CT (no draft as of writing) ships
1900
+ // alongside, not in place.
1901
+ //
1902
+ // LEAF_HASH_PREFIX = 0x00
1903
+ // INNER_HASH_PREFIX = 0x01
1904
+ // k = largest power of 2 < n (RFC 9162 §2.1.1)
1905
+
1906
+ var CT_LEAF_HASH_PREFIX = 0x00;
1907
+ var CT_INNER_HASH_PREFIX = 0x01;
1908
+
1909
+ function _ctSha256(buf) {
1910
+ return nodeCrypto.createHash("sha256").update(buf).digest();
1911
+ }
1912
+ function _ctLeafHash(leafBytes) {
1913
+ return _ctSha256(Buffer.concat([Buffer.from([CT_LEAF_HASH_PREFIX]), leafBytes]));
1914
+ }
1915
+ function _ctInnerHash(left, right) {
1916
+ return Buffer.concat([Buffer.from([CT_INNER_HASH_PREFIX]), left, right]);
1917
+ }
1918
+ function _ctInnerHashFinal(left, right) {
1919
+ return _ctSha256(_ctInnerHash(left, right));
1920
+ }
1921
+
1922
+ // _ctLargestPowerOf2LessThan — k from RFC 9162 §2.1.1: the largest
1923
+ // power of 2 that is strictly less than n. n must be > 1.
1924
+ function _ctLargestPowerOf2LessThan(n) {
1925
+ if (n < 2) {
1926
+ throw new TlsTrustError("tls/ct-bad-tree-size",
1927
+ "ct: largest-power-of-2-less-than requires n >= 2 (got " + n + ")");
1928
+ }
1929
+ var k = 1;
1930
+ while ((k << 1) < n) k = k << 1;
1931
+ return k;
1932
+ }
1933
+
1934
+ // _ctVerifyInclusion — RFC 9162 §2.1.3 algorithm. Walks the audit path
1935
+ // from the leaf hash up to the tree's expected root using the supplied
1936
+ // audit path siblings. The leafIndex (0-based) selects which side at
1937
+ // each level the leaf sits on; the audit path provides the sibling
1938
+ // hash for that level.
1939
+ //
1940
+ // args:
1941
+ // leafHash: Buffer (32 bytes) — MTH({d}) of the leaf
1942
+ // leafIndex: integer 0 <= idx < treeSize
1943
+ // treeSize: integer >= 1
1944
+ // auditPath: Array of Buffer (each 32 bytes) — siblings bottom-up
1945
+ //
1946
+ // returns: Buffer (32 bytes) — computed root hash to compare
1947
+ // throws: TlsTrustError on shape errors
1948
+ function _ctVerifyInclusionPath(leafHash, leafIndex, treeSize, auditPath) {
1949
+ if (!Buffer.isBuffer(leafHash) || leafHash.length !== 32) { // allow:raw-byte-literal — RFC 9162 SHA-256 digest length
1950
+ throw new TlsTrustError("tls/ct-bad-leaf-hash",
1951
+ "ct.verifyInclusion: leafHash must be a 32-byte Buffer");
1952
+ }
1953
+ if (typeof leafIndex !== "number" || leafIndex < 0 || leafIndex >= treeSize ||
1954
+ Math.floor(leafIndex) !== leafIndex) {
1955
+ throw new TlsTrustError("tls/ct-bad-index",
1956
+ "ct.verifyInclusion: leafIndex must be an integer 0..treeSize-1");
1957
+ }
1958
+ if (typeof treeSize !== "number" || treeSize < 1 || Math.floor(treeSize) !== treeSize) {
1959
+ throw new TlsTrustError("tls/ct-bad-tree-size",
1960
+ "ct.verifyInclusion: treeSize must be a positive integer");
1961
+ }
1962
+ if (!Array.isArray(auditPath)) {
1963
+ throw new TlsTrustError("tls/ct-bad-audit-path",
1964
+ "ct.verifyInclusion: auditPath must be an array of 32-byte Buffers");
1965
+ }
1966
+
1967
+ // Per RFC 9162 §2.1.3 — climb the tree using the audit path. fn=leafIndex,
1968
+ // sn=treeSize-1 (last index in the tree at this level). Pop one
1969
+ // sibling from the audit path per level.
1970
+ var fn = leafIndex;
1971
+ var sn = treeSize - 1;
1972
+ var r = leafHash;
1973
+ var pathPos = 0;
1974
+ while (sn > 0) {
1975
+ if (pathPos >= auditPath.length) {
1976
+ throw new TlsTrustError("tls/ct-audit-path-short",
1977
+ "ct.verifyInclusion: audit path exhausted before tree root reached");
1978
+ }
1979
+ var sibling = auditPath[pathPos++];
1980
+ if (!Buffer.isBuffer(sibling) || sibling.length !== 32) { // allow:raw-byte-literal — RFC 9162 SHA-256 digest length
1981
+ throw new TlsTrustError("tls/ct-bad-audit-path",
1982
+ "ct.verifyInclusion: audit path entry " + (pathPos - 1) + " is not a 32-byte Buffer");
1983
+ }
1984
+ if ((fn & 1) === 1 || fn === sn) {
1985
+ r = _ctInnerHashFinal(sibling, r);
1986
+ // Right-side leaf — climb until we hit a left-side ancestor.
1987
+ while ((fn & 1) === 0 && fn !== 0) { fn >>>= 1; sn >>>= 1; }
1988
+ } else {
1989
+ r = _ctInnerHashFinal(r, sibling);
1990
+ }
1991
+ fn >>>= 1;
1992
+ sn >>>= 1;
1993
+ }
1994
+ if (pathPos !== auditPath.length) {
1995
+ throw new TlsTrustError("tls/ct-audit-path-long",
1996
+ "ct.verifyInclusion: audit path has " + (auditPath.length - pathPos) +
1997
+ " trailing entries beyond the root");
1998
+ }
1999
+ return r;
2000
+ }
2001
+
2002
+ // _ctVerifyConsistency — RFC 9162 §2.1.4 consistency proof verification.
2003
+ // Given a first STH (size m) and a second STH (size n, n >= m), the
2004
+ // consistency proof shows the second tree contains the first tree as a
2005
+ // prefix. Returns the computed roots (oldRoot, newRoot) so the caller
2006
+ // can compare against the operator-supplied STHs.
2007
+ function _ctVerifyConsistencyPath(m, n, consistencyProof, firstHash) {
2008
+ if (typeof m !== "number" || m < 1 || Math.floor(m) !== m) {
2009
+ throw new TlsTrustError("tls/ct-bad-first-size",
2010
+ "ct.verifyConsistency: m (first tree size) must be a positive integer");
2011
+ }
2012
+ if (typeof n !== "number" || n < m || Math.floor(n) !== n) {
2013
+ throw new TlsTrustError("tls/ct-bad-second-size",
2014
+ "ct.verifyConsistency: n (second tree size) must be an integer >= m");
2015
+ }
2016
+ if (!Buffer.isBuffer(firstHash) || firstHash.length !== 32) { // allow:raw-byte-literal — RFC 9162 SHA-256 digest length
2017
+ throw new TlsTrustError("tls/ct-bad-first-hash",
2018
+ "ct.verifyConsistency: firstHash must be a 32-byte Buffer");
2019
+ }
2020
+ if (!Array.isArray(consistencyProof)) {
2021
+ throw new TlsTrustError("tls/ct-bad-consistency-proof",
2022
+ "ct.verifyConsistency: consistencyProof must be an array of Buffers");
2023
+ }
2024
+ // RFC 9162 §2.1.4.2 — algorithm is the same as the inclusion-proof
2025
+ // walk, with the leaf-index seeded at the first-tree size minus 1 and
2026
+ // the special case for m being a complete subtree.
2027
+ var path = consistencyProof.slice();
2028
+ var node;
2029
+ var fn = m - 1;
2030
+ var sn = n - 1;
2031
+ // Walk past the right-side bits — the consistency proof omits the
2032
+ // path while the first tree is a complete subtree of the second.
2033
+ while ((fn & 1) === 1) { fn >>>= 1; sn >>>= 1; }
2034
+
2035
+ if (fn === 0) {
2036
+ // m was a complete subtree — its root is the firstHash itself.
2037
+ node = firstHash;
2038
+ } else {
2039
+ if (path.length === 0) {
2040
+ throw new TlsTrustError("tls/ct-consistency-empty",
2041
+ "ct.verifyConsistency: consistency proof empty but first tree is not a complete subtree");
2042
+ }
2043
+ node = path.shift();
2044
+ }
2045
+ while (sn > 0) {
2046
+ if (path.length === 0) {
2047
+ throw new TlsTrustError("tls/ct-consistency-short",
2048
+ "ct.verifyConsistency: consistency proof exhausted before second-tree root");
2049
+ }
2050
+ var sibling = path.shift();
2051
+ if (!Buffer.isBuffer(sibling) || sibling.length !== 32) { // allow:raw-byte-literal — RFC 9162 SHA-256 digest length
2052
+ throw new TlsTrustError("tls/ct-bad-consistency-entry",
2053
+ "ct.verifyConsistency: consistency-proof entry is not a 32-byte Buffer");
2054
+ }
2055
+ if ((fn & 1) === 1 || fn === sn) {
2056
+ node = _ctInnerHashFinal(sibling, node);
2057
+ while ((fn & 1) === 0 && fn !== 0) { fn >>>= 1; sn >>>= 1; }
2058
+ } else {
2059
+ node = _ctInnerHashFinal(node, sibling);
2060
+ }
2061
+ fn >>>= 1;
2062
+ sn >>>= 1;
2063
+ }
2064
+ return node;
2065
+ }
2066
+
2067
+ function _findSctOid(rawDer) {
2068
+ // Cheap presence check — used by inspect() before ASN.1 walking.
2069
+ // OID 1.3.6.1.4.1.11129.2.4.2 = 06 0A 2B 06 01 04 01 D6 79 02 04 02.
2070
+ var oidBytes = Buffer.from([
2071
+ 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02,
2072
+ ]);
2073
+ return rawDer.indexOf(oidBytes) !== -1;
2074
+ }
2075
+
2076
+ var ct = Object.freeze({
2077
+ // inspect — quick presence check for the SCT extension.
2078
+ inspect: function (rawDer) {
2079
+ if (!Buffer.isBuffer(rawDer)) {
2080
+ throw new TlsTrustError("tls/ct-bad-input",
2081
+ "ct.inspect: rawDer must be a Buffer (cert.raw)");
2082
+ }
2083
+ return {
2084
+ hasSctExtension: _findSctOid(rawDer),
2085
+ rawLength: rawDer.length,
2086
+ };
2087
+ },
2088
+ // parseScts — full ASN.1 walk + SCT-list parse. Returns
2089
+ // [{ version, logIdHex, timestamp, signature, ... }, ...] or [] when
2090
+ // no SCT extension is present.
2091
+ parseScts: function (rawDer) {
2092
+ if (!Buffer.isBuffer(rawDer)) {
2093
+ throw new TlsTrustError("tls/ct-bad-input",
2094
+ "ct.parseScts: rawDer must be a Buffer");
2095
+ }
2096
+ var ext = _extractSctExtensionFromCert(rawDer);
2097
+ if (!ext.sctListRaw) return [];
2098
+ return _parseSctList(ext.sctListRaw);
2099
+ },
2100
+ // verifyScts — full RFC 6962 verification. opts.logKeys maps
2101
+ // log_id (hex SHA-256 of the log's pubkey) → PEM public key.
2102
+ // Operators populate from the Chrome CT log list. Returns
2103
+ // { ok, verifiedCount, totalScts, scts: [{ logIdHex, verified, ... }] }.
2104
+ verifyScts: verifyScts,
2105
+ // Operator middleware predicate: refuse a peer cert lacking SCT
2106
+ // verification. Composes verifyScts under the hood.
2107
+ // verifyInclusion — RFC 9162 §4.5/§5.1 inclusion-proof verifier.
2108
+ // Composes with inspect() / parseScts() / verifyScts() for the
2109
+ // signature side: an SCT proves a log promised to include the cert,
2110
+ // and verifyInclusion proves that promise was kept (the leaf actually
2111
+ // sits in the published tree).
2112
+ //
2113
+ // opts: {
2114
+ // sct: { logIdHex, timestamp, signedEntryDer? } — from parseScts
2115
+ // leafCertificate: Buffer — leaf cert DER (the entry hashed at the leaf)
2116
+ // leafIndex: integer — position in the tree (from RFC 9162 §6.7 get-proof-by-hash)
2117
+ // auditPath: [Buffer] — the inclusion-proof siblings, bottom-up
2118
+ // sthFromLog: { treeSize, rootHash[, sha256RootHash] }
2119
+ // — operator fetched the signed tree head from the log
2120
+ // (RFC 9162 §6.4 get-sth) and supplies treeSize +
2121
+ // rootHash (32-byte Buffer or hex string)
2122
+ // consistency: { firstSize, firstRoot, proof } — optional
2123
+ // — when provided, also verifies that the supplied
2124
+ // STH is consistent with an earlier STH the operator
2125
+ // pinned (RFC 9162 §6.5 get-sth-consistency)
2126
+ // }
2127
+ //
2128
+ // returns: { valid: bool, reason?: string, computedRoot?: hex,
2129
+ // consistency?: { ok, computedSecondRoot? } }
2130
+ verifyInclusion: function (opts) {
2131
+ if (!opts || typeof opts !== "object") {
2132
+ return { valid: false, reason: "missing-opts" };
2133
+ }
2134
+ if (!opts.sct || typeof opts.sct !== "object") {
2135
+ return { valid: false, reason: "missing-sct" };
2136
+ }
2137
+ if (!Buffer.isBuffer(opts.leafCertificate)) {
2138
+ return { valid: false, reason: "missing-leaf-certificate" };
2139
+ }
2140
+ if (!opts.sthFromLog || typeof opts.sthFromLog !== "object") {
2141
+ return { valid: false, reason: "missing-sth" };
2142
+ }
2143
+ if (typeof opts.leafIndex !== "number" || !isFinite(opts.leafIndex) ||
2144
+ opts.leafIndex < 0 || Math.floor(opts.leafIndex) !== opts.leafIndex) {
2145
+ return { valid: false, reason: "bad-leaf-index" };
2146
+ }
2147
+ if (!Array.isArray(opts.auditPath)) {
2148
+ return { valid: false, reason: "bad-audit-path" };
2149
+ }
2150
+
2151
+ // Build the leaf bytes per RFC 9162 §4.6 — TimestampedEntry.
2152
+ // entry_type = x509_entry (0); signed_entry = strip-SCT-extension(cert).
2153
+ // Operators may pass a pre-built signedEntryDer when the SCT was
2154
+ // already extracted via parseScts() + the framework has the
2155
+ // pre-issuance cert; otherwise we strip the SCT extension here.
2156
+ var signedEntryDer = opts.sct.signedEntryDer;
2157
+ if (!Buffer.isBuffer(signedEntryDer)) {
2158
+ try { signedEntryDer = _stripSctExtensionFromCert(opts.leafCertificate); }
2159
+ catch (e) {
2160
+ return { valid: false, reason: "strip-failed",
2161
+ error: (e && e.message) || String(e) };
2162
+ }
2163
+ }
2164
+
2165
+ // RFC 9162 §4.6 MerkleTreeLeaf — version (1) + leaf_type (0) +
2166
+ // timestamp (uint64) + entry_type (uint16) + signed_entry (variable-
2167
+ // length cert DER with 24-bit length prefix) + extensions (variable-
2168
+ // length, 16-bit length prefix, empty for x509_entry).
2169
+ var ts = opts.sct.timestamp;
2170
+ if (typeof ts !== "number" && typeof ts !== "bigint") {
2171
+ return { valid: false, reason: "bad-sct-timestamp" };
2172
+ }
2173
+ var tsBuf = Buffer.alloc(8); // allow:raw-byte-literal — TLS uint64 width
2174
+ var tsBig = typeof ts === "bigint" ? ts : BigInt(Math.floor(ts));
2175
+ tsBuf.writeBigUInt64BE(tsBig);
2176
+ var entryTypeBuf = Buffer.from([0x00, 0x00]);
2177
+ var lenBuf = Buffer.alloc(3); // allow:raw-byte-literal — TLS uint24 length prefix
2178
+ lenBuf.writeUIntBE(signedEntryDer.length, 0, 3);
2179
+ var extensionsBuf = Buffer.from([0x00, 0x00]); // allow:raw-byte-literal — empty extensions vector
2180
+ var leafBytes = Buffer.concat([
2181
+ Buffer.from([0x00]), // version v1
2182
+ Buffer.from([0x00]), // leaf_type timestamped_entry
2183
+ tsBuf,
2184
+ entryTypeBuf,
2185
+ lenBuf, signedEntryDer,
2186
+ extensionsBuf,
2187
+ ]);
2188
+
2189
+ var leafHash = _ctLeafHash(leafBytes);
2190
+ var computedRoot;
2191
+ try {
2192
+ computedRoot = _ctVerifyInclusionPath(leafHash, opts.leafIndex,
2193
+ opts.sthFromLog.treeSize, opts.auditPath);
2194
+ } catch (e) {
2195
+ return { valid: false, reason: "inclusion-walk-failed",
2196
+ error: (e && e.message) || String(e) };
2197
+ }
2198
+
2199
+ // sthFromLog.rootHash may be a Buffer or hex string.
2200
+ var sthRoot = opts.sthFromLog.rootHash || opts.sthFromLog.sha256RootHash;
2201
+ if (typeof sthRoot === "string") {
2202
+ try { sthRoot = Buffer.from(sthRoot, "hex"); }
2203
+ catch (_e) { return { valid: false, reason: "bad-sth-root-encoding" }; }
2204
+ }
2205
+ if (!Buffer.isBuffer(sthRoot) || sthRoot.length !== 32) { // allow:raw-byte-literal — RFC 9162 SHA-256 digest length
2206
+ return { valid: false, reason: "bad-sth-root" };
2207
+ }
2208
+ if (!bCrypto.timingSafeEqual(computedRoot, sthRoot)) {
2209
+ return { valid: false, reason: "root-mismatch",
2210
+ computedRoot: computedRoot.toString("hex") };
2211
+ }
2212
+
2213
+ // Optional consistency proof — RFC 9162 §2.1.4.
2214
+ var consistencyResult = null;
2215
+ if (opts.consistency && typeof opts.consistency === "object") {
2216
+ var firstRoot = opts.consistency.firstRoot;
2217
+ if (typeof firstRoot === "string") {
2218
+ try { firstRoot = Buffer.from(firstRoot, "hex"); }
2219
+ catch (_e) {
2220
+ return { valid: false, reason: "bad-consistency-first-root-encoding" };
2221
+ }
2222
+ }
2223
+ try {
2224
+ var computedSecond = _ctVerifyConsistencyPath(
2225
+ opts.consistency.firstSize, opts.sthFromLog.treeSize,
2226
+ opts.consistency.proof || [], firstRoot);
2227
+ var ok = bCrypto.timingSafeEqual(computedSecond, sthRoot);
2228
+ consistencyResult = {
2229
+ ok: ok,
2230
+ computedSecondRoot: computedSecond.toString("hex"),
2231
+ };
2232
+ if (!ok) {
2233
+ return { valid: false, reason: "consistency-mismatch",
2234
+ computedRoot: computedRoot.toString("hex"),
2235
+ consistency: consistencyResult };
2236
+ }
2237
+ } catch (e) {
2238
+ return { valid: false, reason: "consistency-walk-failed",
2239
+ error: (e && e.message) || String(e) };
2240
+ }
2241
+ }
2242
+
2243
+ return {
2244
+ valid: true,
2245
+ computedRoot: computedRoot.toString("hex"),
2246
+ leafHash: leafHash.toString("hex"),
2247
+ consistency: consistencyResult,
2248
+ };
2249
+ },
2250
+ // verifyConsistency — standalone RFC 9162 §2.1.4 consistency-proof
2251
+ // verifier. Operators pinning historical tree-head fingerprints call
2252
+ // this whenever they fetch a fresh STH to confirm the log hasn't
2253
+ // forked. Returns { valid, computedRoot } / { valid:false, reason }.
2254
+ verifyConsistency: function (opts) {
2255
+ if (!opts || typeof opts !== "object") {
2256
+ return { valid: false, reason: "missing-opts" };
2257
+ }
2258
+ var firstRoot = opts.firstRoot;
2259
+ if (typeof firstRoot === "string") {
2260
+ try { firstRoot = Buffer.from(firstRoot, "hex"); }
2261
+ catch (_e) { return { valid: false, reason: "bad-first-root-encoding" }; }
2262
+ }
2263
+ var secondRoot = opts.secondRoot;
2264
+ if (typeof secondRoot === "string") {
2265
+ try { secondRoot = Buffer.from(secondRoot, "hex"); }
2266
+ catch (_e) { return { valid: false, reason: "bad-second-root-encoding" }; }
2267
+ }
2268
+ if (!Buffer.isBuffer(firstRoot) || firstRoot.length !== 32) { // allow:raw-byte-literal — RFC 9162 SHA-256 digest length
2269
+ return { valid: false, reason: "bad-first-root" };
2270
+ }
2271
+ if (!Buffer.isBuffer(secondRoot) || secondRoot.length !== 32) { // allow:raw-byte-literal — RFC 9162 SHA-256 digest length
2272
+ return { valid: false, reason: "bad-second-root" };
2273
+ }
2274
+ var computed;
2275
+ try {
2276
+ computed = _ctVerifyConsistencyPath(opts.firstSize, opts.secondSize,
2277
+ opts.proof || [], firstRoot);
2278
+ } catch (e) {
2279
+ return { valid: false, reason: "consistency-walk-failed",
2280
+ error: (e && e.message) || String(e) };
2281
+ }
2282
+ if (!bCrypto.timingSafeEqual(computed, secondRoot)) {
2283
+ return { valid: false, reason: "root-mismatch",
2284
+ computedRoot: computed.toString("hex") };
2285
+ }
2286
+ return { valid: true, computedRoot: computed.toString("hex") };
2287
+ },
2288
+ requireScts: function (opts) {
2289
+ opts = opts || {};
2290
+ return function (peerCert) {
2291
+ if (!peerCert || !peerCert.raw) {
2292
+ return new TlsTrustError("tls/ct-no-cert",
2293
+ "requireScts: peer cert.raw missing");
2294
+ }
2295
+ var rv = verifyScts(peerCert.raw, opts);
2296
+ if (!rv.ok) {
2297
+ // Map verifier reason → operator-facing error code so call
2298
+ // sites can distinguish "no SCT extension at all" from
2299
+ // "extension present but verification short of minScts".
2300
+ var code = "tls/ct-not-verified";
2301
+ if (rv.reason === "no-sct-extension") code = "tls/ct-no-sct-extension";
2302
+ else if (rv.reason === "insufficient-verified") code = "tls/ct-insufficient-verified";
2303
+ return new TlsTrustError(code,
2304
+ "SCT verification failed: " + (rv.reason || "unknown") +
2305
+ " (" + rv.verifiedCount + "/" + rv.totalScts + " verified)");
2306
+ }
2307
+ return null;
2308
+ };
2309
+ },
2310
+ });
2311
+
2312
+ // ---- ECH (Encrypted Client Hello) — RFC 9460 SVCB ech= SvcParam +
2313
+ // draft-ietf-tls-esni-22 §4 ECHConfigList -----------------------
2314
+ //
2315
+ // ECH is a TLS 1.3 extension that encrypts the Client Hello Inner
2316
+ // (SNI, ALPN, etc.) under a public key the server publishes via DNS
2317
+ // SVCB/HTTPS records. A passive observer sees only the public_name
2318
+ // SNI in the outer hello — the real virtual host stays confidential.
2319
+ //
2320
+ // Wire format reminder (uint16 lengths are big-endian throughout):
2321
+ //
2322
+ // ECHConfigList = uint16 total_length || ECHConfig[]
2323
+ // ECHConfig = uint16 version || uint16 length || contents
2324
+ // contents (v=0xfe0d) =
2325
+ // HpkeKeyConfig key_config
2326
+ // uint8 maximum_name_length
2327
+ // opaque<1..255> public_name (with uint8 length prefix)
2328
+ // Extension extensions<0..2^16-1> (uint16 length prefix +
2329
+ // list of (uint16 ext_type,
2330
+ // opaque<0..2^16-1> ext_data))
2331
+ // HpkeKeyConfig =
2332
+ // uint8 config_id
2333
+ // uint16 kem_id
2334
+ // opaque public_key<1..2^16-1> (uint16 length prefix)
2335
+ // HpkeSymmetricCipherSuite cipher_suites<4..2^16-1>
2336
+ // (uint16 length prefix; entries
2337
+ // each (uint16 kdf_id, uint16
2338
+ // aead_id) — 4 bytes apiece)
2339
+
2340
+ var ECH_CONFIG_VERSION_DRAFT_22 = 0xfe0d; // allow:raw-byte-literal — draft-ietf-tls-esni-22 ECH version codepoint
2341
+
2342
+ function _echReadU8(buf, off) {
2343
+ if (off + 1 > buf.length) {
2344
+ throw new NetworkTlsError("tls/ech-config-malformed",
2345
+ "ECHConfigList: truncated reading uint8 at offset " + off);
2346
+ }
2347
+ return buf[off];
2348
+ }
2349
+ function _echReadU16(buf, off) {
2350
+ if (off + 2 > buf.length) { // allow:raw-byte-literal — uint16 width
2351
+ throw new NetworkTlsError("tls/ech-config-malformed",
2352
+ "ECHConfigList: truncated reading uint16 at offset " + off);
2353
+ }
2354
+ return buf.readUInt16BE(off);
2355
+ }
2356
+ function _echReadVarOpaqueU16(buf, off) {
2357
+ var len = _echReadU16(buf, off);
2358
+ off += 2; // allow:raw-byte-literal — uint16 length-prefix width
2359
+ if (off + len > buf.length) {
2360
+ throw new NetworkTlsError("tls/ech-config-malformed",
2361
+ "ECHConfigList: opaque vector overflows buffer (declared " + len +
2362
+ " bytes at offset " + (off - 2) + ", " + (buf.length - off) + " available)");
2363
+ }
2364
+ return { value: buf.slice(off, off + len), nextOff: off + len };
2365
+ }
2366
+ function _echReadVarOpaqueU8(buf, off) {
2367
+ var len = _echReadU8(buf, off);
2368
+ off += 1;
2369
+ if (off + len > buf.length) {
2370
+ throw new NetworkTlsError("tls/ech-config-malformed",
2371
+ "ECHConfigList: u8-prefixed opaque overflows buffer");
2372
+ }
2373
+ return { value: buf.slice(off, off + len), nextOff: off + len };
2374
+ }
2375
+
2376
+ /**
2377
+ * @primitive b.network.tls.parseEchConfigList
2378
+ * @signature b.network.tls.parseEchConfigList(raw)
2379
+ * @since 0.8.53
2380
+ * @status stable
2381
+ * @related b.network.tls.connectWithEch, b.network.dns.queryHttps
2382
+ *
2383
+ * Parse a draft-ietf-tls-esni-22 ECHConfigList byte string (the value
2384
+ * of the `ech=` SvcParam in an SVCB or HTTPS DNS record per RFC 9460
2385
+ * paragraph 7.4.2). Accepts a `Buffer` or a strict-base64 string. Returns
2386
+ * `{ rawLength, configs: [{ version, length, keyConfig, ... }] }`.
2387
+ *
2388
+ * For each ECHConfig at the published draft-22 version (`0xfe0d`) the
2389
+ * decoded `keyConfig` carries `configId`, `kemId`, `publicKey`
2390
+ * (Buffer), and `cipherSuites` (each `{ kdfId, aeadId }`); the entry
2391
+ * also exposes `maximumNameLength`, `publicName`, and `extensions`.
2392
+ * Unknown future ECH versions surface their raw `body` Buffer so the
2393
+ * caller can forward them to a Node build that supports them.
2394
+ *
2395
+ * Throws `NetworkTlsError("tls/ech-config-malformed")` on any framing
2396
+ * violation (truncated length prefix, vector overflow, bad
2397
+ * cipher_suites stride, etc.).
2398
+ *
2399
+ * @example
2400
+ * var b = require("@blamejs/core");
2401
+ * var rrs = await b.network.dns.queryHttps("example.com");
2402
+ * var rec = rrs.find(function (r) { return r.params && r.params.ech; });
2403
+ * var parsed = b.network.tls.parseEchConfigList(rec.params.ech);
2404
+ * // parsed.configs[0].keyConfig.kemId === 0x0020 (X25519)
2405
+ */
2406
+ function parseEchConfigList(raw) {
2407
+ if (typeof raw === "string") {
2408
+ // Operators sometimes hold the SvcParam as a base64 string; accept
2409
+ // both. Reject anything that doesn't round-trip cleanly through
2410
+ // strict-base64 — Node's Buffer.from(b64, "base64") is lenient
2411
+ // (silently ignores stray bytes), so we re-encode and compare.
2412
+ var stripped = raw.replace(/\s+/g, "");
2413
+ var decoded = Buffer.from(stripped, "base64");
2414
+ if (decoded.length === 0 || decoded.toString("base64") !== stripped) {
2415
+ throw new NetworkTlsError("tls/ech-config-malformed",
2416
+ "parseEchConfigList: input string is not strict base64");
2417
+ }
2418
+ raw = decoded;
2419
+ }
2420
+ if (!Buffer.isBuffer(raw) || raw.length === 0) {
2421
+ throw new NetworkTlsError("tls/ech-config-malformed",
2422
+ "parseEchConfigList: input must be a non-empty Buffer or base64 string");
2423
+ }
2424
+ if (raw.length < 2) { // allow:raw-byte-literal — uint16 outer length prefix
2425
+ throw new NetworkTlsError("tls/ech-config-malformed",
2426
+ "ECHConfigList: too short for outer length prefix");
2427
+ }
2428
+ var totalLen = raw.readUInt16BE(0);
2429
+ if (2 + totalLen !== raw.length) { // allow:raw-byte-literal — uint16 prefix width
2430
+ throw new NetworkTlsError("tls/ech-config-malformed",
2431
+ "ECHConfigList: outer length " + totalLen + " does not match buffer " +
2432
+ "tail length " + (raw.length - 2));
2433
+ }
2434
+ var off = 2; // allow:raw-byte-literal — uint16 prefix width
2435
+ var configs = [];
2436
+ while (off < raw.length) {
2437
+ if (off + 4 > raw.length) { // allow:raw-byte-literal — uint16 ver + uint16 len
2438
+ throw new NetworkTlsError("tls/ech-config-malformed",
2439
+ "ECHConfig: truncated header at offset " + off);
2440
+ }
2441
+ var version = raw.readUInt16BE(off);
2442
+ var length = raw.readUInt16BE(off + 2);
2443
+ var bodyOff = off + 4;
2444
+ var bodyEnd = bodyOff + length;
2445
+ if (bodyEnd > raw.length) {
2446
+ throw new NetworkTlsError("tls/ech-config-malformed",
2447
+ "ECHConfig: declared length " + length + " overflows ECHConfigList");
2448
+ }
2449
+ var entry = { version: version, length: length };
2450
+ if (version === ECH_CONFIG_VERSION_DRAFT_22) {
2451
+ var p = bodyOff;
2452
+ // HpkeKeyConfig
2453
+ var configId = _echReadU8(raw, p); p += 1;
2454
+ var kemId = _echReadU16(raw, p); p += 2; // allow:raw-byte-literal — uint16 KEM id width
2455
+ var pkOpaque = _echReadVarOpaqueU16(raw, p); p = pkOpaque.nextOff;
2456
+ var suitesLen = _echReadU16(raw, p); p += 2; // allow:raw-byte-literal — uint16 length prefix width
2457
+ if (p + suitesLen > bodyEnd) {
2458
+ throw new NetworkTlsError("tls/ech-config-malformed",
2459
+ "ECHConfig: cipher_suites vector overflows config body");
2460
+ }
2461
+ if (suitesLen % 4 !== 0 || suitesLen < 4) { // allow:raw-byte-literal — kdf+aead = 4 bytes per suite
2462
+ throw new NetworkTlsError("tls/ech-config-malformed",
2463
+ "ECHConfig: cipher_suites length must be a positive multiple of 4");
2464
+ }
2465
+ var suites = [];
2466
+ for (var sp = p; sp < p + suitesLen; sp += 4) { // allow:raw-byte-literal — 4-byte cipher suite stride
2467
+ suites.push({
2468
+ kdfId: raw.readUInt16BE(sp),
2469
+ aeadId: raw.readUInt16BE(sp + 2),
2470
+ });
2471
+ }
2472
+ p += suitesLen;
2473
+ // remainder of contents
2474
+ var maxNameLen = _echReadU8(raw, p); p += 1;
2475
+ var publicName = _echReadVarOpaqueU8(raw, p); p = publicName.nextOff;
2476
+ var extLen = _echReadU16(raw, p); p += 2; // allow:raw-byte-literal — uint16 length prefix width
2477
+ if (p + extLen !== bodyEnd) {
2478
+ throw new NetworkTlsError("tls/ech-config-malformed",
2479
+ "ECHConfig: extensions vector does not consume remaining body " +
2480
+ "(extLen=" + extLen + ", remaining=" + (bodyEnd - p) + ")");
2481
+ }
2482
+ var extensions = [];
2483
+ var extEnd = p + extLen;
2484
+ while (p < extEnd) {
2485
+ var extType = _echReadU16(raw, p); p += 2; // allow:raw-byte-literal — uint16 ext type
2486
+ var extData = _echReadVarOpaqueU16(raw, p); p = extData.nextOff;
2487
+ extensions.push({ type: extType, data: extData.value });
2488
+ }
2489
+ entry.keyConfig = {
2490
+ configId: configId,
2491
+ kemId: kemId,
2492
+ publicKey: pkOpaque.value,
2493
+ cipherSuites: suites,
2494
+ };
2495
+ entry.maximumNameLength = maxNameLen;
2496
+ entry.publicName = publicName.value.toString("ascii");
2497
+ entry.extensions = extensions;
2498
+ } else {
2499
+ // Unknown future version — surface raw bytes so the caller can
2500
+ // forward them to a Node build that does support that version.
2501
+ entry.body = Buffer.from(raw.slice(bodyOff, bodyEnd));
2502
+ }
2503
+ configs.push(entry);
2504
+ off = bodyEnd;
2505
+ }
2506
+ return { rawLength: raw.length, configs: configs };
2507
+ }
2508
+
2509
+ // Feature-detect: probe whether tls.connect accepts the `ech` option.
2510
+ // Cached so repeated connect calls don't re-test on every connection.
2511
+ // Strategy: tls.connect throws synchronously on a port=0 socket attempt
2512
+ // when the option shape is rejected at the C++ layer with
2513
+ // ERR_INVALID_ARG_TYPE / ERR_TLS_INVALID_OPTION; if it makes it past
2514
+ // option-validation we destroy the half-built socket. We never actually
2515
+ // open a socket — the probe runs entirely in option-parsing.
2516
+ var _echFeatureProbe = null;
2517
+ function _isEchSupported() {
2518
+ if (_echFeatureProbe !== null) return _echFeatureProbe;
2519
+ // The cleanest probe is to read tls.connect.toString() — but Node
2520
+ // hides option parsing in C++. Instead we attempt to construct the
2521
+ // options object via tls.checkServerIdentity-adjacent surface: call
2522
+ // tls.connect with a sentinel `ech: Buffer.alloc(0)` and an
2523
+ // immediately-destroyed socket. Any non-throwing path = supported.
2524
+ var supported = false;
2525
+ try {
2526
+ var probe = nodeTls.connect({
2527
+ host: "127.0.0.1",
2528
+ port: 1,
2529
+ ech: Buffer.alloc(0),
2530
+ lookup: function (_h, _o, cb) { cb(new Error("probe-abort")); },
2531
+ });
2532
+ supported = true;
2533
+ try { probe.destroy(); } catch (_e) { /* probe socket */ }
2534
+ } catch (e) {
2535
+ var msg = (e && (e.code || e.message)) || "";
2536
+ // ERR_INVALID_ARG_TYPE or ERR_TLS_* on `ech` = unsupported.
2537
+ if (/ech/i.test(msg) || /unknown option/i.test(msg)) supported = false;
2538
+ else supported = true; // unrelated throw (e.g. lookup): option accepted
2539
+ }
2540
+ _echFeatureProbe = supported;
2541
+ return supported;
2542
+ }
2543
+
2544
+ /**
2545
+ * @primitive b.network.tls.connectWithEch
2546
+ * @signature b.network.tls.connectWithEch(opts)
2547
+ * @since 0.8.53
2548
+ * @status stable
2549
+ * @related b.network.tls.parseEchConfigList, b.network.dns.queryHttps,
2550
+ * b.network.tls.checkServerIdentity9525
2551
+ *
2552
+ * Open a TLS-1.3 outbound connection with Encrypted Client Hello (ECH,
2553
+ * draft-ietf-tls-esni-22) when the destination publishes an `ech=`
2554
+ * SvcParam via SVCB/HTTPS records (RFC 9460 paragraph 2.4 / paragraph 9). The flow:
2555
+ *
2556
+ * 1. `b.network.dns.queryHttps(host)` to discover ECH config.
2557
+ * 2. If any record carries `ech=`, the parsed ECHConfigList is
2558
+ * attached to `tls.connect({ ech })` so the outer ClientHello
2559
+ * uses the published `public_name` SNI and the inner ClientHello
2560
+ * (real SNI, ALPN, etc.) is HPKE-encrypted under the published
2561
+ * public key.
2562
+ * 3. If no record carries `ech=`, or DNS fails, the function falls
2563
+ * back to a normal TLS connect (still TLSv1.3-floor + framework
2564
+ * PQC group preference). Operators get an `observability.event`
2565
+ * so the degradation is visible.
2566
+ * 4. If the running Node build does not support the `ech` connect
2567
+ * option, the function emits a one-shot warn and connects
2568
+ * without ECH — never throws on missing Node-side support.
2569
+ *
2570
+ * Returns the connected `tls.TLSSocket` once `secureConnect` fires.
2571
+ * `b.httpClient` will compose this in a follow-up release; this
2572
+ * primitive is the operator escape hatch for raw outbound TLS over
2573
+ * ECH (custom protocol clients, mTLS testing, ECH validation tools).
2574
+ *
2575
+ * @opts
2576
+ * {
2577
+ * host: string,
2578
+ * port: number,
2579
+ * alpn: string[],
2580
+ * ipFamily: 4 | 6,
2581
+ * timeoutMs: number,
2582
+ * servername: string,
2583
+ * ca: string|Buffer|Array,
2584
+ * checkServerIdentity: function,
2585
+ * echOverride: Buffer|string,
2586
+ * rejectUnauthorized: boolean,
2587
+ * }
2588
+ *
2589
+ * @example
2590
+ * var b = require("@blamejs/core");
2591
+ * var sock = await b.network.tls.connectWithEch({
2592
+ * host: "ech-target.example.com",
2593
+ * alpn: ["h2", "http/1.1"],
2594
+ * });
2595
+ * sock.write("GET / HTTP/1.1\r\nHost: ech-target.example.com\r\n\r\n");
2596
+ */
2597
+ function connectWithEch(opts) {
2598
+ opts = opts || {};
2599
+ if (typeof opts !== "object" || Array.isArray(opts)) {
2600
+ throw new NetworkTlsError("tls/ech-bad-opts",
2601
+ "connectWithEch: opts must be a plain object");
2602
+ }
2603
+ validateOpts(opts,
2604
+ ["host", "port", "alpn", "ipFamily", "timeoutMs", "servername", "ca",
2605
+ "checkServerIdentity", "echOverride", "rejectUnauthorized"],
2606
+ "network.tls.connectWithEch");
2607
+ validateOpts.requireNonEmptyString(opts.host, "connectWithEch: host",
2608
+ NetworkTlsError, "tls/ech-bad-opts");
2609
+ var port = opts.port === undefined ? 443 : opts.port; // allow:raw-byte-literal — HTTPS default port
2610
+ if (typeof port !== "number" || !isFinite(port) ||
2611
+ port <= 0 || port > 65535 || Math.floor(port) !== port) { // allow:raw-byte-literal — TCP port range
2612
+ throw new NetworkTlsError("tls/ech-bad-opts",
2613
+ "connectWithEch: port must be an integer in 1..65535");
2614
+ }
2615
+ if (opts.alpn !== undefined && !Array.isArray(opts.alpn)) {
2616
+ throw new NetworkTlsError("tls/ech-bad-opts",
2617
+ "connectWithEch: alpn must be an array of strings");
2618
+ }
2619
+ if (opts.ipFamily !== undefined && opts.ipFamily !== 4 && opts.ipFamily !== 6) {
2620
+ throw new NetworkTlsError("tls/ech-bad-opts",
2621
+ "connectWithEch: ipFamily must be 4 | 6 | undefined");
2622
+ }
2623
+ var timeoutMs = opts.timeoutMs === undefined
2624
+ ? C.TIME.seconds(30) : opts.timeoutMs;
2625
+ if (typeof timeoutMs !== "number" || !isFinite(timeoutMs) || timeoutMs < 0) {
2626
+ throw new NetworkTlsError("tls/ech-bad-opts",
2627
+ "connectWithEch: timeoutMs must be a non-negative finite number");
2628
+ }
2629
+ if (opts.echOverride !== undefined &&
2630
+ !Buffer.isBuffer(opts.echOverride) &&
2631
+ typeof opts.echOverride !== "string") {
2632
+ throw new NetworkTlsError("tls/ech-bad-opts",
2633
+ "connectWithEch: echOverride must be a Buffer or base64 string");
2634
+ }
2635
+
2636
+ return new Promise(function (resolve, reject) {
2637
+ function _doConnect(echConfigBuf, sourceLabel) {
2638
+ var nodeSupportsEch = _isEchSupported();
2639
+ var connectOpts = {
2640
+ host: opts.host,
2641
+ port: port,
2642
+ servername: opts.servername || opts.host,
2643
+ minVersion: "TLSv1.3",
2644
+ };
2645
+ if (Array.isArray(opts.alpn)) connectOpts.ALPNProtocols = opts.alpn.slice();
2646
+ if (opts.ipFamily !== undefined) connectOpts.family = opts.ipFamily;
2647
+ if (opts.ca !== undefined) connectOpts.ca = _normalizeCaInput(opts.ca);
2648
+ if (typeof opts.checkServerIdentity === "function") {
2649
+ connectOpts.checkServerIdentity = opts.checkServerIdentity;
2650
+ }
2651
+ if (opts.rejectUnauthorized === false) {
2652
+ connectOpts.rejectUnauthorized = false;
2653
+ }
2654
+ var echAttached = false;
2655
+ if (echConfigBuf && nodeSupportsEch) {
2656
+ connectOpts.ech = echConfigBuf;
2657
+ echAttached = true;
2658
+ } else if (echConfigBuf && !nodeSupportsEch) {
2659
+ // ECHConfig present but Node build can't honor it — degrade
2660
+ // gracefully with a one-shot warn so operators know they're
2661
+ // sending an outer-only ClientHello.
2662
+ try {
2663
+ observability().emit("network.tls.ech.unsupported", {
2664
+ host: opts.host, source: sourceLabel,
2665
+ });
2666
+ } catch (_e) { /* drop-silent */ }
2667
+ try {
2668
+ audit().safeEmit({
2669
+ action: "network.tls.ech.unsupported",
2670
+ outcome: "success", // Node lacks `ech` opt — degraded to non-ECH
2671
+ metadata: { host: opts.host, source: sourceLabel },
2672
+ });
2673
+ } catch (_e) { /* drop-silent */ }
2674
+ }
2675
+
2676
+ var sock;
2677
+ try { sock = nodeTls.connect(connectOpts); }
2678
+ catch (e) {
2679
+ reject(new NetworkTlsError("tls/ech-connect-failed",
2680
+ "connectWithEch: tls.connect threw: " + ((e && e.message) || String(e))));
2681
+ return;
2682
+ }
2683
+ var settled = false;
2684
+ var to = null;
2685
+ if (timeoutMs > 0) {
2686
+ to = setTimeout(function () {
2687
+ if (settled) return;
2688
+ settled = true;
2689
+ try { sock.destroy(); } catch (_e) { /* destroy best-effort */ }
2690
+ reject(new NetworkTlsError("tls/ech-timeout",
2691
+ "connectWithEch: handshake timed out after " + timeoutMs + "ms"));
2692
+ }, timeoutMs);
2693
+ if (typeof to.unref === "function") to.unref();
2694
+ }
2695
+ sock.once("secureConnect", function () {
2696
+ if (settled) return;
2697
+ settled = true;
2698
+ if (to) clearTimeout(to);
2699
+ try {
2700
+ observability().emit("network.tls.ech.connected", {
2701
+ host: opts.host, echAttached: echAttached, source: sourceLabel,
2702
+ });
2703
+ } catch (_e) { /* drop-silent */ }
2704
+ resolve(sock);
2705
+ });
2706
+ sock.once("error", function (e) {
2707
+ if (settled) return;
2708
+ settled = true;
2709
+ if (to) clearTimeout(to);
2710
+ reject(e);
2711
+ });
2712
+ }
2713
+
2714
+ if (Buffer.isBuffer(opts.echOverride) || typeof opts.echOverride === "string") {
2715
+ // Operator-provided ECHConfigList — skip the SVCB lookup, validate
2716
+ // shape, then connect.
2717
+ var override;
2718
+ try {
2719
+ var bufOverride = Buffer.isBuffer(opts.echOverride)
2720
+ ? opts.echOverride
2721
+ : Buffer.from(opts.echOverride, "base64");
2722
+ parseEchConfigList(bufOverride); // validate-only
2723
+ override = bufOverride;
2724
+ } catch (e) {
2725
+ reject(e);
2726
+ return;
2727
+ }
2728
+ _doConnect(override, "override");
2729
+ return;
2730
+ }
2731
+
2732
+ // Default: SVCB/HTTPS lookup. Per RFC 9460 §2.4 the prefix `_https.`
2733
+ // is the SVCB owner-name for an HTTPS origin; modern Node honors a
2734
+ // bare HTTPS QTYPE on the apex name though, which is what
2735
+ // queryHttps does. We use queryHttps directly.
2736
+ var dnsMod;
2737
+ try { dnsMod = networkDns(); }
2738
+ catch (e) {
2739
+ reject(new NetworkTlsError("tls/ech-dns-unavailable",
2740
+ "connectWithEch: network-dns module unavailable: " +
2741
+ ((e && e.message) || String(e))));
2742
+ return;
2743
+ }
2744
+ dnsMod.queryHttps(opts.host).then(function (records) {
2745
+ var echBuf = null;
2746
+ for (var i = 0; i < records.length; i += 1) {
2747
+ var rec = records[i];
2748
+ if (rec && rec.params && Buffer.isBuffer(rec.params.ech) &&
2749
+ rec.params.ech.length > 0) {
2750
+ echBuf = rec.params.ech;
2751
+ break;
2752
+ }
2753
+ }
2754
+ _doConnect(echBuf, echBuf ? "svcb" : "no-ech-record");
2755
+ }).catch(function (e) {
2756
+ // DNS failure is not fatal — fall back to non-ECH connect so the
2757
+ // operator still gets a working TLS session. Emit obs so the
2758
+ // operator sees the degradation.
2759
+ try {
2760
+ observability().emit("network.tls.ech.dns_failed", {
2761
+ host: opts.host, error: (e && e.message) || String(e),
2762
+ });
2763
+ } catch (_e) { /* drop-silent */ }
2764
+ _doConnect(null, "dns-failed");
2765
+ });
2766
+ });
2767
+ }
2768
+
2769
+ // ---- RFC 9525 strict server identity verification ----------------
2770
+ //
2771
+ // RFC 9525 §6 — PKIX name validation:
2772
+ // §6.1 The certificate's subjectAltName extension is the
2773
+ // authoritative source of identifiers. CN-fallback is
2774
+ // forbidden when SAN is present. RFC 9525 §6.4.4 explicitly
2775
+ // deprecates CN matching outright; legacy CN-only certs
2776
+ // (no SAN) are refused under strict mode.
2777
+ // §6.4.3 Wildcard `*.example.com` matches `foo.example.com` (one
2778
+ // left-most label) but NOT `foo.bar.example.com` (deeper
2779
+ // subdomain) and NOT `example.com` (the wildcard owner
2780
+ // itself). Wildcards in the middle (`foo.*.example.com`) or
2781
+ // partial wildcards (`f*o.example.com`) are refused.
2782
+ // §6.5 IP addresses match against iPAddress entries in SAN, never
2783
+ // dNSName entries. Textual IP literals do not get DNS-style
2784
+ // wildcard treatment.
2785
+ //
2786
+ // Operators pass `b.network.tls.checkServerIdentity9525` to
2787
+ // `tls.connect({ checkServerIdentity })` to swap Node's permissive
2788
+ // default for the strict policy.
2789
+
2790
+ function _normalizeAsciiHost(host) {
2791
+ // RFC 9525 §6.4 — comparisons are ASCII case-insensitive on the
2792
+ // A-label form. We don't perform IDNA conversion (operators that
2793
+ // need U-label hosts must pre-convert via punycode); raw non-ASCII
2794
+ // input is refused so we never silently match across encodings.
2795
+ if (typeof host !== "string" || host.length === 0) return null;
2796
+ for (var i = 0; i < host.length; i += 1) {
2797
+ var cc = host.charCodeAt(i);
2798
+ if (cc > 0x7f) return null; // allow:raw-byte-literal — ASCII upper bound codepoint
2799
+ }
2800
+ // Strip a trailing dot (FQDN absolute form) for matching.
2801
+ var h = host.toLowerCase();
2802
+ if (h.length > 1 && h.charAt(h.length - 1) === ".") h = h.slice(0, -1);
2803
+ return h;
2804
+ }
2805
+
2806
+ function _matchDnsNamePattern(pattern, host) {
2807
+ // Both inputs must be ASCII-normalized. `pattern` is from the SAN;
2808
+ // `host` is the operator-supplied target host.
2809
+ pattern = _normalizeAsciiHost(pattern);
2810
+ if (!pattern || !host) return false;
2811
+ if (pattern.indexOf("*") === -1) {
2812
+ return pattern === host;
2813
+ }
2814
+ // Wildcards permitted only as the entire left-most label.
2815
+ var pLabels = pattern.split(".");
2816
+ var hLabels = host.split(".");
2817
+ if (pLabels.length !== hLabels.length) return false;
2818
+ if (pLabels.length < 3) return false; // refuse `*.tld` — too broad
2819
+ // Only the FIRST label may contain the wildcard, and it must be `*`
2820
+ // exactly (no partial like `f*o`).
2821
+ if (pLabels[0] !== "*") return false;
2822
+ for (var li = 1; li < pLabels.length; li += 1) {
2823
+ if (pLabels[li].indexOf("*") !== -1) return false;
2824
+ if (pLabels[li] !== hLabels[li]) return false;
2825
+ }
2826
+ // Left-most host label must be non-empty (no `*` matching empty).
2827
+ if (hLabels[0].length === 0) return false;
2828
+ return true;
2829
+ }
2830
+
2831
+ function _parseSanString(rawSubjectAltName) {
2832
+ // Node exposes the SAN as a comma-separated string of typed entries:
2833
+ // "DNS:foo.example.com, DNS:*.example.com, IP Address:198.51.100.1,
2834
+ // IP Address:2001:db8::1"
2835
+ // The RFC 9525 verifier only consumes DNS / IP entries.
2836
+ var dns = [];
2837
+ var ips = [];
2838
+ if (typeof rawSubjectAltName !== "string" || rawSubjectAltName.length === 0) {
2839
+ return { dns: dns, ips: ips };
2840
+ }
2841
+ var entries = rawSubjectAltName.split(",");
2842
+ for (var i = 0; i < entries.length; i += 1) {
2843
+ var raw = entries[i].trim();
2844
+ var colon = raw.indexOf(":");
2845
+ if (colon === -1) continue;
2846
+ var kind = raw.slice(0, colon).trim();
2847
+ var val = raw.slice(colon + 1).trim();
2848
+ if (kind === "DNS") {
2849
+ dns.push(val);
2850
+ } else if (kind === "IP Address" || kind === "IP") {
2851
+ ips.push(val);
2852
+ }
2853
+ // Other GeneralName types (URI / email / dirName / OID-based) are
2854
+ // outside RFC 9525's HTTPS scope.
2855
+ }
2856
+ return { dns: dns, ips: ips };
2857
+ }
2858
+
2859
+ function _normalizeIpForCompare(ip) {
2860
+ // Lower-case + strip embedded brackets so "[::1]" / "::1" / "::0001"
2861
+ // all compare equal.
2862
+ if (typeof ip !== "string") return null;
2863
+ var s = ip.trim();
2864
+ if (s.length >= 2 && s.charAt(0) === "[" && s.charAt(s.length - 1) === "]") {
2865
+ s = s.slice(1, -1);
2866
+ }
2867
+ // For IPv6 the canonical form is what `net.isIP` accepts; we
2868
+ // round-trip through Buffer comparison via net.isIPv4 / isIPv6.
2869
+ if (net.isIPv4(s)) return { family: 4, text: s };
2870
+ if (net.isIPv6(s)) {
2871
+ // Canonicalize by expanding to bytes and re-emitting lower-case.
2872
+ var parts = s.split("%"); // strip zone id
2873
+ var addr = parts[0];
2874
+ // Expand "::" then re-collapse via toString won't work in pure JS;
2875
+ // instead produce a 16-byte buffer for byte-equal comparison.
2876
+ var bytes = _ipv6ToBytes(addr);
2877
+ if (!bytes) return null;
2878
+ return { family: 6, text: addr.toLowerCase(), bytes: bytes };
2879
+ }
2880
+ return null;
2881
+ }
2882
+ function _ipv6ToBytes(addr) {
2883
+ // Minimal IPv6 → 16-byte parser. Splits on "::" once, parses each
2884
+ // hextet as base-16 uint16. Returns null on malformed input.
2885
+ if (typeof addr !== "string") return null;
2886
+ var halves;
2887
+ var doubleIdx = addr.indexOf("::");
2888
+ if (doubleIdx === -1) {
2889
+ halves = [addr.split(":"), []];
2890
+ } else {
2891
+ var leftStr = addr.slice(0, doubleIdx);
2892
+ var rightStr = addr.slice(doubleIdx + 2);
2893
+ halves = [
2894
+ leftStr.length ? leftStr.split(":") : [],
2895
+ rightStr.length ? rightStr.split(":") : [],
2896
+ ];
2897
+ }
2898
+ var left = halves[0], right = halves[1];
2899
+ var fillCount = 8 - (left.length + right.length); // allow:raw-byte-literal — IPv6 has 8 hextets
2900
+ if (fillCount < 0) return null;
2901
+ var hextets = left.concat(new Array(fillCount).fill("0")).concat(right);
2902
+ if (hextets.length !== 8) return null; // allow:raw-byte-literal — IPv6 hextet count
2903
+ var bytes = Buffer.alloc(16); // allow:raw-byte-literal — IPv6 = 16 bytes
2904
+ for (var i = 0; i < 8; i += 1) { // allow:raw-byte-literal — IPv6 hextet count
2905
+ var h = hextets[i];
2906
+ if (!safeBuffer.IPV6_HEXTET_RE.test(h)) return null;
2907
+ var v = parseInt(h, 16); // allow:raw-byte-literal — hex radix
2908
+ bytes[i * 2] = (v >> 8) & 0xff; // allow:raw-byte-literal — uint8 mask + uint16-half shift
2909
+ bytes[i * 2 + 1] = v & 0xff; // allow:raw-byte-literal — uint8 mask
2910
+ }
2911
+ return bytes;
2912
+ }
2913
+ function _ipsEqual(sanIp, hostIp) {
2914
+ var a = _normalizeIpForCompare(sanIp);
2915
+ var b = _normalizeIpForCompare(hostIp);
2916
+ if (!a || !b) return false;
2917
+ if (a.family !== b.family) return false;
2918
+ if (a.family === 4) return a.text === b.text;
2919
+ // family === 6 — byte compare.
2920
+ if (!a.bytes || !b.bytes) return false;
2921
+ if (a.bytes.length !== b.bytes.length) return false;
2922
+ for (var i = 0; i < a.bytes.length; i += 1) {
2923
+ if (a.bytes[i] !== b.bytes[i]) return false;
2924
+ }
2925
+ return true;
2926
+ }
2927
+
2928
+ /**
2929
+ * @primitive b.network.tls.checkServerIdentity9525
2930
+ * @signature b.network.tls.checkServerIdentity9525(host, cert)
2931
+ * @since 0.8.53
2932
+ * @status stable
2933
+ * @related b.network.tls.connectWithEch
2934
+ *
2935
+ * Drop-in replacement for Node's `tls.checkServerIdentity` that
2936
+ * implements RFC 9525 paragraph 6 strictly. Operators pass it to
2937
+ * `tls.connect({ checkServerIdentity })` (or to any framework primitive
2938
+ * that exposes `pkixStrict: true`).
2939
+ *
2940
+ * Differences vs Node's default matcher:
2941
+ *
2942
+ * - SAN-required when present is mandatory: a peer cert lacking
2943
+ * `subjectAltName` refuses with `tls/pkix-san-required` (RFC 9525
2944
+ * paragraph 6.4.4 forbids Common Name fallback).
2945
+ * - CN-only legacy certs surface a distinct
2946
+ * `tls/pkix-cn-fallback-refused` code so audit logs distinguish
2947
+ * "missing SAN" from "ancient CN-only cert still shipping".
2948
+ * - Wildcard matching is restricted to the entire leftmost label.
2949
+ * `*.example.com` matches `foo.example.com` but NOT
2950
+ * `foo.bar.example.com` and NOT `example.com`. Partial wildcards
2951
+ * like `f*o.example.com` and middle wildcards like
2952
+ * `foo.*.example.com` refuse.
2953
+ * - IP literals match `iPAddress` SAN entries only — never DNS
2954
+ * entries, never wildcards. IPv6 comparison is byte-equal after
2955
+ * canonicalization (zone-id stripped, `::` expanded).
2956
+ *
2957
+ * Returns `Error | undefined` — the `Error` shape Node expects; when
2958
+ * undefined, the connection is permitted to proceed.
2959
+ *
2960
+ * @example
2961
+ * var tls = require("node:tls");
2962
+ * var b = require("@blamejs/core");
2963
+ * var sock = tls.connect({
2964
+ * host: "internal.example.com",
2965
+ * port: 443,
2966
+ * checkServerIdentity: b.network.tls.checkServerIdentity9525,
2967
+ * });
2968
+ */
2969
+ function checkServerIdentity9525(host, cert) {
2970
+ // Drop-in for tls.checkServerIdentity. Returns Error|undefined.
2971
+ // Node calls this with the post-handshake `cert` shape: subject,
2972
+ // subjectaltname, etc.
2973
+ if (typeof host !== "string" || host.length === 0) {
2974
+ return new NetworkTlsError("tls/pkix-hostname-mismatch",
2975
+ "checkServerIdentity9525: host must be a non-empty string");
2976
+ }
2977
+ if (!cert || typeof cert !== "object") {
2978
+ return new NetworkTlsError("tls/pkix-hostname-mismatch",
2979
+ "checkServerIdentity9525: peer cert object missing");
2980
+ }
2981
+ var hostIsIp = net.isIP(host) > 0;
2982
+ var hostNorm = hostIsIp ? host : _normalizeAsciiHost(host);
2983
+ if (!hostIsIp && !hostNorm) {
2984
+ return new NetworkTlsError("tls/pkix-hostname-mismatch",
2985
+ "checkServerIdentity9525: host '" + host + "' is not a valid ASCII " +
2986
+ "DNS name (pre-convert U-labels to A-labels with punycode)");
2987
+ }
2988
+ var rawSan = cert.subjectaltname;
2989
+ if (typeof rawSan !== "string" || rawSan.length === 0) {
2990
+ // RFC 9525 §6.4.4 forbids CN fallback. If there's no SAN we refuse,
2991
+ // never inspect cert.subject.CN — a CN-only cert violates the
2992
+ // modern PKIX baseline and the operator chose the strict checker.
2993
+ return new NetworkTlsError("tls/pkix-san-required",
2994
+ "checkServerIdentity9525: certificate has no subjectAltName " +
2995
+ "extension (RFC 9525 §6.4.4 forbids Common Name fallback)");
2996
+ }
2997
+ var san = _parseSanString(rawSan);
2998
+ if (hostIsIp) {
2999
+ if (san.ips.length === 0) {
3000
+ return new NetworkTlsError("tls/pkix-hostname-mismatch",
3001
+ "checkServerIdentity9525: host '" + host + "' is an IP literal " +
3002
+ "but the certificate's SAN contains no iPAddress entries");
3003
+ }
3004
+ for (var ii = 0; ii < san.ips.length; ii += 1) {
3005
+ if (_ipsEqual(san.ips[ii], host)) return undefined;
3006
+ }
3007
+ return new NetworkTlsError("tls/pkix-hostname-mismatch",
3008
+ "checkServerIdentity9525: host IP '" + host + "' does not match " +
3009
+ "any iPAddress SAN (" + san.ips.join(", ") + ")");
3010
+ }
3011
+ // DNS host — must match a dNSName SAN entry.
3012
+ if (san.dns.length === 0) {
3013
+ return new NetworkTlsError("tls/pkix-hostname-mismatch",
3014
+ "checkServerIdentity9525: certificate's SAN contains no dNSName " +
3015
+ "entries (host '" + host + "' cannot match an iPAddress-only cert)");
3016
+ }
3017
+ for (var di = 0; di < san.dns.length; di += 1) {
3018
+ if (_matchDnsNamePattern(san.dns[di], hostNorm)) return undefined;
3019
+ }
3020
+ return new NetworkTlsError("tls/pkix-hostname-mismatch",
3021
+ "checkServerIdentity9525: host '" + host + "' does not match any " +
3022
+ "dNSName SAN (" + san.dns.join(", ") + ")");
3023
+ }
3024
+
3025
+ // Detect: did the caller pass a CN-only legacy cert? Surface a
3026
+ // distinct error code so operators can grep audit logs for the
3027
+ // fallback-refused shape vs a generic mismatch.
3028
+ function _refuseCnFallback(host, cert) {
3029
+ if (cert && cert.subject && typeof cert.subject.CN === "string" &&
3030
+ cert.subject.CN.length > 0 &&
3031
+ (typeof cert.subjectaltname !== "string" || cert.subjectaltname.length === 0)) {
3032
+ return new NetworkTlsError("tls/pkix-cn-fallback-refused",
3033
+ "checkServerIdentity9525: peer cert is CN-only (CN='" +
3034
+ cert.subject.CN + "'); RFC 9525 §6.4.4 refuses CN-fallback. " +
3035
+ "Reissue the certificate with a subjectAltName extension covering " +
3036
+ "host '" + host + "'.");
3037
+ }
3038
+ return null;
3039
+ }
3040
+
3041
+ // Public combined verifier — applies both the SAN-required check and
3042
+ // the CN-fallback explicit refusal so operators get the more specific
3043
+ // of the two error codes when applicable. checkServerIdentity9525 is
3044
+ // the drop-in name; this internal helper is what `connect` wires in.
3045
+ function _checkServerIdentityStrict(host, cert) {
3046
+ var cnRefusal = _refuseCnFallback(host, cert);
3047
+ if (cnRefusal) return cnRefusal;
3048
+ return checkServerIdentity9525(host, cert);
3049
+ }
3050
+
3051
+ // CVE-2026-21637 — Node propagates a synchronous throw from an
3052
+ // operator-supplied SNICallback up through the TLS handshake listener;
3053
+ // the unhandled throw on an unexpected servername crashes the
3054
+ // listener. RFC 6066 §3 expects the server to abort the handshake on a
3055
+ // failed callback, NOT crash the process.
3056
+ //
3057
+ // `wrapSNICallback(operatorCb)` returns a wrapper that:
3058
+ //
3059
+ // - Calls the operator callback in a try/catch.
3060
+ // - Surface a synchronous throw via the async (err, null) callback so
3061
+ // the TLS handshake aborts cleanly. Cb is best-effort: an operator
3062
+ // callback that throws AFTER invoking the callback already (double
3063
+ // invoke) gets the throw caught here without double-invoking again.
3064
+ // - Emit an audit event so a burst of crashes-that-weren't surfaces
3065
+ // in operator review.
3066
+ // - Returns the operator's original callback unchanged if it's not a
3067
+ // function (lets the caller pass undefined through without
3068
+ // special-casing).
3069
+ //
3070
+ // router.js routes its operator-supplied tlsOptions.SNICallback through
3071
+ // this helper before handing the options off to https.createServer.
3072
+ // Any future framework primitive that takes operator SNICallback
3073
+ // values does the same.
3074
+ function wrapSNICallback(operatorCb) {
3075
+ if (typeof operatorCb !== "function") return operatorCb;
3076
+ return function _wrappedSNICallback(servername, cb) {
3077
+ try {
3078
+ operatorCb(servername, cb);
3079
+ } catch (err) {
3080
+ try {
3081
+ audit().safeEmit({
3082
+ action: "network.tls.sni_callback_threw",
3083
+ outcome: "failure",
3084
+ metadata: {
3085
+ servername: typeof servername === "string" ? servername : null,
3086
+ reason: (err && err.message) ? err.message : String(err),
3087
+ },
3088
+ });
3089
+ } catch (_auditErr) { /* drop-silent — audit best-effort */ }
3090
+ try { cb(err, null); }
3091
+ catch (_cbErr) { /* cb already invoked or unavailable */ }
3092
+ }
3093
+ };
3094
+ }
3095
+
3096
+ module.exports = {
3097
+ addCa: addCa,
3098
+ addCaBundle: addCaBundle,
3099
+ removeCa: removeCa,
3100
+ removeCaByLabel: removeCaByLabel,
3101
+ clearAll: clearAll,
3102
+ purgeExpired: purgeExpired,
3103
+ expiringSoon: expiringSoon,
3104
+ expiryMonitor: expiryMonitor,
3105
+ pinsetDriftMonitor: pinsetDriftMonitor,
3106
+ useSystemTrust: useSystemTrust,
3107
+ isSystemTrustEnabled: isSystemTrustEnabled,
3108
+ getTrustStore: getTrustStore,
3109
+ captureBaselineFingerprints: captureBaselineFingerprints,
3110
+ detectBaselineDrift: detectBaselineDrift,
3111
+ applyToContext: applyToContext,
3112
+ buildOptions: buildOptions,
3113
+ getCaPems: getCaPems,
3114
+ ocsp: ocsp,
3115
+ ct: ct,
3116
+ pqc: pqc,
3117
+ preferredGroups: preferredGroups,
3118
+ parseEchConfigList: parseEchConfigList,
3119
+ connectWithEch: connectWithEch,
3120
+ checkServerIdentity9525: checkServerIdentity9525,
3121
+ wrapSNICallback: wrapSNICallback,
3122
+ TlsTrustError: TlsTrustError,
3123
+ NetworkTlsError: NetworkTlsError,
3124
+ _resetForTest: _resetForTest,
3125
+ _checkServerIdentityStrict: _checkServerIdentityStrict,
3126
+ };