@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.
- package/CHANGELOG.md +87 -0
- package/LICENSE +17 -0
- package/README.md +117 -0
- package/SECURITY.md +139 -0
- package/lib/admin.js +952 -0
- package/lib/analytics.js +267 -0
- package/lib/cart.js +279 -0
- package/lib/catalog-import.js +344 -0
- package/lib/catalog.js +769 -0
- package/lib/checkout.js +320 -0
- package/lib/config.js +151 -0
- package/lib/customers.js +322 -0
- package/lib/email.js +242 -0
- package/lib/externaldb-d1.js +283 -0
- package/lib/index.js +57 -0
- package/lib/inventory-alerts.js +198 -0
- package/lib/newsletter.js +142 -0
- package/lib/order.js +380 -0
- package/lib/payment.js +318 -0
- package/lib/pricing.js +185 -0
- package/lib/r2-bridge.js +169 -0
- package/lib/shipping.js +185 -0
- package/lib/storefront.js +2160 -0
- package/lib/subscriptions.js +410 -0
- package/lib/tax.js +161 -0
- package/lib/theme.js +194 -0
- package/lib/vendor/MANIFEST.json +19 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +23 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +34 -0
- package/lib/vendor/blamejs/.clusterfuzzlite/project.yaml +16 -0
- package/lib/vendor/blamejs/.dockerignore +45 -0
- package/lib/vendor/blamejs/.gitattributes +42 -0
- package/lib/vendor/blamejs/.github/CODEOWNERS +4 -0
- package/lib/vendor/blamejs/.github/FUNDING.yml +2 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/bug_report.md +58 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/feature_request.md +99 -0
- package/lib/vendor/blamejs/.github/PULL_REQUEST_TEMPLATE.md +77 -0
- package/lib/vendor/blamejs/.github/dependabot.yml +37 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +148 -0
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +107 -0
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +122 -0
- package/lib/vendor/blamejs/.github/workflows/ci.yml +511 -0
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +50 -0
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +655 -0
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +406 -0
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +101 -0
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +134 -0
- package/lib/vendor/blamejs/.gitignore +102 -0
- package/lib/vendor/blamejs/.gitleaks.toml +166 -0
- package/lib/vendor/blamejs/.hadolint.yaml +18 -0
- package/lib/vendor/blamejs/.npmrc +5 -0
- package/lib/vendor/blamejs/.pinact.yaml +17 -0
- package/lib/vendor/blamejs/ARCHITECTURE.md +158 -0
- package/lib/vendor/blamejs/CHANGELOG.md +1351 -0
- package/lib/vendor/blamejs/CODE_OF_CONDUCT.md +86 -0
- package/lib/vendor/blamejs/CONTRIBUTING.md +156 -0
- package/lib/vendor/blamejs/GOVERNANCE.md +201 -0
- package/lib/vendor/blamejs/LICENSE +201 -0
- package/lib/vendor/blamejs/LTS-CALENDAR.md +29 -0
- package/lib/vendor/blamejs/MIGRATING.md +29 -0
- package/lib/vendor/blamejs/NOTICE +81 -0
- package/lib/vendor/blamejs/README.md +304 -0
- package/lib/vendor/blamejs/SECURITY.md +432 -0
- package/lib/vendor/blamejs/api-snapshot.json +48709 -0
- package/lib/vendor/blamejs/assets/BlameJS_Logo.png +0 -0
- package/lib/vendor/blamejs/assets/BlameJS_Logo.svg +129 -0
- package/lib/vendor/blamejs/bench/README.md +77 -0
- package/lib/vendor/blamejs/bench/_helpers.js +70 -0
- package/lib/vendor/blamejs/bench/baseline.json +183 -0
- package/lib/vendor/blamejs/bench/crypto-hash.bench.js +19 -0
- package/lib/vendor/blamejs/bench/crypto-symmetric.bench.js +28 -0
- package/lib/vendor/blamejs/bench/run.js +140 -0
- package/lib/vendor/blamejs/bench/safe-json.bench.js +31 -0
- package/lib/vendor/blamejs/bin/blamejs.js +13 -0
- package/lib/vendor/blamejs/docker/caddy/Caddyfile +46 -0
- package/lib/vendor/blamejs/docker/coredns/Corefile +37 -0
- package/lib/vendor/blamejs/docker/haproxy/haproxy.cfg +52 -0
- package/lib/vendor/blamejs/docker/init/generate-certs.sh +118 -0
- package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +87 -0
- package/lib/vendor/blamejs/docker/mitmproxy/config.yaml +16 -0
- package/lib/vendor/blamejs/docker/mongo/init-tls.sh +17 -0
- package/lib/vendor/blamejs/docker/mysql/my.cnf +12 -0
- package/lib/vendor/blamejs/docker/nats/nats.conf +33 -0
- package/lib/vendor/blamejs/docker/postgres/init-tls.sh +17 -0
- package/lib/vendor/blamejs/docker/postgres/postgresql.conf +18 -0
- package/lib/vendor/blamejs/docker/rabbitmq/rabbitmq.conf +18 -0
- package/lib/vendor/blamejs/docker/redis/redis.conf +15 -0
- package/lib/vendor/blamejs/docker/squid/squid.conf +24 -0
- package/lib/vendor/blamejs/docker/syslog/syslog-ng.conf +34 -0
- package/lib/vendor/blamejs/docker-compose.test.yml +545 -0
- package/lib/vendor/blamejs/docs/cis-postgres-crosswalk.md +102 -0
- package/lib/vendor/blamejs/docs/cis-sqlite-equivalent.md +92 -0
- package/lib/vendor/blamejs/eslint.config.mjs +204 -0
- package/lib/vendor/blamejs/examples/wiki/Caddyfile +40 -0
- package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +218 -0
- package/lib/vendor/blamejs/examples/wiki/Dockerfile +120 -0
- package/lib/vendor/blamejs/examples/wiki/README.md +157 -0
- package/lib/vendor/blamejs/examples/wiki/cli-snapshot.json +250 -0
- package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +231 -0
- package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +166 -0
- package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +217 -0
- package/lib/vendor/blamejs/examples/wiki/lib/auto-site-entries.js +139 -0
- package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +555 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-cli.js +507 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-env-vars.js +435 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-errors.js +282 -0
- package/lib/vendor/blamejs/examples/wiki/lib/harvest-vendored-deps.js +321 -0
- package/lib/vendor/blamejs/examples/wiki/lib/nav.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/lib/opts-resolver.js +75 -0
- package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +508 -0
- package/lib/vendor/blamejs/examples/wiki/lib/section.js +276 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +587 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +318 -0
- package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +122 -0
- package/lib/vendor/blamejs/examples/wiki/migrations/0001-pages-schema.js +74 -0
- package/lib/vendor/blamejs/examples/wiki/package.json +18 -0
- package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.png +0 -0
- package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.svg +129 -0
- package/lib/vendor/blamejs/examples/wiki/public/robots.txt +5 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/MANIFEST.json +30 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.css +1 -0
- package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/public/wiki.css +1250 -0
- package/lib/vendor/blamejs/examples/wiki/routes/admin.js +366 -0
- package/lib/vendor/blamejs/examples/wiki/routes/integration.js +230 -0
- package/lib/vendor/blamejs/examples/wiki/routes/pages.js +266 -0
- package/lib/vendor/blamejs/examples/wiki/scripts/backfill-module-metadata.js +214 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/0001-default-pages.js +35 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/_index.js +34 -0
- package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/api.js +76 -0
- package/lib/vendor/blamejs/examples/wiki/server.js +129 -0
- package/lib/vendor/blamejs/examples/wiki/site.config.js +197 -0
- package/lib/vendor/blamejs/examples/wiki/snippets/README.md +38 -0
- package/lib/vendor/blamejs/examples/wiki/snippets/auth/password-hash.example.js +15 -0
- package/lib/vendor/blamejs/examples/wiki/src/editor.js +103 -0
- package/lib/vendor/blamejs/examples/wiki/src/wiki.js +349 -0
- package/lib/vendor/blamejs/examples/wiki/test/AUDIT.md +155 -0
- package/lib/vendor/blamejs/examples/wiki/test/codebase-patterns.test.js +594 -0
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +741 -0
- package/lib/vendor/blamejs/examples/wiki/test/find-missing-pages.js +254 -0
- package/lib/vendor/blamejs/examples/wiki/test/integration.js +391 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-cli-snapshot.js +379 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-env-snapshot.js +346 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-nav-coverage.js +212 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-site-coverage.js +252 -0
- package/lib/vendor/blamejs/examples/wiki/test/validate-source-comment-blocks.js +107 -0
- package/lib/vendor/blamejs/examples/wiki/views/_layout.html +115 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/api-keys.html +51 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/dashboard.html +22 -0
- package/lib/vendor/blamejs/examples/wiki/views/admin/edit.html +17 -0
- package/lib/vendor/blamejs/examples/wiki/views/home.html +85 -0
- package/lib/vendor/blamejs/examples/wiki/views/login.html +18 -0
- package/lib/vendor/blamejs/examples/wiki/views/page.html +5 -0
- package/lib/vendor/blamejs/examples/wiki/views/partials/nav.html +13 -0
- package/lib/vendor/blamejs/examples/wiki/views/search.html +19 -0
- package/lib/vendor/blamejs/examples/wiki/wiki.config.js +15 -0
- package/lib/vendor/blamejs/fuzz/README.md +137 -0
- package/lib/vendor/blamejs/fuzz/_expected.js +35 -0
- package/lib/vendor/blamejs/fuzz/guard-agent-registry.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-csv.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/01-basic.csv +3 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/02-formula.csv +1 -0
- package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/03-hyperlink.csv +1 -0
- package/lib/vendor/blamejs/fuzz/guard-dsn.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-email.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-email_seed_corpus/01-basic.eml +5 -0
- package/lib/vendor/blamejs/fuzz/guard-envelope.fuzz.js +24 -0
- package/lib/vendor/blamejs/fuzz/guard-event-bus-payload.fuzz.js +24 -0
- package/lib/vendor/blamejs/fuzz/guard-event-bus-topic.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-html.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/01-basic.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/02-script.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/03-event.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/04-jsurl.html +1 -0
- package/lib/vendor/blamejs/fuzz/guard-idempotency-key.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-imap-command.fuzz.js +35 -0
- package/lib/vendor/blamejs/fuzz/guard-jmap.fuzz.js +41 -0
- package/lib/vendor/blamejs/fuzz/guard-json.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/01-basic.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/02-proto.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/03-dupkey.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/04-nan.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/05-bom.json +1 -0
- package/lib/vendor/blamejs/fuzz/guard-list-id.fuzz.js +21 -0
- package/lib/vendor/blamejs/fuzz/guard-list-unsubscribe.fuzz.js +25 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-compose.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-move.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-query.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-reply.fuzz.js +23 -0
- package/lib/vendor/blamejs/fuzz/guard-mail-sieve.fuzz.js +36 -0
- package/lib/vendor/blamejs/fuzz/guard-managesieve-command.fuzz.js +26 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/01-basic.md +2 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/02-jsurl.md +1 -0
- package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/03-jsimg.md +1 -0
- package/lib/vendor/blamejs/fuzz/guard-message-id.fuzz.js +26 -0
- package/lib/vendor/blamejs/fuzz/guard-pop3-command.fuzz.js +23 -0
- package/lib/vendor/blamejs/fuzz/guard-posture-chain.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-saga-config.fuzz.js +32 -0
- package/lib/vendor/blamejs/fuzz/guard-smtp-command.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/guard-snapshot-envelope.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-stream-args.fuzz.js +22 -0
- package/lib/vendor/blamejs/fuzz/guard-svg.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/01-basic.svg +1 -0
- package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/02-script.svg +1 -0
- package/lib/vendor/blamejs/fuzz/guard-tenant-id.fuzz.js +20 -0
- package/lib/vendor/blamejs/fuzz/guard-trace-context.fuzz.js +30 -0
- package/lib/vendor/blamejs/fuzz/guard-xml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/01-basic.xml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/02-xxe.xml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/01-basic.yaml +2 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/02-anchor.yaml +2 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/03-norway.yaml +1 -0
- package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/04-multidoc.yaml +4 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-ini.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-ini_seed_corpus/01-basic.ini +2 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-toml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-toml_seed_corpus/01-basic.toml +4 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-xml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-xml_seed_corpus/01-basic.xml +1 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-yaml.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/parsers__safe-yaml_seed_corpus/01-basic.yaml +4 -0
- package/lib/vendor/blamejs/fuzz/safe-decompress.fuzz.js +49 -0
- package/lib/vendor/blamejs/fuzz/safe-dns.fuzz.js +29 -0
- package/lib/vendor/blamejs/fuzz/safe-ical.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-icap.fuzz.js +42 -0
- package/lib/vendor/blamejs/fuzz/safe-json.fuzz.js +25 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/01-object.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/02-array.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/03-string.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/04-proto.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/05-deep.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/01-basic.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/02-filter.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/03-deepscan.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/04-slice.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-mime.fuzz.js +27 -0
- package/lib/vendor/blamejs/fuzz/safe-mount-info.fuzz.js +33 -0
- package/lib/vendor/blamejs/fuzz/safe-sieve.fuzz.js +28 -0
- package/lib/vendor/blamejs/fuzz/safe-smtp.fuzz.js +64 -0
- package/lib/vendor/blamejs/fuzz/safe-url.fuzz.js +16 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/01-basic.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/02-userinfo.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/03-dangerous.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/04-data.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/05-ipv6.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/06-idn.txt +1 -0
- package/lib/vendor/blamejs/fuzz/safe-vcard.fuzz.js +16 -0
- package/lib/vendor/blamejs/index.js +678 -0
- package/lib/vendor/blamejs/keys/release-pqc-pub.json +7 -0
- package/lib/vendor/blamejs/lib/_test/crypto-fixtures.js +67 -0
- package/lib/vendor/blamejs/lib/a2a-tasks.js +598 -0
- package/lib/vendor/blamejs/lib/a2a.js +407 -0
- package/lib/vendor/blamejs/lib/acme.js +1448 -0
- package/lib/vendor/blamejs/lib/agent-audit.js +45 -0
- package/lib/vendor/blamejs/lib/agent-event-bus.js +382 -0
- package/lib/vendor/blamejs/lib/agent-idempotency.js +497 -0
- package/lib/vendor/blamejs/lib/agent-orchestrator.js +717 -0
- package/lib/vendor/blamejs/lib/agent-posture-chain.js +366 -0
- package/lib/vendor/blamejs/lib/agent-saga.js +321 -0
- package/lib/vendor/blamejs/lib/agent-snapshot.js +676 -0
- package/lib/vendor/blamejs/lib/agent-stream.js +269 -0
- package/lib/vendor/blamejs/lib/agent-tenant.js +632 -0
- package/lib/vendor/blamejs/lib/agent-trace.js +281 -0
- package/lib/vendor/blamejs/lib/ai-adverse-decision.js +184 -0
- package/lib/vendor/blamejs/lib/ai-content-detect.js +268 -0
- package/lib/vendor/blamejs/lib/ai-input.js +201 -0
- package/lib/vendor/blamejs/lib/ai-model-manifest.js +363 -0
- package/lib/vendor/blamejs/lib/ai-pref.js +340 -0
- package/lib/vendor/blamejs/lib/api-key.js +721 -0
- package/lib/vendor/blamejs/lib/api-snapshot.js +458 -0
- package/lib/vendor/blamejs/lib/app-shutdown.js +557 -0
- package/lib/vendor/blamejs/lib/app.js +365 -0
- package/lib/vendor/blamejs/lib/archive.js +547 -0
- package/lib/vendor/blamejs/lib/arg-parser.js +697 -0
- package/lib/vendor/blamejs/lib/argon2-builtin.js +173 -0
- package/lib/vendor/blamejs/lib/asn1-der.js +424 -0
- package/lib/vendor/blamejs/lib/asyncapi-bindings.js +160 -0
- package/lib/vendor/blamejs/lib/asyncapi-traits.js +143 -0
- package/lib/vendor/blamejs/lib/asyncapi.js +575 -0
- package/lib/vendor/blamejs/lib/atomic-file.js +1023 -0
- package/lib/vendor/blamejs/lib/audit-chain.js +266 -0
- package/lib/vendor/blamejs/lib/audit-daily-review.js +389 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +751 -0
- package/lib/vendor/blamejs/lib/audit-tools.js +1113 -0
- package/lib/vendor/blamejs/lib/audit.js +1671 -0
- package/lib/vendor/blamejs/lib/auth/aal.js +169 -0
- package/lib/vendor/blamejs/lib/auth/access-lock.js +220 -0
- package/lib/vendor/blamejs/lib/auth/acr-vocabulary.js +265 -0
- package/lib/vendor/blamejs/lib/auth/ato-kill-switch.js +112 -0
- package/lib/vendor/blamejs/lib/auth/auth-time-tracker.js +111 -0
- package/lib/vendor/blamejs/lib/auth/bot-challenge.js +573 -0
- package/lib/vendor/blamejs/lib/auth/ciba.js +637 -0
- package/lib/vendor/blamejs/lib/auth/dpop.js +516 -0
- package/lib/vendor/blamejs/lib/auth/elevation-grant.js +306 -0
- package/lib/vendor/blamejs/lib/auth/fal.js +229 -0
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +681 -0
- package/lib/vendor/blamejs/lib/auth/jwt-external.js +519 -0
- package/lib/vendor/blamejs/lib/auth/jwt.js +430 -0
- package/lib/vendor/blamejs/lib/auth/lockout.js +449 -0
- package/lib/vendor/blamejs/lib/auth/oauth.js +2141 -0
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +657 -0
- package/lib/vendor/blamejs/lib/auth/oid4vp.js +531 -0
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +600 -0
- package/lib/vendor/blamejs/lib/auth/passkey.js +676 -0
- package/lib/vendor/blamejs/lib/auth/password.js +693 -0
- package/lib/vendor/blamejs/lib/auth/saml.js +2109 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-disclosure.js +95 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +225 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +197 -0
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +728 -0
- package/lib/vendor/blamejs/lib/auth/status-list.js +272 -0
- package/lib/vendor/blamejs/lib/auth/step-up-policy.js +335 -0
- package/lib/vendor/blamejs/lib/auth/step-up.js +454 -0
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +505 -0
- package/lib/vendor/blamejs/lib/auth-header.js +148 -0
- package/lib/vendor/blamejs/lib/backup/bundle.js +265 -0
- package/lib/vendor/blamejs/lib/backup/crypto.js +176 -0
- package/lib/vendor/blamejs/lib/backup/index.js +1001 -0
- package/lib/vendor/blamejs/lib/backup/manifest.js +443 -0
- package/lib/vendor/blamejs/lib/boot-gates.js +174 -0
- package/lib/vendor/blamejs/lib/breach-deadline.js +272 -0
- package/lib/vendor/blamejs/lib/break-glass.js +1753 -0
- package/lib/vendor/blamejs/lib/budr.js +205 -0
- package/lib/vendor/blamejs/lib/bundler.js +461 -0
- package/lib/vendor/blamejs/lib/cache-redis.js +256 -0
- package/lib/vendor/blamejs/lib/cache-status.js +288 -0
- package/lib/vendor/blamejs/lib/cache.js +1331 -0
- package/lib/vendor/blamejs/lib/calendar.js +1240 -0
- package/lib/vendor/blamejs/lib/canonical-json.js +143 -0
- package/lib/vendor/blamejs/lib/cdn-cache-control.js +473 -0
- package/lib/vendor/blamejs/lib/cert.js +763 -0
- package/lib/vendor/blamejs/lib/chain-writer.js +259 -0
- package/lib/vendor/blamejs/lib/circuit-breaker.js +101 -0
- package/lib/vendor/blamejs/lib/cli-helpers.js +237 -0
- package/lib/vendor/blamejs/lib/cli.js +2328 -0
- package/lib/vendor/blamejs/lib/client-hints.js +318 -0
- package/lib/vendor/blamejs/lib/cloud-events.js +277 -0
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +317 -0
- package/lib/vendor/blamejs/lib/cluster-storage.js +351 -0
- package/lib/vendor/blamejs/lib/cluster.js +1017 -0
- package/lib/vendor/blamejs/lib/cms-codec.js +826 -0
- package/lib/vendor/blamejs/lib/codepoint-class.js +262 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +190 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +205 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-risk.js +189 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +200 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act.js +821 -0
- package/lib/vendor/blamejs/lib/compliance-eaa.js +204 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-aliases.js +167 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +206 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions-fuzzy.js +297 -0
- package/lib/vendor/blamejs/lib/compliance-sanctions.js +569 -0
- package/lib/vendor/blamejs/lib/compliance.js +1558 -0
- package/lib/vendor/blamejs/lib/config-drift.js +426 -0
- package/lib/vendor/blamejs/lib/config.js +446 -0
- package/lib/vendor/blamejs/lib/consent.js +369 -0
- package/lib/vendor/blamejs/lib/constants.js +209 -0
- package/lib/vendor/blamejs/lib/content-credentials.js +704 -0
- package/lib/vendor/blamejs/lib/cookies.js +560 -0
- package/lib/vendor/blamejs/lib/cra-report.js +299 -0
- package/lib/vendor/blamejs/lib/credential-hash.js +394 -0
- package/lib/vendor/blamejs/lib/crypto-field.js +1017 -0
- package/lib/vendor/blamejs/lib/crypto-hpke-pq.js +187 -0
- package/lib/vendor/blamejs/lib/crypto-hpke.js +256 -0
- package/lib/vendor/blamejs/lib/crypto.js +1908 -0
- package/lib/vendor/blamejs/lib/csp.js +271 -0
- package/lib/vendor/blamejs/lib/csv.js +418 -0
- package/lib/vendor/blamejs/lib/daemon.js +481 -0
- package/lib/vendor/blamejs/lib/dark-patterns.js +488 -0
- package/lib/vendor/blamejs/lib/data-act.js +328 -0
- package/lib/vendor/blamejs/lib/db-collection.js +587 -0
- package/lib/vendor/blamejs/lib/db-declare-row-policy.js +267 -0
- package/lib/vendor/blamejs/lib/db-declare-view.js +420 -0
- package/lib/vendor/blamejs/lib/db-file-lifecycle.js +333 -0
- package/lib/vendor/blamejs/lib/db-query.js +802 -0
- package/lib/vendor/blamejs/lib/db-role-context.js +50 -0
- package/lib/vendor/blamejs/lib/db-schema.js +322 -0
- package/lib/vendor/blamejs/lib/db.js +3111 -0
- package/lib/vendor/blamejs/lib/dbsc.js +299 -0
- package/lib/vendor/blamejs/lib/ddl-change-control.js +523 -0
- package/lib/vendor/blamejs/lib/deprecate.js +377 -0
- package/lib/vendor/blamejs/lib/dev.js +405 -0
- package/lib/vendor/blamejs/lib/dora.js +402 -0
- package/lib/vendor/blamejs/lib/dr-runbook.js +368 -0
- package/lib/vendor/blamejs/lib/dsr.js +1188 -0
- package/lib/vendor/blamejs/lib/dual-control.js +526 -0
- package/lib/vendor/blamejs/lib/early-hints.js +212 -0
- package/lib/vendor/blamejs/lib/error-page.js +420 -0
- package/lib/vendor/blamejs/lib/events.js +214 -0
- package/lib/vendor/blamejs/lib/external-db-migrate.js +659 -0
- package/lib/vendor/blamejs/lib/external-db.js +1877 -0
- package/lib/vendor/blamejs/lib/fapi2.js +394 -0
- package/lib/vendor/blamejs/lib/fda-21cfr11.js +395 -0
- package/lib/vendor/blamejs/lib/fdx.js +370 -0
- package/lib/vendor/blamejs/lib/fedcm.js +264 -0
- package/lib/vendor/blamejs/lib/file-type.js +360 -0
- package/lib/vendor/blamejs/lib/file-upload.js +1256 -0
- package/lib/vendor/blamejs/lib/flag-cache.js +136 -0
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +135 -0
- package/lib/vendor/blamejs/lib/flag-providers.js +279 -0
- package/lib/vendor/blamejs/lib/flag-targeting.js +210 -0
- package/lib/vendor/blamejs/lib/flag.js +346 -0
- package/lib/vendor/blamejs/lib/forms.js +525 -0
- package/lib/vendor/blamejs/lib/framework-error.js +724 -0
- package/lib/vendor/blamejs/lib/framework-schema.js +845 -0
- package/lib/vendor/blamejs/lib/framework-sha1-hibp.js +34 -0
- package/lib/vendor/blamejs/lib/fsm.js +469 -0
- package/lib/vendor/blamejs/lib/gate-contract.js +1661 -0
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +261 -0
- package/lib/vendor/blamejs/lib/graphql-federation.js +234 -0
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +179 -0
- package/lib/vendor/blamejs/lib/guard-all.js +555 -0
- package/lib/vendor/blamejs/lib/guard-archive.js +901 -0
- package/lib/vendor/blamejs/lib/guard-auth.js +451 -0
- package/lib/vendor/blamejs/lib/guard-cidr.js +676 -0
- package/lib/vendor/blamejs/lib/guard-csv.js +1176 -0
- package/lib/vendor/blamejs/lib/guard-domain.js +814 -0
- package/lib/vendor/blamejs/lib/guard-dsn.js +382 -0
- package/lib/vendor/blamejs/lib/guard-email.js +951 -0
- package/lib/vendor/blamejs/lib/guard-envelope.js +294 -0
- package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +217 -0
- package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +150 -0
- package/lib/vendor/blamejs/lib/guard-filename.js +956 -0
- package/lib/vendor/blamejs/lib/guard-graphql.js +731 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-aria.js +164 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-forms.js +144 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-tables.js +154 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag-tagwalk.js +44 -0
- package/lib/vendor/blamejs/lib/guard-html-wcag.js +470 -0
- package/lib/vendor/blamejs/lib/guard-html.js +1209 -0
- package/lib/vendor/blamejs/lib/guard-idempotency-key.js +151 -0
- package/lib/vendor/blamejs/lib/guard-image.js +584 -0
- package/lib/vendor/blamejs/lib/guard-imap-command.js +337 -0
- package/lib/vendor/blamejs/lib/guard-jmap.js +321 -0
- package/lib/vendor/blamejs/lib/guard-json.js +935 -0
- package/lib/vendor/blamejs/lib/guard-jsonpath.js +512 -0
- package/lib/vendor/blamejs/lib/guard-jwt.js +772 -0
- package/lib/vendor/blamejs/lib/guard-list-id.js +318 -0
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +412 -0
- package/lib/vendor/blamejs/lib/guard-mail-compose.js +282 -0
- package/lib/vendor/blamejs/lib/guard-mail-move.js +202 -0
- package/lib/vendor/blamejs/lib/guard-mail-query.js +310 -0
- package/lib/vendor/blamejs/lib/guard-mail-reply.js +172 -0
- package/lib/vendor/blamejs/lib/guard-mail-sieve.js +207 -0
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +566 -0
- package/lib/vendor/blamejs/lib/guard-markdown.js +768 -0
- package/lib/vendor/blamejs/lib/guard-message-id.js +267 -0
- package/lib/vendor/blamejs/lib/guard-mime.js +609 -0
- package/lib/vendor/blamejs/lib/guard-oauth.js +650 -0
- package/lib/vendor/blamejs/lib/guard-pdf.js +569 -0
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +317 -0
- package/lib/vendor/blamejs/lib/guard-posture-chain.js +201 -0
- package/lib/vendor/blamejs/lib/guard-regex.js +632 -0
- package/lib/vendor/blamejs/lib/guard-saga-config.js +157 -0
- package/lib/vendor/blamejs/lib/guard-shell.js +522 -0
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +594 -0
- package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +168 -0
- package/lib/vendor/blamejs/lib/guard-stream-args.js +166 -0
- package/lib/vendor/blamejs/lib/guard-svg.js +1163 -0
- package/lib/vendor/blamejs/lib/guard-template.js +490 -0
- package/lib/vendor/blamejs/lib/guard-tenant-id.js +138 -0
- package/lib/vendor/blamejs/lib/guard-time.js +586 -0
- package/lib/vendor/blamejs/lib/guard-trace-context.js +172 -0
- package/lib/vendor/blamejs/lib/guard-uuid.js +548 -0
- package/lib/vendor/blamejs/lib/guard-xml.js +666 -0
- package/lib/vendor/blamejs/lib/guard-yaml.js +726 -0
- package/lib/vendor/blamejs/lib/hal.js +125 -0
- package/lib/vendor/blamejs/lib/handlers.js +350 -0
- package/lib/vendor/blamejs/lib/honeytoken.js +168 -0
- package/lib/vendor/blamejs/lib/html-balance.js +347 -0
- package/lib/vendor/blamejs/lib/http-client-cache.js +923 -0
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +519 -0
- package/lib/vendor/blamejs/lib/http-client.js +2152 -0
- package/lib/vendor/blamejs/lib/http-message-signature.js +589 -0
- package/lib/vendor/blamejs/lib/http2-teardown.js +34 -0
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +398 -0
- package/lib/vendor/blamejs/lib/i18n.js +931 -0
- package/lib/vendor/blamejs/lib/iab-mspa.js +257 -0
- package/lib/vendor/blamejs/lib/iab-tcf.js +461 -0
- package/lib/vendor/blamejs/lib/importmap-integrity.js +90 -0
- package/lib/vendor/blamejs/lib/inbox.js +435 -0
- package/lib/vendor/blamejs/lib/incident-report.js +314 -0
- package/lib/vendor/blamejs/lib/ip-utils.js +102 -0
- package/lib/vendor/blamejs/lib/jobs.js +185 -0
- package/lib/vendor/blamejs/lib/jose-jwe-experimental.js +228 -0
- package/lib/vendor/blamejs/lib/jsonapi.js +230 -0
- package/lib/vendor/blamejs/lib/keychain.js +865 -0
- package/lib/vendor/blamejs/lib/lazy-require.js +48 -0
- package/lib/vendor/blamejs/lib/legal-hold.js +374 -0
- package/lib/vendor/blamejs/lib/local-db-thin.js +321 -0
- package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +369 -0
- package/lib/vendor/blamejs/lib/log-stream-local.js +146 -0
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +410 -0
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +286 -0
- package/lib/vendor/blamejs/lib/log-stream-syslog.js +310 -0
- package/lib/vendor/blamejs/lib/log-stream-webhook.js +199 -0
- package/lib/vendor/blamejs/lib/log-stream.js +584 -0
- package/lib/vendor/blamejs/lib/log.js +625 -0
- package/lib/vendor/blamejs/lib/lro.js +200 -0
- package/lib/vendor/blamejs/lib/mail-agent.js +786 -0
- package/lib/vendor/blamejs/lib/mail-arc-sign.js +417 -0
- package/lib/vendor/blamejs/lib/mail-arf.js +343 -0
- package/lib/vendor/blamejs/lib/mail-auth.js +2144 -0
- package/lib/vendor/blamejs/lib/mail-bimi.js +1047 -0
- package/lib/vendor/blamejs/lib/mail-bounce.js +955 -0
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +1286 -0
- package/lib/vendor/blamejs/lib/mail-crypto-smime.js +789 -0
- package/lib/vendor/blamejs/lib/mail-crypto.js +108 -0
- package/lib/vendor/blamejs/lib/mail-dav.js +1224 -0
- package/lib/vendor/blamejs/lib/mail-deploy.js +1119 -0
- package/lib/vendor/blamejs/lib/mail-dkim.js +1250 -0
- package/lib/vendor/blamejs/lib/mail-greylist.js +448 -0
- package/lib/vendor/blamejs/lib/mail-helo.js +473 -0
- package/lib/vendor/blamejs/lib/mail-journal.js +435 -0
- package/lib/vendor/blamejs/lib/mail-mdn.js +424 -0
- package/lib/vendor/blamejs/lib/mail-rbl.js +392 -0
- package/lib/vendor/blamejs/lib/mail-require-tls.js +198 -0
- package/lib/vendor/blamejs/lib/mail-scan.js +502 -0
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +629 -0
- package/lib/vendor/blamejs/lib/mail-server-imap.js +1858 -0
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +1565 -0
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +908 -0
- package/lib/vendor/blamejs/lib/mail-server-mx.js +969 -0
- package/lib/vendor/blamejs/lib/mail-server-pop3.js +915 -0
- package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +315 -0
- package/lib/vendor/blamejs/lib/mail-server-registry.js +378 -0
- package/lib/vendor/blamejs/lib/mail-server-submission.js +1396 -0
- package/lib/vendor/blamejs/lib/mail-server-tls.js +445 -0
- package/lib/vendor/blamejs/lib/mail-sieve.js +557 -0
- package/lib/vendor/blamejs/lib/mail-spam-score.js +284 -0
- package/lib/vendor/blamejs/lib/mail-srs.js +248 -0
- package/lib/vendor/blamejs/lib/mail-store-fts.js +394 -0
- package/lib/vendor/blamejs/lib/mail-store.js +929 -0
- package/lib/vendor/blamejs/lib/mail-unsubscribe.js +400 -0
- package/lib/vendor/blamejs/lib/mail.js +1971 -0
- package/lib/vendor/blamejs/lib/mcp-tool-registry.js +473 -0
- package/lib/vendor/blamejs/lib/mcp.js +950 -0
- package/lib/vendor/blamejs/lib/metrics.js +1503 -0
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +177 -0
- package/lib/vendor/blamejs/lib/middleware/ai-act-disclosure.js +203 -0
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +981 -0
- package/lib/vendor/blamejs/lib/middleware/assetlinks.js +137 -0
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +171 -0
- package/lib/vendor/blamejs/lib/middleware/attach-user.js +220 -0
- package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +293 -0
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +1519 -0
- package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +183 -0
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +217 -0
- package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +122 -0
- package/lib/vendor/blamejs/lib/middleware/compose-pipeline.js +355 -0
- package/lib/vendor/blamejs/lib/middleware/compression.js +489 -0
- package/lib/vendor/blamejs/lib/middleware/cookies.js +130 -0
- package/lib/vendor/blamejs/lib/middleware/cors.js +386 -0
- package/lib/vendor/blamejs/lib/middleware/csp-nonce.js +388 -0
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +167 -0
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +499 -0
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +243 -0
- package/lib/vendor/blamejs/lib/middleware/db-role-for.js +304 -0
- package/lib/vendor/blamejs/lib/middleware/dpop.js +402 -0
- package/lib/vendor/blamejs/lib/middleware/error-handler.js +69 -0
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +168 -0
- package/lib/vendor/blamejs/lib/middleware/flag-context.js +110 -0
- package/lib/vendor/blamejs/lib/middleware/gpc.js +153 -0
- package/lib/vendor/blamejs/lib/middleware/headers.js +242 -0
- package/lib/vendor/blamejs/lib/middleware/health.js +438 -0
- package/lib/vendor/blamejs/lib/middleware/host-allowlist.js +189 -0
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +964 -0
- package/lib/vendor/blamejs/lib/middleware/index.js +183 -0
- package/lib/vendor/blamejs/lib/middleware/nel.js +214 -0
- package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +237 -0
- package/lib/vendor/blamejs/lib/middleware/no-cache.js +106 -0
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +177 -0
- package/lib/vendor/blamejs/lib/middleware/protected-resource-metadata.js +277 -0
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +556 -0
- package/lib/vendor/blamejs/lib/middleware/request-id.js +79 -0
- package/lib/vendor/blamejs/lib/middleware/request-log.js +205 -0
- package/lib/vendor/blamejs/lib/middleware/require-aal.js +138 -0
- package/lib/vendor/blamejs/lib/middleware/require-auth.js +144 -0
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +290 -0
- package/lib/vendor/blamejs/lib/middleware/require-content-type.js +113 -0
- package/lib/vendor/blamejs/lib/middleware/require-methods.js +97 -0
- package/lib/vendor/blamejs/lib/middleware/require-mtls.js +212 -0
- package/lib/vendor/blamejs/lib/middleware/require-step-up.js +226 -0
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +375 -0
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +285 -0
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +170 -0
- package/lib/vendor/blamejs/lib/middleware/span-http-server.js +280 -0
- package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +323 -0
- package/lib/vendor/blamejs/lib/middleware/sse.js +200 -0
- package/lib/vendor/blamejs/lib/middleware/trace-log-correlation.js +167 -0
- package/lib/vendor/blamejs/lib/middleware/trace-propagate.js +148 -0
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +749 -0
- package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +164 -0
- package/lib/vendor/blamejs/lib/migration-files.js +37 -0
- package/lib/vendor/blamejs/lib/migrations.js +385 -0
- package/lib/vendor/blamejs/lib/mime-parse.js +198 -0
- package/lib/vendor/blamejs/lib/money.js +699 -0
- package/lib/vendor/blamejs/lib/mtls-ca.js +572 -0
- package/lib/vendor/blamejs/lib/mtls-engine-default.js +501 -0
- package/lib/vendor/blamejs/lib/network-byte-quota.js +308 -0
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +533 -0
- package/lib/vendor/blamejs/lib/network-dns.js +1930 -0
- package/lib/vendor/blamejs/lib/network-heartbeat.js +425 -0
- package/lib/vendor/blamejs/lib/network-nts.js +574 -0
- package/lib/vendor/blamejs/lib/network-proxy.js +265 -0
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +836 -0
- package/lib/vendor/blamejs/lib/network-tls.js +3126 -0
- package/lib/vendor/blamejs/lib/network.js +346 -0
- package/lib/vendor/blamejs/lib/nis2-report.js +181 -0
- package/lib/vendor/blamejs/lib/nist-crosswalk.js +293 -0
- package/lib/vendor/blamejs/lib/nonce-store.js +177 -0
- package/lib/vendor/blamejs/lib/notify.js +683 -0
- package/lib/vendor/blamejs/lib/ntp-check.js +458 -0
- package/lib/vendor/blamejs/lib/numeric-bounds.js +111 -0
- package/lib/vendor/blamejs/lib/numeric-checks.js +40 -0
- package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +349 -0
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +488 -0
- package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +351 -0
- package/lib/vendor/blamejs/lib/object-store/gcs.js +515 -0
- package/lib/vendor/blamejs/lib/object-store/http-put.js +153 -0
- package/lib/vendor/blamejs/lib/object-store/http-request.js +38 -0
- package/lib/vendor/blamejs/lib/object-store/index.js +197 -0
- package/lib/vendor/blamejs/lib/object-store/local.js +163 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +1133 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +957 -0
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +420 -0
- package/lib/vendor/blamejs/lib/observability-tracer.js +395 -0
- package/lib/vendor/blamejs/lib/observability.js +720 -0
- package/lib/vendor/blamejs/lib/openapi-paths-builder.js +248 -0
- package/lib/vendor/blamejs/lib/openapi-schema-walk.js +192 -0
- package/lib/vendor/blamejs/lib/openapi-security.js +169 -0
- package/lib/vendor/blamejs/lib/openapi-yaml.js +154 -0
- package/lib/vendor/blamejs/lib/openapi.js +489 -0
- package/lib/vendor/blamejs/lib/otel-export.js +278 -0
- package/lib/vendor/blamejs/lib/outbox.js +547 -0
- package/lib/vendor/blamejs/lib/pagination.js +542 -0
- package/lib/vendor/blamejs/lib/parsers/index.js +91 -0
- package/lib/vendor/blamejs/lib/parsers/safe-env.js +642 -0
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +293 -0
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +784 -0
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +390 -0
- package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +1015 -0
- package/lib/vendor/blamejs/lib/permissions.js +793 -0
- package/lib/vendor/blamejs/lib/pick.js +105 -0
- package/lib/vendor/blamejs/lib/pqc-agent.js +351 -0
- package/lib/vendor/blamejs/lib/pqc-gate.js +279 -0
- package/lib/vendor/blamejs/lib/pqc-software.js +271 -0
- package/lib/vendor/blamejs/lib/problem-details.js +482 -0
- package/lib/vendor/blamejs/lib/process-spawn.js +196 -0
- package/lib/vendor/blamejs/lib/promise-pool.js +162 -0
- package/lib/vendor/blamejs/lib/protobuf-encoder.js +190 -0
- package/lib/vendor/blamejs/lib/protocol-dispatcher.js +161 -0
- package/lib/vendor/blamejs/lib/public-suffix.js +403 -0
- package/lib/vendor/blamejs/lib/pubsub-cluster.js +154 -0
- package/lib/vendor/blamejs/lib/pubsub-redis.js +167 -0
- package/lib/vendor/blamejs/lib/pubsub.js +463 -0
- package/lib/vendor/blamejs/lib/queue-local.js +476 -0
- package/lib/vendor/blamejs/lib/queue-redis.js +745 -0
- package/lib/vendor/blamejs/lib/queue-sqs.js +319 -0
- package/lib/vendor/blamejs/lib/queue.js +1016 -0
- package/lib/vendor/blamejs/lib/redact.js +1007 -0
- package/lib/vendor/blamejs/lib/redis-client.js +520 -0
- package/lib/vendor/blamejs/lib/render.js +285 -0
- package/lib/vendor/blamejs/lib/request-helpers.js +767 -0
- package/lib/vendor/blamejs/lib/resource-access-lock.js +116 -0
- package/lib/vendor/blamejs/lib/restore-bundle.js +340 -0
- package/lib/vendor/blamejs/lib/restore-rollback.js +365 -0
- package/lib/vendor/blamejs/lib/restore.js +409 -0
- package/lib/vendor/blamejs/lib/retention.js +640 -0
- package/lib/vendor/blamejs/lib/retry.js +523 -0
- package/lib/vendor/blamejs/lib/router.js +1289 -0
- package/lib/vendor/blamejs/lib/safe-async.js +1184 -0
- package/lib/vendor/blamejs/lib/safe-buffer.js +562 -0
- package/lib/vendor/blamejs/lib/safe-decompress.js +297 -0
- package/lib/vendor/blamejs/lib/safe-dns.js +665 -0
- package/lib/vendor/blamejs/lib/safe-ical.js +634 -0
- package/lib/vendor/blamejs/lib/safe-icap.js +502 -0
- package/lib/vendor/blamejs/lib/safe-json.js +946 -0
- package/lib/vendor/blamejs/lib/safe-jsonpath.js +285 -0
- package/lib/vendor/blamejs/lib/safe-mime.js +831 -0
- package/lib/vendor/blamejs/lib/safe-mount-info.js +306 -0
- package/lib/vendor/blamejs/lib/safe-path.js +254 -0
- package/lib/vendor/blamejs/lib/safe-redirect.js +106 -0
- package/lib/vendor/blamejs/lib/safe-schema.js +1810 -0
- package/lib/vendor/blamejs/lib/safe-sieve.js +684 -0
- package/lib/vendor/blamejs/lib/safe-smtp.js +185 -0
- package/lib/vendor/blamejs/lib/safe-sql.js +363 -0
- package/lib/vendor/blamejs/lib/safe-url.js +428 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +473 -0
- package/lib/vendor/blamejs/lib/sandbox-worker.js +135 -0
- package/lib/vendor/blamejs/lib/sandbox.js +358 -0
- package/lib/vendor/blamejs/lib/scheduler.js +827 -0
- package/lib/vendor/blamejs/lib/sd-notify.js +269 -0
- package/lib/vendor/blamejs/lib/sec-cyber.js +214 -0
- package/lib/vendor/blamejs/lib/security-assert.js +395 -0
- package/lib/vendor/blamejs/lib/seeders.js +620 -0
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +309 -0
- package/lib/vendor/blamejs/lib/self-update.js +804 -0
- package/lib/vendor/blamejs/lib/server-timing.js +174 -0
- package/lib/vendor/blamejs/lib/session-device-binding.js +431 -0
- package/lib/vendor/blamejs/lib/session-stores.js +138 -0
- package/lib/vendor/blamejs/lib/session.js +1162 -0
- package/lib/vendor/blamejs/lib/slug.js +381 -0
- package/lib/vendor/blamejs/lib/sse.js +349 -0
- package/lib/vendor/blamejs/lib/ssrf-guard.js +792 -0
- package/lib/vendor/blamejs/lib/standard-webhooks.js +183 -0
- package/lib/vendor/blamejs/lib/static.js +1249 -0
- package/lib/vendor/blamejs/lib/storage.js +1272 -0
- package/lib/vendor/blamejs/lib/stream-throttle.js +235 -0
- package/lib/vendor/blamejs/lib/structured-fields.js +244 -0
- package/lib/vendor/blamejs/lib/subject.js +667 -0
- package/lib/vendor/blamejs/lib/tcpa-10dlc.js +175 -0
- package/lib/vendor/blamejs/lib/template.js +931 -0
- package/lib/vendor/blamejs/lib/tenant-quota.js +545 -0
- package/lib/vendor/blamejs/lib/test-harness.js +275 -0
- package/lib/vendor/blamejs/lib/testing.js +1185 -0
- package/lib/vendor/blamejs/lib/time.js +578 -0
- package/lib/vendor/blamejs/lib/tls-exporter.js +239 -0
- package/lib/vendor/blamejs/lib/totp.js +318 -0
- package/lib/vendor/blamejs/lib/tracing.js +546 -0
- package/lib/vendor/blamejs/lib/uuid.js +207 -0
- package/lib/vendor/blamejs/lib/validate-opts.js +381 -0
- package/lib/vendor/blamejs/lib/vault/index.js +638 -0
- package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +311 -0
- package/lib/vendor/blamejs/lib/vault/passphrase-source.js +198 -0
- package/lib/vendor/blamejs/lib/vault/rotate.js +803 -0
- package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +471 -0
- package/lib/vendor/blamejs/lib/vault/wrap.js +296 -0
- package/lib/vendor/blamejs/lib/vault-aad.js +259 -0
- package/lib/vendor/blamejs/lib/vendor/.vendor-data-pubkey +4 -0
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +161 -0
- package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.data.js +68 -0
- package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.pem +33 -0
- package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.data.js +1325 -0
- package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.txt +10002 -0
- package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +9 -0
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +18 -0
- package/lib/vendor/blamejs/lib/vendor/pki.cjs +181 -0
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +16382 -0
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5881 -0
- package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +328 -0
- package/lib/vendor/blamejs/lib/vendor/vendor-data-pubkey.js +16 -0
- package/lib/vendor/blamejs/lib/vendor-data.js +520 -0
- package/lib/vendor/blamejs/lib/vex.js +630 -0
- package/lib/vendor/blamejs/lib/watcher.js +608 -0
- package/lib/vendor/blamejs/lib/web-push-vapid.js +322 -0
- package/lib/vendor/blamejs/lib/webhook.js +977 -0
- package/lib/vendor/blamejs/lib/websocket-channels.js +327 -0
- package/lib/vendor/blamejs/lib/websocket.js +1561 -0
- package/lib/vendor/blamejs/lib/wiki-concepts.js +338 -0
- package/lib/vendor/blamejs/lib/worker-pool.js +464 -0
- package/lib/vendor/blamejs/lib/ws-client.js +978 -0
- package/lib/vendor/blamejs/lib/xml-c14n.js +506 -0
- package/lib/vendor/blamejs/memory/specs/node-26-map-getorinsert-migration.md +164 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +19 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/README.md +88 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/build.sh +26 -0
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/project.yaml +28 -0
- package/lib/vendor/blamejs/package.json +81 -0
- package/lib/vendor/blamejs/release-notes/v0.0.x.json +310 -0
- package/lib/vendor/blamejs/release-notes/v0.1.x.json +1798 -0
- package/lib/vendor/blamejs/release-notes/v0.10.x.json +1288 -0
- package/lib/vendor/blamejs/release-notes/v0.11.x.json +2551 -0
- package/lib/vendor/blamejs/release-notes/v0.12.0.json +64 -0
- package/lib/vendor/blamejs/release-notes/v0.12.1.json +32 -0
- package/lib/vendor/blamejs/release-notes/v0.12.2.json +45 -0
- package/lib/vendor/blamejs/release-notes/v0.2.x.json +706 -0
- package/lib/vendor/blamejs/release-notes/v0.3.x.json +786 -0
- package/lib/vendor/blamejs/release-notes/v0.4.x.json +588 -0
- package/lib/vendor/blamejs/release-notes/v0.5.x.json +390 -0
- package/lib/vendor/blamejs/release-notes/v0.6.x.json +1947 -0
- package/lib/vendor/blamejs/release-notes/v0.7.x.json +3811 -0
- package/lib/vendor/blamejs/release-notes/v0.8.x.json +3318 -0
- package/lib/vendor/blamejs/release-notes/v0.9.x.json +2257 -0
- package/lib/vendor/blamejs/scripts/build-vendored-sbom.js +325 -0
- package/lib/vendor/blamejs/scripts/check-api-snapshot.js +62 -0
- package/lib/vendor/blamejs/scripts/check-changelog-extract.js +108 -0
- package/lib/vendor/blamejs/scripts/check-pack-against-gitignore.js +83 -0
- package/lib/vendor/blamejs/scripts/check-services.js +483 -0
- package/lib/vendor/blamejs/scripts/check-vendor-currency.js +349 -0
- package/lib/vendor/blamejs/scripts/consolidate-release-notes.js +216 -0
- package/lib/vendor/blamejs/scripts/gen-migrating.js +275 -0
- package/lib/vendor/blamejs/scripts/generate-changelog-entry.js +577 -0
- package/lib/vendor/blamejs/scripts/generate-release-signing-key.js +79 -0
- package/lib/vendor/blamejs/scripts/publish-dep-confusion-placeholder.sh +101 -0
- package/lib/vendor/blamejs/scripts/refresh-api-snapshot.js +31 -0
- package/lib/vendor/blamejs/scripts/refresh-vendor-manifest.js +132 -0
- package/lib/vendor/blamejs/scripts/release.js +652 -0
- package/lib/vendor/blamejs/scripts/sha3-digest.js +62 -0
- package/lib/vendor/blamejs/scripts/sign-release-artifact.js +92 -0
- package/lib/vendor/blamejs/scripts/test-integration.js +181 -0
- package/lib/vendor/blamejs/scripts/test-wiki-integration.js +126 -0
- package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +77 -0
- package/lib/vendor/blamejs/scripts/vendor-data-gen.js +186 -0
- package/lib/vendor/blamejs/scripts/vendor-data-keygen.js +101 -0
- package/lib/vendor/blamejs/scripts/vendor-update.sh +278 -0
- package/lib/vendor/blamejs/test/00-primitives.js +19075 -0
- package/lib/vendor/blamejs/test/10-state.js +622 -0
- package/lib/vendor/blamejs/test/20-db.js +561 -0
- package/lib/vendor/blamejs/test/30-chain.js +2110 -0
- package/lib/vendor/blamejs/test/40-consumers.js +2453 -0
- package/lib/vendor/blamejs/test/50-integration.js +486 -0
- package/lib/vendor/blamejs/test/_helpers.js +10 -0
- package/lib/vendor/blamejs/test/_smoke-worker.js +69 -0
- package/lib/vendor/blamejs/test/fixtures/exploit-corpus/corpus.json +368 -0
- package/lib/vendor/blamejs/test/fixtures/http-client-stream-payload.txt +2 -0
- package/lib/vendor/blamejs/test/fixtures/worker-pool/echo.js +52 -0
- package/lib/vendor/blamejs/test/helpers/_codebase-shingle-worker.js +24 -0
- package/lib/vendor/blamejs/test/helpers/_codebase-shingle.js +203 -0
- package/lib/vendor/blamejs/test/helpers/_shape-match.js +513 -0
- package/lib/vendor/blamejs/test/helpers/check.js +36 -0
- package/lib/vendor/blamejs/test/helpers/cluster.js +70 -0
- package/lib/vendor/blamejs/test/helpers/db.js +143 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +207 -0
- package/lib/vendor/blamejs/test/helpers/fs-watch.js +101 -0
- package/lib/vendor/blamejs/test/helpers/http.js +14 -0
- package/lib/vendor/blamejs/test/helpers/index.js +93 -0
- package/lib/vendor/blamejs/test/helpers/json-round-trip.js +120 -0
- package/lib/vendor/blamejs/test/helpers/mocks.js +20 -0
- package/lib/vendor/blamejs/test/helpers/otel.js +13 -0
- package/lib/vendor/blamejs/test/helpers/services.js +380 -0
- package/lib/vendor/blamejs/test/helpers/wait.js +206 -0
- package/lib/vendor/blamejs/test/integration/cache.test.js +235 -0
- package/lib/vendor/blamejs/test/integration/cluster-provider-mysql.test.js +174 -0
- package/lib/vendor/blamejs/test/integration/federation-auth.test.js +611 -0
- package/lib/vendor/blamejs/test/integration/http-client.test.js +129 -0
- package/lib/vendor/blamejs/test/integration/log-stream.test.js +219 -0
- package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +181 -0
- package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +152 -0
- package/lib/vendor/blamejs/test/integration/mail-smtp.test.js +161 -0
- package/lib/vendor/blamejs/test/integration/mtls-ca.test.js +289 -0
- package/lib/vendor/blamejs/test/integration/network-dns.test.js +123 -0
- package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +101 -0
- package/lib/vendor/blamejs/test/integration/ntp-check.test.js +89 -0
- package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +403 -0
- package/lib/vendor/blamejs/test/integration/pqc-pkcs8-forward-compat.test.js +271 -0
- package/lib/vendor/blamejs/test/integration/pubsub.test.js +137 -0
- package/lib/vendor/blamejs/test/integration/queue-redis.test.js +352 -0
- package/lib/vendor/blamejs/test/integration/redis-client-tls.test.js +96 -0
- package/lib/vendor/blamejs/test/integration/ssrf-guard.test.js +98 -0
- package/lib/vendor/blamejs/test/integration/websocket-permessage-deflate.test.js +261 -0
- package/lib/vendor/blamejs/test/integration/ws-client-roundtrip.test.js +230 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +211 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/access-lock.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +219 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +262 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-orchestrator.test.js +390 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-posture-chain.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +279 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +322 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-stream.test.js +227 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-tenant.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-trace.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-adverse-decision.test.js +44 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-content-detect.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-input.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-model-manifest.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ai-pref.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +1080 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +311 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-zip-stream.test.js +291 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +267 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +108 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asyncapi.test.js +929 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-conflict-path.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-cve-defensive.test.js +176 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-export-cadf.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +141 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-segregation.test.js +115 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-ml-dsa-65.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +246 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge-verifier.test.js +485 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +331 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +352 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +572 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-password-audit.test.js +61 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-bucket-ops.test.js +258 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-worker.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/bearer-auth.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-chunked-malformed.test.js +131 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-smuggling.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/boot-gates.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/breach-deadline.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +861 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/budr.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/bundler-engine.test.js +209 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache-status.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +871 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +891 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/canonical-json-jcs.test.js +43 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cdn-cache-control.test.js +243 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +550 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-audit-verify-chain.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-backup.test.js +135 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-config-drift.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +75 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-file-type.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-helpers.test.js +145 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-mtls.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-password.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-restore.test.js +160 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-retention.test.js +84 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-security.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-vault.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/client-hints.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +237 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +9600 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-cascade.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-eaa.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +712 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/config-drift.test.js +97 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/config.test.js +424 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +357 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cra-report.test.js +31 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-envelope.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +193 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke-pq.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke.test.js +155 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-mlkem768-x25519.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-namespace-hash.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-random-int.test.js +72 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +210 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daily-byte-quota.test.js +153 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-collection-extensions.test.js +226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-collection.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-init-extensions.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-extensions.test.js +191 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-role-for.test.js +228 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-vacuum.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +184 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/declare-row-policy.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/declare-view.test.js +303 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dns-dnssec-algorithm.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dns-null-mx.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dr-runbook.test.js +59 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr-state-rules.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +786 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/early-hints.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/events.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/exploit-replay.test.js +243 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +181 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-routing.test.js +531 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fapi2.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +156 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fdx.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +434 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +432 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/file-type.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +887 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/forensic-snapshot.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fsm.test.js +375 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gcs-bucket-ops.test.js +321 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +41 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-agent-registry.test.js +87 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-all.test.js +328 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +339 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +694 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-dsn.test.js +296 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +234 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-envelope.test.js +192 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-payload.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-topic.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +386 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html-wcag.test.js +859 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +357 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +317 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-id.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-unsubscribe.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-compose.test.js +111 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-move.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-query.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-reply.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-sieve.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +301 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +265 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-message-id.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +161 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-posture-chain.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-saga-config.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-smtp-command.test.js +269 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-snapshot-envelope.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-stream-args.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +288 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-tenant-id.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-trace-context.test.js +102 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +202 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/hal.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/honeytoken.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +692 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +280 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +225 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +991 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/iab-mspa.test.js +63 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/iab-tcf.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +612 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +56 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +166 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/incident-report.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jose-jwe-experimental.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-api.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-round-trip-helper.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +159 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +118 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/local-db-thin.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-cloudwatch.test.js +489 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp-grpc.test.js +207 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/lro.test.js +65 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +417 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +208 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +910 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +502 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +680 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-canspam.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +297 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +514 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy-tlsrpt.test.js +369 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +627 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-feedback-id.test.js +56 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +217 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +217 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-mdn.test.js +334 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-rbl.test.js +271 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-require-tls.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +215 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +336 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +732 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +840 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +285 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +229 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +394 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +147 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-spam-score.test.js +204 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-srs.test.js +152 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +279 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-unsubscribe.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +439 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp-tool-registry.test.js +202 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +155 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-shadow-registry.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +224 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-compose-pipeline.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +376 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-paths.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nel.test.js +200 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-byte-quota.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +372 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +635 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-heartbeat-passive.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-build-options.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-ct-inclusion.test.js +179 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +447 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +369 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nis2-report.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nist-crosswalk.test.js +42 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/no-cache.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/notify.test.js +707 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/numeric-bounds.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +72 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +597 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/openapi.test.js +877 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +257 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pagination.test.js +522 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +324 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +546 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +153 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-software.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/problem-details.test.js +195 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/process-spawn.test.js +62 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/promise-pool.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protected-resource-metadata.test.js +68 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protobuf-encoder.test.js +138 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/protocol-dispatcher.test.js +174 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/public-suffix.test.js +197 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +232 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-dlq-extend-lease.test.js +178 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +322 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-priority-rate-progress.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-sqs.test.js +300 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-cluster.test.js +338 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-registry.test.js +75 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +246 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +130 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +335 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-log.test.js +170 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-auth-cache-control.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-mtls.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/resource-access-lock.test.js +52 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retry.test.js +535 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-cross-origin-redirect.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-parallel.test.js +170 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +248 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +451 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +289 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-icap.test.js +206 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +339 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mount-info.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-sieve.test.js +123 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-smtp.test.js +95 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-idn-homograph.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +257 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/saml-slo.test.js +249 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +228 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-exactly-once.test.js +238 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +700 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-notify.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sec-cyber.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +175 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/seeders.test.js +816 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update-standalone-verifier.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/server-timing.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +247 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +295 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/shape-match.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +952 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-multipart-sse.test.js +441 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/slug.test.js +330 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/smtp-policy.test.js +233 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/source-comment-blocks.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/speculation-rules.test.js +319 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sse.test.js +148 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +283 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/standard-webhooks.test.js +67 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +266 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +487 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-chunk-scratch.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +773 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/stream-throttle.test.js +173 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +180 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tcpa-10dlc.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +571 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/test-harness.test.js +190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/testing-request.test.js +119 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/testing.test.js +522 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-exporter.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-ct.test.js +275 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-verify.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-pinset-drift.test.js +35 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tls-preferred-groups.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tracing.test.js +280 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/uuid.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-aad.test.js +277 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-seal-pem-file.test.js +252 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vendor-data.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vendor-manifest.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vex.test.js +661 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +308 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/web-push-vapid.test.js +144 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +674 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket-channels.test.js +360 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool.test.js +302 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +349 -0
- package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +717 -0
- package/lib/vendor/blamejs/test/layer-5-integration/bundler-output.test.js +444 -0
- package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +597 -0
- package/lib/vendor/blamejs/test/layer-5-integration/security-chaos.test.js +308 -0
- package/lib/vendor/blamejs/test/smoke.js +431 -0
- package/lib/webhooks.js +305 -0
- package/package.json +43 -0
|
@@ -0,0 +1,1908 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module b.crypto
|
|
4
|
+
* @featured true
|
|
5
|
+
* @nav Crypto
|
|
6
|
+
* @title Crypto
|
|
7
|
+
*
|
|
8
|
+
* @intro
|
|
9
|
+
* The framework's PQC-first cryptography surface. Every default is
|
|
10
|
+
* post-quantum-aware: ML-KEM-1024 + ECDH P-384 hybrid for key
|
|
11
|
+
* encapsulation (FIPS 203 + classical defense-in-depth), XChaCha20-
|
|
12
|
+
* Poly1305 for authenticated symmetric encryption (24-byte nonce —
|
|
13
|
+
* no nonce-reuse risk under high volume), SHAKE256 as the KDF
|
|
14
|
+
* (FIPS 202 XOF — arbitrary output length), SHA3-512 for hashing,
|
|
15
|
+
* HMAC-SHA3-512 for keyed integrity, and ML-DSA-87 / SLH-DSA-SHAKE-
|
|
16
|
+
* 256f for signatures (auto-detected from the key PEM). Argon2id
|
|
17
|
+
* passphrase stretching lives in `b.vaultWrap`, not here.
|
|
18
|
+
*
|
|
19
|
+
* Envelope wire format (length-prefixed, self-describing):
|
|
20
|
+
*
|
|
21
|
+
* byte 0 : ENVELOPE_MAGIC
|
|
22
|
+
* byte 1 : KEM ID (ML_KEM_1024 / ML_KEM_1024_P384 / ML_KEM_768_X25519)
|
|
23
|
+
* byte 2 : CIPHER ID (XCHACHA20_POLY1305)
|
|
24
|
+
* byte 3 : KDF ID (SHAKE256)
|
|
25
|
+
* ... : KEM ciphertext, ephemeral ECDH pubkey, nonce, AEAD ciphertext
|
|
26
|
+
*
|
|
27
|
+
* The four-byte header is bound as AEAD AAD so an algorithm-
|
|
28
|
+
* substitution attack (a tampered byte-1 KEM ID, byte-2 cipher ID,
|
|
29
|
+
* etc.) fails Poly1305 verification. Old envelopes decrypt under the
|
|
30
|
+
* IDs written into their header; new writes use the active suite.
|
|
31
|
+
* The KDF additionally absorbs a NIST SP 800-56C r2 §4.1 FixedInfo
|
|
32
|
+
* suite-binding label so a key derived under one suite is not
|
|
33
|
+
* silently usable under another.
|
|
34
|
+
*
|
|
35
|
+
* Three KEM hybrids ship: ML-KEM-1024 KEM-only (legacy single-
|
|
36
|
+
* component), ML-KEM-1024 + ECDH P-384 (framework default), and
|
|
37
|
+
* ML-KEM-768 + X25519 (IETF / Cloudflare / Chrome TLS 1.3 codepoint
|
|
38
|
+
* 0x11EC — smaller payload, wider browser interop).
|
|
39
|
+
*
|
|
40
|
+
* SHA-1 / SHA-256 / AES-GCM / classical-only ECDH are intentionally
|
|
41
|
+
* absent from the public surface. Operators who genuinely need them
|
|
42
|
+
* call `node:crypto` directly so the choice surfaces in their code.
|
|
43
|
+
*
|
|
44
|
+
* @card
|
|
45
|
+
* The framework's PQC-first cryptography surface.
|
|
46
|
+
*/
|
|
47
|
+
var nodeCrypto = require("node:crypto");
|
|
48
|
+
var nodeFs = require("node:fs");
|
|
49
|
+
var { pipeline } = require("node:stream/promises");
|
|
50
|
+
var { xchacha20poly1305 } = require("./vendor/noble-ciphers.cjs");
|
|
51
|
+
var C = require("./constants");
|
|
52
|
+
// Circular: audit imports b.crypto for sha3Hash + envelope sign. Lazy-
|
|
53
|
+
// load the audit module so the legacy-envelope decrypt path can emit
|
|
54
|
+
// `system.crypto.decrypt.allow_legacy` events without an inline
|
|
55
|
+
// require() inside setImmediate. (The framework's convention is
|
|
56
|
+
// top-of-file require() except where a documented circular-load
|
|
57
|
+
// reason forces lazy-load; this is one of those reasons.)
|
|
58
|
+
var lazyRequire = require("./lazy-require");
|
|
59
|
+
var audit = lazyRequire(function () { return require("./audit"); });
|
|
60
|
+
// safe-buffer hosts the canonical hasCrlf(s) helper used by every
|
|
61
|
+
// log-injection / CRLF-smuggling refusal in the framework. Lazy-
|
|
62
|
+
// loaded because safe-buffer.js itself imports b.crypto for
|
|
63
|
+
// hex-compare helpers (circular).
|
|
64
|
+
var safeBuffer = lazyRequire(function () { return require("./safe-buffer"); });
|
|
65
|
+
|
|
66
|
+
// Streaming-hash algorithm allowlist. Mirrors the framework's PQC-
|
|
67
|
+
// first crypto policy: SHA3 / SHAKE family is the default surface;
|
|
68
|
+
// SHA-512 is permitted for legitimate interop (signing artifacts that
|
|
69
|
+
// downstream verifiers compute as SHA-512). MD5 / SHA-1 / SHA-256 are
|
|
70
|
+
// not on the list — operators who genuinely need them call
|
|
71
|
+
// node:crypto directly so the choice surfaces in their code.
|
|
72
|
+
var STREAM_HASH_ALGORITHMS = Object.freeze({
|
|
73
|
+
"sha3-256": { algorithm: "sha3-256", needsOutputLength: false },
|
|
74
|
+
"sha3-384": { algorithm: "sha3-384", needsOutputLength: false },
|
|
75
|
+
"sha3-512": { algorithm: "sha3-512", needsOutputLength: false },
|
|
76
|
+
"sha512": { algorithm: "sha512", needsOutputLength: false },
|
|
77
|
+
"shake256": { algorithm: "shake256", needsOutputLength: true },
|
|
78
|
+
});
|
|
79
|
+
var STREAM_HASH_DEFAULT = "sha3-512";
|
|
80
|
+
var SHAKE256_DEFAULT_LEN = 64;
|
|
81
|
+
|
|
82
|
+
// ===========================================================
|
|
83
|
+
// Core primitives — everything else is built from these
|
|
84
|
+
// ===========================================================
|
|
85
|
+
|
|
86
|
+
function hash(data, algorithm, outputLength) {
|
|
87
|
+
var opts = outputLength ? { outputLength: outputLength } : undefined;
|
|
88
|
+
return nodeCrypto.createHash(algorithm, opts).update(data).digest();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function hmac(key, data, algorithm) {
|
|
92
|
+
return nodeCrypto.createHmac(algorithm, key).update(data).digest("hex");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @primitive b.crypto.hashStream
|
|
97
|
+
* @signature b.crypto.hashStream(readable, algorithm)
|
|
98
|
+
* @since 0.5.0
|
|
99
|
+
* @related b.crypto.hashFile, b.crypto.sha3Hash
|
|
100
|
+
*
|
|
101
|
+
* Streams a Readable through `createHash(algorithm)` and resolves with
|
|
102
|
+
* the raw digest Buffer. Default algorithm is SHA3-512. Algorithm is
|
|
103
|
+
* validated against the allowlist (sha3-256 / sha3-384 / sha3-512 /
|
|
104
|
+
* sha512 / shake256) so a typo or weak choice throws at config time
|
|
105
|
+
* rather than producing a digest under a surprise algorithm. Read-
|
|
106
|
+
* only — no audit emit.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* var fs = require("fs");
|
|
110
|
+
* var stream = fs.createReadStream("/etc/hosts");
|
|
111
|
+
* b.crypto.hashStream(stream, "sha3-512").then(function (digest) {
|
|
112
|
+
* digest.toString("hex");
|
|
113
|
+
* // → "abcd0123...e8f9" (128 hex chars, SHA3-512 = 64 bytes)
|
|
114
|
+
* });
|
|
115
|
+
*/
|
|
116
|
+
function hashStream(readable, algorithm) {
|
|
117
|
+
var alg = (algorithm || STREAM_HASH_DEFAULT).toLowerCase();
|
|
118
|
+
var entry = STREAM_HASH_ALGORITHMS[alg];
|
|
119
|
+
if (!entry) {
|
|
120
|
+
return Promise.reject(new TypeError(
|
|
121
|
+
"crypto.hashStream: unsupported algorithm '" + algorithm +
|
|
122
|
+
"' (allowed: " + Object.keys(STREAM_HASH_ALGORITHMS).join(", ") + ")"
|
|
123
|
+
));
|
|
124
|
+
}
|
|
125
|
+
if (!readable || typeof readable.pipe !== "function") {
|
|
126
|
+
return Promise.reject(new TypeError(
|
|
127
|
+
"crypto.hashStream: readable must be a Readable stream"
|
|
128
|
+
));
|
|
129
|
+
}
|
|
130
|
+
var hashOpts = entry.needsOutputLength ? { outputLength: SHAKE256_DEFAULT_LEN } : undefined;
|
|
131
|
+
var digester = nodeCrypto.createHash(entry.algorithm, hashOpts);
|
|
132
|
+
return pipeline(readable, digester).then(function () {
|
|
133
|
+
return digester.digest();
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @primitive b.crypto.hashFile
|
|
139
|
+
* @signature b.crypto.hashFile(filePath, algorithm)
|
|
140
|
+
* @since 0.5.0
|
|
141
|
+
* @related b.crypto.hashStream, b.crypto.sha3Hash
|
|
142
|
+
*
|
|
143
|
+
* Opens `filePath` as a Readable and streams it through `hashStream`.
|
|
144
|
+
* Resolves with the raw digest Buffer. Default algorithm is SHA3-512.
|
|
145
|
+
* Read-only — no audit emit; the path is operator-supplied and the
|
|
146
|
+
* digest is the only observable side-effect.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* b.crypto.hashFile("/etc/hosts", "sha3-256").then(function (digest) {
|
|
150
|
+
* digest.toString("hex");
|
|
151
|
+
* // → "0123abcd...ef89" (64 hex chars, SHA3-256 = 32 bytes)
|
|
152
|
+
* });
|
|
153
|
+
*/
|
|
154
|
+
function hashFile(filePath, algorithm) {
|
|
155
|
+
if (typeof filePath !== "string" || filePath.length === 0) {
|
|
156
|
+
return Promise.reject(new TypeError(
|
|
157
|
+
"crypto.hashFile: path must be a non-empty string"
|
|
158
|
+
));
|
|
159
|
+
}
|
|
160
|
+
return hashStream(nodeFs.createReadStream(filePath), algorithm);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// _hashFileMulti — single-pass stream of a file through N hashers in
|
|
164
|
+
// parallel. Returns { path, byteLength, <alg>: hex } for every
|
|
165
|
+
// `algorithms` entry. Used by hashFilesParallel below; not exported
|
|
166
|
+
// directly because the common case is the parallel-many shape.
|
|
167
|
+
//
|
|
168
|
+
// CRYPTO-5 hardening (v0.9.58):
|
|
169
|
+
// - lstat-then-stat so symlinks are detected before open; refused
|
|
170
|
+
// unless opts.followSymlinks === true (default false — a symlink-
|
|
171
|
+
// in-input-list attack lets a write-restricted caller hash files
|
|
172
|
+
// they can't otherwise reach).
|
|
173
|
+
// - Refuses non-regular files (FIFOs / sockets / block / char
|
|
174
|
+
// devices) which read indefinitely or return platform-undefined
|
|
175
|
+
// bytes. The same path also defeats /dev/zero-as-input DoS.
|
|
176
|
+
// - opts.maxBytesPerFile (default C.BYTES.gib(1)) caps the bytes
|
|
177
|
+
// read per file; oversized inputs reject before exhausting heap.
|
|
178
|
+
function _hashFileMulti(filePath, algorithms, opts) {
|
|
179
|
+
var maxBytes = opts && opts.maxBytesPerFile;
|
|
180
|
+
var followSymlink = opts && opts.followSymlinks === true;
|
|
181
|
+
return new Promise(function (resolve, reject) {
|
|
182
|
+
// Pre-open lstat: detect symlinks + special files before opening the
|
|
183
|
+
// stream. Open-then-stat is racy under symlink-swap; lstat the path
|
|
184
|
+
// itself ahead of createReadStream.
|
|
185
|
+
var st;
|
|
186
|
+
try { st = nodeFs.lstatSync(filePath); }
|
|
187
|
+
catch (statErr) {
|
|
188
|
+
reject(new Error("crypto.hashFilesParallel: stat failed for '" +
|
|
189
|
+
filePath + "': " + (statErr && statErr.message ? statErr.message : String(statErr))));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (st.isSymbolicLink() && !followSymlink) {
|
|
193
|
+
reject(new Error("crypto.hashFilesParallel: refusing symlink '" +
|
|
194
|
+
filePath + "' — pass {followSymlinks: true} to opt in (an attacker " +
|
|
195
|
+
"with write access to the input list can otherwise direct the hasher " +
|
|
196
|
+
"to files the caller cannot read directly)"));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!st.isFile() && !st.isSymbolicLink()) {
|
|
200
|
+
reject(new Error("crypto.hashFilesParallel: refusing non-regular file '" +
|
|
201
|
+
filePath + "' (FIFOs / sockets / character / block devices read indefinitely " +
|
|
202
|
+
"or return platform-undefined bytes; hashing them is meaningless and " +
|
|
203
|
+
"DoS-prone). Type: " +
|
|
204
|
+
(st.isFIFO() ? "FIFO" :
|
|
205
|
+
st.isSocket() ? "socket" :
|
|
206
|
+
st.isBlockDevice() ? "block-device" :
|
|
207
|
+
st.isCharacterDevice() ? "char-device" :
|
|
208
|
+
st.isDirectory() ? "directory" : "unknown")));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
var hashers = new Array(algorithms.length);
|
|
212
|
+
for (var i = 0; i < algorithms.length; i += 1) {
|
|
213
|
+
try { hashers[i] = nodeCrypto.createHash(algorithms[i]); }
|
|
214
|
+
catch (e) {
|
|
215
|
+
reject(new Error("crypto.hashFilesParallel: unknown algorithm '" +
|
|
216
|
+
algorithms[i] + "': " + (e && e.message ? e.message : String(e))));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
var byteLength = 0;
|
|
221
|
+
var aborted = false;
|
|
222
|
+
var stream = nodeFs.createReadStream(filePath);
|
|
223
|
+
stream.on("error", reject);
|
|
224
|
+
stream.on("data", function (chunk) {
|
|
225
|
+
if (aborted) return;
|
|
226
|
+
byteLength += chunk.length;
|
|
227
|
+
if (maxBytes && byteLength > maxBytes) {
|
|
228
|
+
aborted = true;
|
|
229
|
+
try { stream.destroy(); } catch (_e) { /* best-effort */ }
|
|
230
|
+
reject(new Error("crypto.hashFilesParallel: file '" + filePath +
|
|
231
|
+
"' exceeded opts.maxBytesPerFile (" + maxBytes +
|
|
232
|
+
" bytes); refusing to continue hashing"));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
for (var j = 0; j < hashers.length; j += 1) hashers[j].update(chunk);
|
|
236
|
+
});
|
|
237
|
+
stream.on("end", function () {
|
|
238
|
+
if (aborted) return;
|
|
239
|
+
var out = { path: filePath, byteLength: byteLength };
|
|
240
|
+
for (var k = 0; k < hashers.length; k += 1) {
|
|
241
|
+
// Field name = algorithm with `-` → `_` so "sha3-512" surfaces
|
|
242
|
+
// as `out.sha3_512` (matches the standalone-verifier shape).
|
|
243
|
+
out[algorithms[k].replace(/-/g, "_")] = hashers[k].digest("hex");
|
|
244
|
+
}
|
|
245
|
+
resolve(out);
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @primitive b.crypto.hashFilesParallel
|
|
252
|
+
* @signature b.crypto.hashFilesParallel(filePaths, opts?)
|
|
253
|
+
* @since 0.9.14
|
|
254
|
+
* @status stable
|
|
255
|
+
* @related b.crypto.hashFile, b.crypto.hashStream
|
|
256
|
+
*
|
|
257
|
+
* Hash many files in parallel, streaming each one through one or
|
|
258
|
+
* more digest algorithms in a single read pass. Returns an array of
|
|
259
|
+
* `{ path, byteLength, sha256, sha3_512, ... }` records in the same
|
|
260
|
+
* order as `filePaths`. Concurrency is operator-tunable; the default
|
|
261
|
+
* (`min(8, filePaths.length)`) matches the framework's
|
|
262
|
+
* hash-while-streaming convention elsewhere without saturating the
|
|
263
|
+
* fs read queue on spinning-disk hosts.
|
|
264
|
+
*
|
|
265
|
+
* The common consumer-side reason to reach for this primitive is
|
|
266
|
+
* SBOM regeneration / vendor-data integrity sweeps / release-asset
|
|
267
|
+
* bundling — situations where N files each need both SHA-256 (legacy
|
|
268
|
+
* compat) and SHA-3-512 (PQC-first) digests and rolling a worker
|
|
269
|
+
* pool by hand has cost a downstream consumer (`hermitstash-sync`
|
|
270
|
+
* 2026-05-13) the same two-loop, capture-N-promises, settle-Q boilerplate
|
|
271
|
+
* every release.
|
|
272
|
+
*
|
|
273
|
+
* @opts
|
|
274
|
+
* algorithms?: string[], // default ["sha256", "sha3-512"]; any node:crypto-known digest
|
|
275
|
+
* concurrency?: number, // default min(8, filePaths.length); 1..256
|
|
276
|
+
* onProgress?: function (completed, total) // best-effort; thrown errors swallowed
|
|
277
|
+
* maxBytesPerFile?: number, // default C.BYTES.gib(1) — DoS cap; oversized inputs reject
|
|
278
|
+
* followSymlinks?: boolean, // default false — refuse symlinks unless explicitly opted in
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* var rows = await b.crypto.hashFilesParallel(
|
|
282
|
+
* ["/var/lib/blamejs/asset-a.bin",
|
|
283
|
+
* "/var/lib/blamejs/asset-b.bin"],
|
|
284
|
+
* { algorithms: ["sha256", "sha3-512"], concurrency: 4 }
|
|
285
|
+
* );
|
|
286
|
+
* // rows[0] → { path: "...asset-a.bin", byteLength: 4096,
|
|
287
|
+
* // sha256: "...", sha3_512: "..." }
|
|
288
|
+
*/
|
|
289
|
+
function hashFilesParallel(filePaths, opts) {
|
|
290
|
+
if (!Array.isArray(filePaths)) {
|
|
291
|
+
return Promise.reject(new TypeError(
|
|
292
|
+
"crypto.hashFilesParallel: filePaths must be an array of non-empty strings"
|
|
293
|
+
));
|
|
294
|
+
}
|
|
295
|
+
for (var i = 0; i < filePaths.length; i += 1) {
|
|
296
|
+
if (typeof filePaths[i] !== "string" || filePaths[i].length === 0) {
|
|
297
|
+
return Promise.reject(new TypeError(
|
|
298
|
+
"crypto.hashFilesParallel: filePaths[" + i + "] must be a non-empty string"
|
|
299
|
+
));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
opts = opts || {};
|
|
303
|
+
var algorithms = opts.algorithms !== undefined
|
|
304
|
+
? opts.algorithms : ["sha256", "sha3-512"];
|
|
305
|
+
if (!Array.isArray(algorithms) || algorithms.length === 0) {
|
|
306
|
+
return Promise.reject(new TypeError(
|
|
307
|
+
"crypto.hashFilesParallel: opts.algorithms must be a non-empty array"
|
|
308
|
+
));
|
|
309
|
+
}
|
|
310
|
+
for (var ai = 0; ai < algorithms.length; ai += 1) {
|
|
311
|
+
if (typeof algorithms[ai] !== "string" || algorithms[ai].length === 0) {
|
|
312
|
+
return Promise.reject(new TypeError(
|
|
313
|
+
"crypto.hashFilesParallel: opts.algorithms[" + ai + "] must be a non-empty string"
|
|
314
|
+
));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
var concurrency = opts.concurrency !== undefined
|
|
318
|
+
? opts.concurrency
|
|
319
|
+
: Math.min(8, Math.max(1, filePaths.length)); // allow:raw-byte-literal — worker fan-out cap, not bytes
|
|
320
|
+
if (typeof concurrency !== "number" || !isFinite(concurrency) ||
|
|
321
|
+
concurrency < 1 || concurrency > 256 || // allow:raw-byte-literal — concurrency upper cap
|
|
322
|
+
Math.floor(concurrency) !== concurrency) {
|
|
323
|
+
return Promise.reject(new TypeError(
|
|
324
|
+
"crypto.hashFilesParallel: opts.concurrency must be an integer in [1, 256], got " + concurrency
|
|
325
|
+
));
|
|
326
|
+
}
|
|
327
|
+
var onProgress = opts.onProgress;
|
|
328
|
+
if (onProgress !== undefined && typeof onProgress !== "function") {
|
|
329
|
+
return Promise.reject(new TypeError(
|
|
330
|
+
"crypto.hashFilesParallel: opts.onProgress must be a function when supplied"
|
|
331
|
+
));
|
|
332
|
+
}
|
|
333
|
+
// CRYPTO-5 — DoS cap. Default 1 GiB per file; operators with larger
|
|
334
|
+
// legitimate hashing workloads (firmware images, vendor packs)
|
|
335
|
+
// override per-call.
|
|
336
|
+
var maxBytesPerFile = opts.maxBytesPerFile !== undefined
|
|
337
|
+
? opts.maxBytesPerFile : C.BYTES.gib(1);
|
|
338
|
+
if (typeof maxBytesPerFile !== "number" || !isFinite(maxBytesPerFile) ||
|
|
339
|
+
maxBytesPerFile <= 0 || Math.floor(maxBytesPerFile) !== maxBytesPerFile) {
|
|
340
|
+
return Promise.reject(new TypeError(
|
|
341
|
+
"crypto.hashFilesParallel: opts.maxBytesPerFile must be a positive integer, got " + maxBytesPerFile
|
|
342
|
+
));
|
|
343
|
+
}
|
|
344
|
+
var followSymlinks = opts.followSymlinks === true;
|
|
345
|
+
if (filePaths.length === 0) return Promise.resolve([]);
|
|
346
|
+
|
|
347
|
+
var hashOpts = {
|
|
348
|
+
maxBytesPerFile: maxBytesPerFile,
|
|
349
|
+
followSymlinks: followSymlinks,
|
|
350
|
+
};
|
|
351
|
+
var results = new Array(filePaths.length);
|
|
352
|
+
var nextIdx = 0;
|
|
353
|
+
var completed = 0;
|
|
354
|
+
var total = filePaths.length;
|
|
355
|
+
function _worker() {
|
|
356
|
+
function _step() {
|
|
357
|
+
var idx = nextIdx;
|
|
358
|
+
nextIdx += 1;
|
|
359
|
+
if (idx >= total) return Promise.resolve();
|
|
360
|
+
return _hashFileMulti(filePaths[idx], algorithms, hashOpts).then(function (rec) {
|
|
361
|
+
results[idx] = rec;
|
|
362
|
+
completed += 1;
|
|
363
|
+
if (onProgress) {
|
|
364
|
+
try { onProgress(completed, total); }
|
|
365
|
+
catch (_e) { /* progress callback errors are not fatal */ }
|
|
366
|
+
}
|
|
367
|
+
return _step();
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
return _step();
|
|
371
|
+
}
|
|
372
|
+
var workerCount = Math.min(concurrency, total);
|
|
373
|
+
var workers = new Array(workerCount);
|
|
374
|
+
for (var w = 0; w < workerCount; w += 1) workers[w] = _worker();
|
|
375
|
+
return Promise.all(workers).then(function () { return results; });
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function random(byteLength) {
|
|
379
|
+
var n = byteLength || 32;
|
|
380
|
+
// SHAKE256 over OS-RNG bytes. The OS RNG (nodeCrypto.randomBytes) is
|
|
381
|
+
// already cryptographically secure on modern platforms; passing
|
|
382
|
+
// through a hash adds defense-in-depth (stops a hypothetical
|
|
383
|
+
// randomBytes weakness from being directly observable downstream)
|
|
384
|
+
// without measurable cost. SHAKE256 is the right XOF here because it
|
|
385
|
+
// supports arbitrary output length — the previous implementation
|
|
386
|
+
// used SHA3-512 + subarray, which silently truncated to 64 bytes
|
|
387
|
+
// when callers requested more. SHAKE256 is also already the
|
|
388
|
+
// framework's KDF / browser-side derivation primitive, so the same
|
|
389
|
+
// hash family does double duty.
|
|
390
|
+
return nodeCrypto.createHash("shake256", { outputLength: n })
|
|
391
|
+
.update(nodeCrypto.randomBytes(n))
|
|
392
|
+
.digest();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* @primitive b.crypto.randomInt
|
|
397
|
+
* @signature b.crypto.randomInt(min, max)
|
|
398
|
+
* @since 0.10.7
|
|
399
|
+
* @status stable
|
|
400
|
+
*
|
|
401
|
+
* Cryptographically-secure uniform integer in `[min, max)`. Substrate
|
|
402
|
+
* wrapper that routes every framework integer draw (DNS query-ID,
|
|
403
|
+
* DMARC `pct` sampling, retry jitter) through one greppable primitive.
|
|
404
|
+
* Both bounds must be safe integers, `max > min`, and the half-open
|
|
405
|
+
* span must not exceed 2^48 (the underlying runtime's hard cap).
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* var n = b.crypto.randomInt(0, 100);
|
|
409
|
+
* // → integer in [0, 100)
|
|
410
|
+
*/
|
|
411
|
+
function randomInt(min, max) {
|
|
412
|
+
if (typeof min !== "number" || !Number.isInteger(min)) {
|
|
413
|
+
throw new TypeError("b.crypto.randomInt: min must be an integer");
|
|
414
|
+
}
|
|
415
|
+
if (typeof max !== "number" || !Number.isInteger(max)) {
|
|
416
|
+
throw new TypeError("b.crypto.randomInt: max must be an integer");
|
|
417
|
+
}
|
|
418
|
+
if (max <= min) {
|
|
419
|
+
throw new RangeError("b.crypto.randomInt: max must be greater than min");
|
|
420
|
+
}
|
|
421
|
+
return nodeCrypto.randomInt(min, max);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function generateKeyPair(algorithm, options) {
|
|
425
|
+
var pair = nodeCrypto.generateKeyPairSync(algorithm, Object.assign({
|
|
426
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
427
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
428
|
+
}, options || {}));
|
|
429
|
+
return { publicKey: pair.publicKey, privateKey: pair.privateKey };
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* @primitive b.crypto.timingSafeEqual
|
|
434
|
+
* @signature b.crypto.timingSafeEqual(a, b)
|
|
435
|
+
* @since 0.1.0
|
|
436
|
+
* @related b.crypto.hmacSha3
|
|
437
|
+
*
|
|
438
|
+
* Constant-time equality comparison. Accepts only Buffer or string
|
|
439
|
+
* inputs — non-string non-Buffer arguments throw at the entry tier so
|
|
440
|
+
* a `Object.prototype.toString`-poisoned caller can't redirect the
|
|
441
|
+
* compare through arbitrary attacker-controlled bytes. Returns
|
|
442
|
+
* `false` immediately when lengths differ (length itself is not a
|
|
443
|
+
* secret), then routes equal-length inputs through
|
|
444
|
+
* `crypto.timingSafeEqual`. Use when comparing HMAC digests, session
|
|
445
|
+
* tokens, password-reset codes, or any attacker-influenced value
|
|
446
|
+
* where a timing oracle would leak bits.
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* var expected = b.crypto.hmacSha3("server-key", "payload");
|
|
450
|
+
* var supplied = "ab12...e9"; // from request header / body
|
|
451
|
+
* var ok = b.crypto.timingSafeEqual(supplied, expected);
|
|
452
|
+
* // → true when bytes match, false otherwise (no early exit on mismatch)
|
|
453
|
+
*/
|
|
454
|
+
function timingSafeEqual(a, b) {
|
|
455
|
+
// Entry-tier validation. The prior `Buffer.from(String(x))` coercion
|
|
456
|
+
// let a prototype-pollution-influenced caller (Object whose toString
|
|
457
|
+
// returns attacker-chosen bytes) redirect the compare through bytes
|
|
458
|
+
// that have nothing to do with the supplied value. Refuse any
|
|
459
|
+
// non-string non-Buffer input outright.
|
|
460
|
+
if (!Buffer.isBuffer(a) && typeof a !== "string") {
|
|
461
|
+
throw new TypeError(
|
|
462
|
+
"crypto.timingSafeEqual: argument 'a' must be a Buffer or string, got " +
|
|
463
|
+
(a === null ? "null" : typeof a)
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
if (!Buffer.isBuffer(b) && typeof b !== "string") {
|
|
467
|
+
throw new TypeError(
|
|
468
|
+
"crypto.timingSafeEqual: argument 'b' must be a Buffer or string, got " +
|
|
469
|
+
(b === null ? "null" : typeof b)
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
var bufA = Buffer.isBuffer(a) ? a : Buffer.from(a, "utf8");
|
|
473
|
+
var bufB = Buffer.isBuffer(b) ? b : Buffer.from(b, "utf8");
|
|
474
|
+
if (bufA.length !== bufB.length) return false;
|
|
475
|
+
return nodeCrypto.timingSafeEqual(bufA, bufB);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ===========================================================
|
|
479
|
+
// Public API — built on core primitives
|
|
480
|
+
// ===========================================================
|
|
481
|
+
|
|
482
|
+
// ---- Hashing ----
|
|
483
|
+
/**
|
|
484
|
+
* @primitive b.crypto.sha3Hash
|
|
485
|
+
* @signature b.crypto.sha3Hash(data)
|
|
486
|
+
* @since 0.1.0
|
|
487
|
+
* @related b.crypto.hmacSha3, b.crypto.kdf, b.crypto.hashFile
|
|
488
|
+
*
|
|
489
|
+
* Returns the lowercase-hex SHA3-512 digest of the input. SHA3-512 is
|
|
490
|
+
* the framework's default hash — collision-resistant, sponge-based,
|
|
491
|
+
* and PQC-aligned (no quantum speedup beyond Grover's). Suitable for
|
|
492
|
+
* content fingerprints, integrity checks, derived-column inputs, and
|
|
493
|
+
* Merkle-tree leaves.
|
|
494
|
+
*
|
|
495
|
+
* @example
|
|
496
|
+
* var digest = b.crypto.sha3Hash("hello world");
|
|
497
|
+
* // → "75d527c368f2efe848ecf6b073a36767800805e9eef2b1857d5f984f036eb6df..."
|
|
498
|
+
*/
|
|
499
|
+
function sha3Hash(data) { return hash(data, "sha3-512").toString("hex"); }
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* @primitive b.crypto.hmacSha3
|
|
503
|
+
* @signature b.crypto.hmacSha3(key, data)
|
|
504
|
+
* @since 0.1.0
|
|
505
|
+
* @related b.crypto.sha3Hash, b.crypto.timingSafeEqual
|
|
506
|
+
*
|
|
507
|
+
* Returns the lowercase-hex HMAC-SHA3-512 of `data` keyed by `key`.
|
|
508
|
+
* Use for keyed integrity checks (webhook signatures, request
|
|
509
|
+
* authentication tags, audit-chain links). Pair with
|
|
510
|
+
* `b.crypto.timingSafeEqual` when comparing supplied vs computed tags.
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* var tag = b.crypto.hmacSha3("shared-secret", "POST /webhook|123");
|
|
514
|
+
* // → "8f1c...d4e2" (128 hex chars, HMAC-SHA3-512 = 64 bytes)
|
|
515
|
+
*/
|
|
516
|
+
function hmacSha3(key, data) { return hmac(key, data, "sha3-512"); }
|
|
517
|
+
|
|
518
|
+
// (SHA-1 is intentionally NOT exported from b.crypto. The framework's
|
|
519
|
+
// only legitimate SHA-1 use is the HaveIBeenPwned k-anonymity API in
|
|
520
|
+
// lib/auth/password.js, which imports lib/framework-sha1-hibp.js
|
|
521
|
+
// directly. Public b.crypto.sha1* is permanently off the table — a
|
|
522
|
+
// future caller wanting SHA-1 for storage / signing / fingerprinting
|
|
523
|
+
// would re-introduce a broken primitive into the crypto surface this
|
|
524
|
+
// framework spent every other line keeping out.)
|
|
525
|
+
|
|
526
|
+
// ---- KDF ----
|
|
527
|
+
/**
|
|
528
|
+
* @primitive b.crypto.kdf
|
|
529
|
+
* @signature b.crypto.kdf(input, outputLength)
|
|
530
|
+
* @since 0.1.0
|
|
531
|
+
* @related b.crypto.sha3Hash, b.crypto.generateBytes
|
|
532
|
+
*
|
|
533
|
+
* SHAKE256-based key derivation. Returns a Buffer of exactly
|
|
534
|
+
* `outputLength` bytes derived from `input`. SHAKE256 is an XOF
|
|
535
|
+
* (extendable-output function) — arbitrary output length without the
|
|
536
|
+
* truncation pitfalls of fixed-width SHA3 + slice. Used internally
|
|
537
|
+
* for envelope symmetric-key derivation; operators reach for it when
|
|
538
|
+
* they need application-specific subkeys with explicit length.
|
|
539
|
+
*
|
|
540
|
+
* @example
|
|
541
|
+
* var seed = Buffer.from("master-secret|session-42", "utf8");
|
|
542
|
+
* var subkey = b.crypto.kdf(seed, 32);
|
|
543
|
+
* subkey.length;
|
|
544
|
+
* // → 32 (32-byte XChaCha20 key)
|
|
545
|
+
*/
|
|
546
|
+
function kdf(input, outputLength) { return hash(input, "shake256", outputLength); }
|
|
547
|
+
|
|
548
|
+
// ---- App-namespaced indexable hash (for derived-hash columns) ----
|
|
549
|
+
//
|
|
550
|
+
// b.crypto.namespaceHash(prefix, value) → hex-encoded SHA3-512 of
|
|
551
|
+
// `prefix + ":" + value`. Operators wire this into derived-hash
|
|
552
|
+
// columns (emailHash, certFpHash, externalIdHash) where the goal is
|
|
553
|
+
// indexed exact-match lookup, NOT credential storage. Returns hex —
|
|
554
|
+
// not the envelope-versioned base64 b.credentialHash.hash returns —
|
|
555
|
+
// because hex strings are stable, indexable column values across
|
|
556
|
+
// every database backend the framework supports.
|
|
557
|
+
//
|
|
558
|
+
// Why a separate primitive vs `b.crypto.sha3Hash(prefix + ":" + value)`:
|
|
559
|
+
// - Centralized prefix-shape validation (NUL/CR/LF rejection,
|
|
560
|
+
// length bound) — operator can't accidentally smuggle a
|
|
561
|
+
// framework-derived prefix through a user-controlled value.
|
|
562
|
+
// - Clear name documents the intent ("indexable namespace hash"
|
|
563
|
+
// vs "raw content digest"), so callers are less likely to
|
|
564
|
+
// reach for the credential-storage primitive when they want a
|
|
565
|
+
// read-only lookup hash.
|
|
566
|
+
//
|
|
567
|
+
// Read-only / deterministic — no audit emit (the input is operator-
|
|
568
|
+
// supplied; the digest is the only observable side-effect, returned
|
|
569
|
+
// to the caller). NUL / CR / LF in `prefix` are refused so an
|
|
570
|
+
// operator can't smuggle a control sequence into framework or
|
|
571
|
+
// downstream tooling that consumes the audit log; the bound on
|
|
572
|
+
// `prefix` length prevents oversized namespace separators (the
|
|
573
|
+
// framework's HASH_PREFIX entries are <= 16 bytes).
|
|
574
|
+
var NAMESPACE_HASH_PREFIX_MAX_BYTES = 64;
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* @primitive b.crypto.namespaceHash
|
|
578
|
+
* @signature b.crypto.namespaceHash(prefix, value, opts)
|
|
579
|
+
* @since 0.6.0
|
|
580
|
+
* @related b.crypto.sha3Hash, b.credentialHash.hash
|
|
581
|
+
*
|
|
582
|
+
* App-namespaced indexable SHA3-512 hash for derived-hash columns
|
|
583
|
+
* (emailHash, certFpHash, externalIdHash). Returns lowercase hex —
|
|
584
|
+
* stable, indexable column values across every supported database.
|
|
585
|
+
* Centralizes prefix-shape validation: NUL / CR / LF in `prefix` are
|
|
586
|
+
* refused outright, and `prefix` is bounded to 64 UTF-8 bytes so an
|
|
587
|
+
* operator can't smuggle log-injection or oversized labels into
|
|
588
|
+
* derived-column inputs. Use when the goal is exact-match lookup,
|
|
589
|
+
* NOT credential storage — for password-style storage use
|
|
590
|
+
* `b.credentialHash.hash`.
|
|
591
|
+
*
|
|
592
|
+
* @opts
|
|
593
|
+
* reserved: object, // accepted but ignored — reserved for a future algorithm-selection knob
|
|
594
|
+
*
|
|
595
|
+
* @example
|
|
596
|
+
* var emailHash = b.crypto.namespaceHash("email", "alice@example.com");
|
|
597
|
+
* // → "1f3a...c08d" (128 hex chars, SHA3-512 of "email:alice@example.com")
|
|
598
|
+
*
|
|
599
|
+
* var certFpHash = b.crypto.namespaceHash("cert-fp", Buffer.from([1, 2, 3, 4]));
|
|
600
|
+
* // Buffer/Uint8Array values are coerced to UTF-8 string before hashing.
|
|
601
|
+
*/
|
|
602
|
+
function namespaceHash(prefix, value, opts) {
|
|
603
|
+
// opts reserved for future extension (algorithm selection); current
|
|
604
|
+
// surface is fixed to SHA3-512 — no operator demand for SHAKE256
|
|
605
|
+
// variable-length output here, since the indexed column shape is
|
|
606
|
+
// fixed-width hex.
|
|
607
|
+
if (opts && typeof opts !== "object") {
|
|
608
|
+
throw new TypeError("crypto.namespaceHash: opts must be a plain object when provided");
|
|
609
|
+
}
|
|
610
|
+
if (typeof prefix !== "string") {
|
|
611
|
+
throw new TypeError("crypto.namespaceHash: prefix must be a string");
|
|
612
|
+
}
|
|
613
|
+
if (prefix.length === 0) {
|
|
614
|
+
throw new TypeError("crypto.namespaceHash: prefix must be non-empty");
|
|
615
|
+
}
|
|
616
|
+
// Byte-length bound — operator's prefix is the namespace label and
|
|
617
|
+
// shouldn't bloat the hash input. Use Buffer.byteLength so multi-
|
|
618
|
+
// byte UTF-8 prefixes can't slip through a code-unit-only check.
|
|
619
|
+
if (Buffer.byteLength(prefix, "utf8") > NAMESPACE_HASH_PREFIX_MAX_BYTES) {
|
|
620
|
+
throw new TypeError(
|
|
621
|
+
"crypto.namespaceHash: prefix exceeds " + NAMESPACE_HASH_PREFIX_MAX_BYTES +
|
|
622
|
+
" bytes (UTF-8); operator-derived prefixes should be short labels"
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
// NUL / CR / LF in prefix — refuse outright. NUL truncates in many
|
|
626
|
+
// C-string consumers (audit-log path, downstream DB tooling); CR/LF
|
|
627
|
+
// smuggles log-injection patterns into anything that renders the
|
|
628
|
+
// prefix verbatim.
|
|
629
|
+
// eslint-disable-next-line no-control-regex
|
|
630
|
+
if (/[\u0000\r\n]/.test(prefix)) {
|
|
631
|
+
throw new TypeError(
|
|
632
|
+
"crypto.namespaceHash: prefix contains NUL / CR / LF — refuse"
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
// value is the operator-supplied content. Coerce Buffer/Uint8Array
|
|
636
|
+
// to utf-8 string for concatenation; reject anything else so the
|
|
637
|
+
// caller surfaces the type error explicitly rather than silently
|
|
638
|
+
// hashing `[object Object]`.
|
|
639
|
+
var valueStr;
|
|
640
|
+
var valueWasString = false;
|
|
641
|
+
if (typeof value === "string") {
|
|
642
|
+
valueStr = value;
|
|
643
|
+
valueWasString = true;
|
|
644
|
+
} else if (Buffer.isBuffer(value)) {
|
|
645
|
+
valueStr = value.toString("utf8");
|
|
646
|
+
} else if (value instanceof Uint8Array) {
|
|
647
|
+
valueStr = Buffer.from(value).toString("utf8");
|
|
648
|
+
} else {
|
|
649
|
+
throw new TypeError(
|
|
650
|
+
"crypto.namespaceHash: value must be a string, Buffer, or Uint8Array"
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
// Refuse CR / LF in string-typed values. The prior gap let an
|
|
654
|
+
// attacker-controlled string `value` (e.g. an HTTP header that
|
|
655
|
+
// becomes an Idempotency-Key) smuggle log-injection / record-
|
|
656
|
+
// separator bytes into any consumer that logs the value verbatim
|
|
657
|
+
// before hashing (debug paths, audit envelopes, derived-column
|
|
658
|
+
// shadow logs). NUL is NOT refused — multiple internal callers
|
|
659
|
+
// use NUL as a composite-key separator (`method\0actorId\0key`
|
|
660
|
+
// shape in agent-idempotency / mail-greylist / compose-pipeline),
|
|
661
|
+
// and NUL is not a log-injection byte in any standard logger. NUL
|
|
662
|
+
// in operator-supplied content is the operator-boundary
|
|
663
|
+
// responsibility. Buffer / Uint8Array inputs remain operator-side
|
|
664
|
+
// opaque bytes by contract — namespaceHash treats them as raw
|
|
665
|
+
// bytes to be digested without rendering, so the control-char
|
|
666
|
+
// gate does not apply there either.
|
|
667
|
+
if (valueWasString && safeBuffer().hasCrlf(valueStr)) {
|
|
668
|
+
throw new TypeError(
|
|
669
|
+
"crypto.namespaceHash: value (string-typed) contains CR / LF — refuse"
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
return hash(prefix + ":" + valueStr, "sha3-512").toString("hex");
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// _suiteFixedInfo — NIST SP 800-56C r2 §4.1 OtherInfo / RFC 9180
|
|
676
|
+
// (HPKE) §5.1 suite_id binding. Returns the byte string that the KDF
|
|
677
|
+
// MUST absorb alongside the shared-secret(s) so a key derived under
|
|
678
|
+
// one suite is not silently usable under a different suite. Same
|
|
679
|
+
// label is recovered on decrypt by re-reading the envelope-prefix
|
|
680
|
+
// bytes (kemId / cipherId / kdfId).
|
|
681
|
+
function _suiteFixedInfo(kemId, cipherId, kdfId) {
|
|
682
|
+
return Buffer.concat([
|
|
683
|
+
Buffer.from(C.ENVELOPE_FIXED_INFO_LABEL, "utf8"),
|
|
684
|
+
Buffer.from([0x00, kemId, cipherId, kdfId, 0x00]),
|
|
685
|
+
]);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// ---- Random ----
|
|
689
|
+
/**
|
|
690
|
+
* @primitive b.crypto.generateBytes
|
|
691
|
+
* @signature b.crypto.generateBytes(byteLength)
|
|
692
|
+
* @since 0.1.0
|
|
693
|
+
* @related b.crypto.generateToken, b.uuid.v4
|
|
694
|
+
*
|
|
695
|
+
* Cryptographically secure random Buffer of length `byteLength`
|
|
696
|
+
* (default 32). The bytes are SHAKE256(OS-RNG bytes) — defense-in-
|
|
697
|
+
* depth over `crypto.randomBytes` so a hypothetical OS-RNG weakness
|
|
698
|
+
* is not directly observable downstream. Use for session IDs, KDF
|
|
699
|
+
* salts, AEAD nonces, anything requiring unpredictable bytes.
|
|
700
|
+
*
|
|
701
|
+
* @example
|
|
702
|
+
* var sessionId = b.crypto.generateBytes(16).toString("hex");
|
|
703
|
+
* // → "5b8f2a4c7d1e9f0b3c6a8d2e4f7c1b5d" (32 hex chars, 16 random bytes)
|
|
704
|
+
*
|
|
705
|
+
* var nonce = b.crypto.generateBytes(24); // XChaCha20-Poly1305 nonce
|
|
706
|
+
* nonce.length;
|
|
707
|
+
* // → 24
|
|
708
|
+
*/
|
|
709
|
+
function generateBytes(byteLength) { return Buffer.from(random(byteLength)); }
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* @primitive b.crypto.generateToken
|
|
713
|
+
* @signature b.crypto.generateToken(byteLength)
|
|
714
|
+
* @since 0.1.0
|
|
715
|
+
* @related b.crypto.generateBytes, b.uuid.v4
|
|
716
|
+
*
|
|
717
|
+
* Hex-encoded random token. Same entropy source as `generateBytes`
|
|
718
|
+
* (SHAKE256 over OS-RNG bytes) but returned as a lowercase hex string
|
|
719
|
+
* — convenient for HTTP headers, URL parameters, log fields, or any
|
|
720
|
+
* context where a Buffer would need to be encoded anyway. Default
|
|
721
|
+
* `byteLength` is 32 (64 hex chars, ~256 bits of entropy).
|
|
722
|
+
*
|
|
723
|
+
* @example
|
|
724
|
+
* var token = b.crypto.generateToken();
|
|
725
|
+
* token.length;
|
|
726
|
+
* // → 64 (32 bytes hex-encoded)
|
|
727
|
+
*
|
|
728
|
+
* var shortId = b.crypto.generateToken(8);
|
|
729
|
+
* // → "a3f9...b1" (16 hex chars, 8 random bytes)
|
|
730
|
+
*/
|
|
731
|
+
function generateToken(byteLength) { return random(byteLength || 32).toString("hex"); }
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* @primitive b.crypto.toBase64Url
|
|
735
|
+
* @signature b.crypto.toBase64Url(buf)
|
|
736
|
+
* @since 0.9.45
|
|
737
|
+
* @status stable
|
|
738
|
+
* @related b.crypto.fromBase64Url
|
|
739
|
+
*
|
|
740
|
+
* RFC 4648 §5 base64url-encode a Buffer / Uint8Array / string. Routes
|
|
741
|
+
* through Node's built-in `"base64url"` encoding rather than the
|
|
742
|
+
* historical inline `.toString("base64").replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_")`
|
|
743
|
+
* pattern. Without this helper, every JWS / JWT / DPoP / WebAuthn /
|
|
744
|
+
* DNS-base64url / pagination-cursor / GCS-signed-URL call site
|
|
745
|
+
* reinvented the same three-replace pipeline — and the trailing
|
|
746
|
+
* `=+$` regex is polynomial-ReDoS-vulnerable per CodeQL
|
|
747
|
+
* `js/polynomial-redos`. Node's built-in encoder is linear time, no
|
|
748
|
+
* regex, no backtracking surface.
|
|
749
|
+
*
|
|
750
|
+
* Input shape: Buffer / Uint8Array → encoded; string → treated as
|
|
751
|
+
* UTF-8 bytes then encoded.
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* b.crypto.toBase64Url(Buffer.from("hello"));
|
|
755
|
+
* // → "aGVsbG8"
|
|
756
|
+
*
|
|
757
|
+
* b.crypto.toBase64Url("hello");
|
|
758
|
+
* // → "aGVsbG8"
|
|
759
|
+
*/
|
|
760
|
+
function toBase64Url(buf) {
|
|
761
|
+
if (typeof buf === "string") return Buffer.from(buf, "utf8").toString("base64url");
|
|
762
|
+
if (Buffer.isBuffer(buf)) return buf.toString("base64url");
|
|
763
|
+
if (buf instanceof Uint8Array) return Buffer.from(buf).toString("base64url");
|
|
764
|
+
throw new TypeError("crypto.toBase64Url: input must be Buffer, Uint8Array, or string");
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* @primitive b.crypto.fromBase64Url
|
|
769
|
+
* @signature b.crypto.fromBase64Url(s, opts?)
|
|
770
|
+
* @since 0.9.45
|
|
771
|
+
* @status stable
|
|
772
|
+
* @related b.crypto.toBase64Url
|
|
773
|
+
*
|
|
774
|
+
* RFC 4648 §5 base64url-decode a string into a Buffer. Inverse of
|
|
775
|
+
* `toBase64Url`. Operators previously reached for `Buffer.from(s,
|
|
776
|
+
* "base64url")` directly; this wrapper validates the input is a
|
|
777
|
+
* string + provides a single grep-able call site for the round-trip
|
|
778
|
+
* pair.
|
|
779
|
+
*
|
|
780
|
+
* Strict mode (default) refuses non-canonical input — chars outside
|
|
781
|
+
* the RFC 4648 §5 alphabet, length-mod-4-of-1, mixed `+/` from
|
|
782
|
+
* standard base64, trailing garbage. Defends a CVE-2022-0235-class
|
|
783
|
+
* footgun where Node's permissive decoder silently tolerated
|
|
784
|
+
* tampered JWT signatures. Operators with a documented lossy legacy
|
|
785
|
+
* payload opt out per call via `{ strict: false }`.
|
|
786
|
+
*
|
|
787
|
+
* @opts
|
|
788
|
+
* strict: boolean // default: true — refuse non-canonical input
|
|
789
|
+
*
|
|
790
|
+
* @example
|
|
791
|
+
* var buf = b.crypto.fromBase64Url("aGVsbG8");
|
|
792
|
+
* buf.toString("utf8");
|
|
793
|
+
* // → "hello"
|
|
794
|
+
*/
|
|
795
|
+
// RFC 4648 §5 alphabet for base64url, with optional padding. The
|
|
796
|
+
// canonical form has no padding, the URL-safe alphabet (`-_`), and a
|
|
797
|
+
// length consistent with the byte count (length % 4 ∈ {0, 2, 3}; the
|
|
798
|
+
// `length % 4 === 1` shape is impossible to produce by any conforming
|
|
799
|
+
// encoder and signals truncated / forged input).
|
|
800
|
+
var _BASE64URL_STRICT_RE = /^[A-Za-z0-9_-]*={0,2}$/;
|
|
801
|
+
|
|
802
|
+
function fromBase64Url(s, opts) {
|
|
803
|
+
if (typeof s !== "string") {
|
|
804
|
+
throw new TypeError("crypto.fromBase64Url: input must be a string");
|
|
805
|
+
}
|
|
806
|
+
// Crypto callers (JWT signature payloads, JWS / COSE encoded values,
|
|
807
|
+
// OAuth `state` round-tripping) MUST reject non-canonical / malformed
|
|
808
|
+
// input. The Node base64url decoder silently tolerates trailing
|
|
809
|
+
// garbage, mixed `+/` from standard base64, missing padding errors,
|
|
810
|
+
// and length-mod-4 shapes — CVE-2022-0235-class footgun. Strict mode
|
|
811
|
+
// (the default) refuses anything outside the RFC 4648 §5 alphabet +
|
|
812
|
+
// length rules. Operators with a known-lossy legacy payload pass
|
|
813
|
+
// `{ strict: false }` to opt out per call.
|
|
814
|
+
var strict = !opts || opts.strict !== false;
|
|
815
|
+
if (strict) {
|
|
816
|
+
// Manual trailing-`=` strip — avoids the polynomial-regex shape
|
|
817
|
+
// `/=+$/` CodeQL flags, where `=+` can backtrack on long input
|
|
818
|
+
// ending in many `=`. Walking from end is O(n) worst-case.
|
|
819
|
+
var trimEnd = s.length;
|
|
820
|
+
while (trimEnd > 0 && s.charCodeAt(trimEnd - 1) === 0x3D) trimEnd -= 1; // allow:raw-byte-literal — '=' codepoint
|
|
821
|
+
var unpadded = s.slice(0, trimEnd);
|
|
822
|
+
if (!_BASE64URL_STRICT_RE.test(s)) {
|
|
823
|
+
throw new TypeError(
|
|
824
|
+
"crypto.fromBase64Url: input contains characters outside RFC 4648 §5 " +
|
|
825
|
+
"base64url alphabet (A-Z a-z 0-9 - _ =) — pass {strict:false} to allow non-canonical input"
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
if (unpadded.length % 4 === 1) { // allow:raw-byte-literal — base64 group length, not bytes
|
|
829
|
+
throw new TypeError(
|
|
830
|
+
"crypto.fromBase64Url: input length %% 4 === 1 is not a valid base64url encoding " +
|
|
831
|
+
"(every conforming encoder produces 0 / 2 / 3 remainder; got " + unpadded.length + " chars)"
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
return Buffer.from(s, "base64url");
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// ---- Subresource Integrity (W3C SRI 1.0) ----
|
|
839
|
+
//
|
|
840
|
+
// b.crypto.sri(content, { algorithm? }) — returns a `sha###-base64`
|
|
841
|
+
// integrity attribute string operators paste into <script integrity="...">
|
|
842
|
+
// or <link integrity="..."> tags. Defends against CDN compromise + ISP
|
|
843
|
+
// MITM injection — the browser refuses to load the resource when its
|
|
844
|
+
// hash diverges from the integrity attribute.
|
|
845
|
+
//
|
|
846
|
+
// W3C SRI 1.0 §3.2 lists sha256 / sha384 / sha512 as the supported
|
|
847
|
+
// digest algorithms; sha384 is the recommended default (collision
|
|
848
|
+
// margin without sha512's 64-byte overhead).
|
|
849
|
+
//
|
|
850
|
+
// b.crypto.sri(scriptBuffer, { algorithm: "sha384" })
|
|
851
|
+
// → "sha384-AbCdEf...="
|
|
852
|
+
//
|
|
853
|
+
// b.crypto.sri(["a", "b"], { algorithm: "sha384" }) // array → multi-hash
|
|
854
|
+
// → "sha384-X1... sha384-X2..." (per W3C §3.3 multi-integrity)
|
|
855
|
+
var SRI_ALGORITHMS = { "sha256": "sha256", "sha384": "sha384", "sha512": "sha512" };
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* @primitive b.crypto.sri
|
|
859
|
+
* @signature b.crypto.sri(content, opts)
|
|
860
|
+
* @since 0.5.0
|
|
861
|
+
* @related b.staticServe
|
|
862
|
+
*
|
|
863
|
+
* Computes a W3C Subresource Integrity 1.0 attribute string —
|
|
864
|
+
* `sha###-base64` — that operators paste into `<script integrity>` or
|
|
865
|
+
* `<link integrity>` tags. Defends against CDN compromise and ISP
|
|
866
|
+
* MITM injection: the browser refuses to load the resource when its
|
|
867
|
+
* computed hash diverges from the integrity attribute. SRI 1.0 §3.2
|
|
868
|
+
* supports sha256 / sha384 / sha512; sha384 is the recommended
|
|
869
|
+
* default (collision margin without sha512's 64-byte overhead). Pass
|
|
870
|
+
* an array of contents to emit multiple integrity tokens space-
|
|
871
|
+
* separated per §3.3 (browser picks the strongest it recognizes).
|
|
872
|
+
*
|
|
873
|
+
* @opts
|
|
874
|
+
* algorithm: string, // "sha256" | "sha384" | "sha512" — default "sha384"
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
877
|
+
* var attr = b.crypto.sri(Buffer.from("alert(1);", "utf8"), { algorithm: "sha384" });
|
|
878
|
+
* // → "sha384-pNdyOuHIPKgRPnYJTBxEEEZcJj1qHxJzNheCuHGRy3Cm0UpVbcnruIvMRIs5VcDb"
|
|
879
|
+
*
|
|
880
|
+
* var multi = b.crypto.sri(["payload-a", "payload-b"], { algorithm: "sha512" });
|
|
881
|
+
* // → "sha512-... sha512-..." (two tokens, space-separated)
|
|
882
|
+
*/
|
|
883
|
+
function sri(content, opts) {
|
|
884
|
+
opts = opts || {};
|
|
885
|
+
var algorithm = (opts.algorithm || "sha384").toLowerCase();
|
|
886
|
+
if (!SRI_ALGORITHMS[algorithm]) {
|
|
887
|
+
throw new Error("crypto.sri: unsupported algorithm '" + algorithm +
|
|
888
|
+
"' (W3C SRI 1.0 §3.2 supports sha256/sha384/sha512)");
|
|
889
|
+
}
|
|
890
|
+
// Array input — emit multiple integrity tokens space-separated per
|
|
891
|
+
// W3C §3.3 (browser picks the strongest one it recognizes).
|
|
892
|
+
if (Array.isArray(content)) {
|
|
893
|
+
return content.map(function (c) { return sri(c, opts); }).join(" ");
|
|
894
|
+
}
|
|
895
|
+
var buf;
|
|
896
|
+
if (Buffer.isBuffer(content)) buf = content;
|
|
897
|
+
else if (typeof content === "string") buf = Buffer.from(content, "utf8");
|
|
898
|
+
else if (content instanceof Uint8Array) buf = Buffer.from(content);
|
|
899
|
+
else throw new Error("crypto.sri: content must be a Buffer, Uint8Array, string, or array of those");
|
|
900
|
+
var digest = nodeCrypto.createHash(algorithm).update(buf).digest("base64");
|
|
901
|
+
return algorithm + "-" + digest;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// ---- Key generation ----
|
|
905
|
+
/**
|
|
906
|
+
* @primitive b.crypto.generateEncryptionKeyPair
|
|
907
|
+
* @signature b.crypto.generateEncryptionKeyPair()
|
|
908
|
+
* @since 0.1.0
|
|
909
|
+
* @related b.crypto.encrypt, b.crypto.decrypt, b.crypto.generateMlkem768X25519KeyPair
|
|
910
|
+
*
|
|
911
|
+
* Generates a hybrid recipient keypair for `b.crypto.encrypt`:
|
|
912
|
+
* ML-KEM-1024 (FIPS 203 PQC KEM) plus ECDH P-384 (classical defense-
|
|
913
|
+
* in-depth). Returns `{ publicKey, privateKey, ecPublicKey,
|
|
914
|
+
* ecPrivateKey }` — all four PEMs. Persist the private halves in
|
|
915
|
+
* sealed storage; publish the public halves to recipients. The
|
|
916
|
+
* framework default for at-rest envelopes and api-encrypt strategies.
|
|
917
|
+
*
|
|
918
|
+
* @example
|
|
919
|
+
* var pair = b.crypto.generateEncryptionKeyPair();
|
|
920
|
+
* var sealed = b.crypto.encrypt("secret payload", {
|
|
921
|
+
* publicKey: pair.publicKey,
|
|
922
|
+
* ecPublicKey: pair.ecPublicKey,
|
|
923
|
+
* });
|
|
924
|
+
* var roundTrip = b.crypto.decrypt(sealed, {
|
|
925
|
+
* privateKey: pair.privateKey,
|
|
926
|
+
* ecPrivateKey: pair.ecPrivateKey,
|
|
927
|
+
* });
|
|
928
|
+
* // → "secret payload"
|
|
929
|
+
*/
|
|
930
|
+
function generateEncryptionKeyPair() {
|
|
931
|
+
var mlkem = generateKeyPair("ml-kem-1024");
|
|
932
|
+
var ec = generateKeyPair("ec", { namedCurve: "P-384" });
|
|
933
|
+
return {
|
|
934
|
+
publicKey: mlkem.publicKey,
|
|
935
|
+
privateKey: mlkem.privateKey,
|
|
936
|
+
ecPublicKey: ec.publicKey,
|
|
937
|
+
ecPrivateKey: ec.privateKey,
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/**
|
|
942
|
+
* @primitive b.crypto.generateSigningKeyPair
|
|
943
|
+
* @signature b.crypto.generateSigningKeyPair(algorithm)
|
|
944
|
+
* @since 0.1.0
|
|
945
|
+
* @related b.crypto.sign, b.crypto.verify
|
|
946
|
+
*
|
|
947
|
+
* Generates a PQC signature keypair. Default algorithm is `ml-dsa-87`
|
|
948
|
+
* (FIPS 204 — lattice-based, fast verify); pass `slh-dsa-shake-256f`
|
|
949
|
+
* for hash-based signatures (larger, slower, but minimal cryptographic
|
|
950
|
+
* assumptions — useful for long-lived audit-chain keys). Returns
|
|
951
|
+
* `{ publicKey, privateKey }` PEMs. The signing primitives auto-
|
|
952
|
+
* detect the algorithm from the key PEM, so callers don't need to
|
|
953
|
+
* pass it explicitly to `sign` / `verify`.
|
|
954
|
+
*
|
|
955
|
+
* @example
|
|
956
|
+
* var pair = b.crypto.generateSigningKeyPair();
|
|
957
|
+
* var sig = b.crypto.sign("audit:row=42|action=delete", pair.privateKey);
|
|
958
|
+
* var ok = b.crypto.verify("audit:row=42|action=delete", sig, pair.publicKey);
|
|
959
|
+
* // → true
|
|
960
|
+
*
|
|
961
|
+
* // Hash-based alternative:
|
|
962
|
+
* var slh = b.crypto.generateSigningKeyPair("slh-dsa-shake-256f");
|
|
963
|
+
*/
|
|
964
|
+
function generateSigningKeyPair(algorithm) {
|
|
965
|
+
return generateKeyPair(algorithm || "ml-dsa-87");
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// ---- Signatures (auto-detect algorithm from key PEM) ----
|
|
969
|
+
/**
|
|
970
|
+
* @primitive b.crypto.sign
|
|
971
|
+
* @signature b.crypto.sign(data, privateKeyPem)
|
|
972
|
+
* @since 0.1.0
|
|
973
|
+
* @related b.crypto.verify, b.crypto.generateSigningKeyPair
|
|
974
|
+
*
|
|
975
|
+
* Produces a PQC signature over `data`. Algorithm is auto-detected
|
|
976
|
+
* from the private-key PEM (ML-DSA-87 lattice / SLH-DSA-SHAKE-256f
|
|
977
|
+
* hash-based). Returns a Buffer. Pair with `b.crypto.verify` on the
|
|
978
|
+
* recipient side; use for audit-chain links, webhook tags,
|
|
979
|
+
* cross-service request signatures.
|
|
980
|
+
*
|
|
981
|
+
* @example
|
|
982
|
+
* var pair = b.crypto.generateSigningKeyPair();
|
|
983
|
+
* var sig = b.crypto.sign("payload-to-sign", pair.privateKey);
|
|
984
|
+
* sig.length > 0;
|
|
985
|
+
* // → true (ML-DSA-87 signature ~ 4627 bytes)
|
|
986
|
+
*/
|
|
987
|
+
function sign(data, privateKeyPem) {
|
|
988
|
+
return nodeCrypto.sign(null, Buffer.from(data), privateKeyPem);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* @primitive b.crypto.verify
|
|
993
|
+
* @signature b.crypto.verify(data, signature, publicKeyPem)
|
|
994
|
+
* @since 0.1.0
|
|
995
|
+
* @related b.crypto.sign, b.crypto.generateSigningKeyPair
|
|
996
|
+
*
|
|
997
|
+
* Verifies a signature produced by `b.crypto.sign`. Returns `true` on
|
|
998
|
+
* a valid signature, `false` otherwise — never throws on a malformed
|
|
999
|
+
* signature, so operators don't need to wrap the call. Algorithm is
|
|
1000
|
+
* auto-detected from the public-key PEM.
|
|
1001
|
+
*
|
|
1002
|
+
* @example
|
|
1003
|
+
* var pair = b.crypto.generateSigningKeyPair();
|
|
1004
|
+
* var sig = b.crypto.sign("hello", pair.privateKey);
|
|
1005
|
+
* var ok = b.crypto.verify("hello", sig, pair.publicKey);
|
|
1006
|
+
* // → true
|
|
1007
|
+
*
|
|
1008
|
+
* var tampered = b.crypto.verify("HELLO", sig, pair.publicKey);
|
|
1009
|
+
* // → false (data mismatch)
|
|
1010
|
+
*/
|
|
1011
|
+
function verify(data, signature, publicKeyPem) {
|
|
1012
|
+
return nodeCrypto.verify(null, Buffer.from(data), publicKeyPem, signature);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// Track whether the hybrid-disabled audit has been emitted at least
|
|
1016
|
+
// once per process, so a high-volume KEM-only deployment doesn't peg
|
|
1017
|
+
// the audit bus with one event per encrypt() call. Operators who want
|
|
1018
|
+
// the per-call signal can call encryptMlkemOnly directly (which never
|
|
1019
|
+
// emits) or read the metric at b.metrics — the count is preserved.
|
|
1020
|
+
var _hybridDisabledAuditEmitted = false;
|
|
1021
|
+
|
|
1022
|
+
// ---- Envelope encrypt (ML-KEM-1024 + P-384 ECDH hybrid + SHAKE256 + XChaCha20) ----
|
|
1023
|
+
/**
|
|
1024
|
+
* @primitive b.crypto.encrypt
|
|
1025
|
+
* @signature b.crypto.encrypt(plaintext, publicKeys)
|
|
1026
|
+
* @since 0.1.0
|
|
1027
|
+
* @related b.crypto.decrypt, b.crypto.generateEncryptionKeyPair, b.crypto.encryptMlkem768X25519
|
|
1028
|
+
*
|
|
1029
|
+
* Seals `plaintext` into a base64 envelope under the recipient's
|
|
1030
|
+
* keypair. Default suite is ML-KEM-1024 + ECDH P-384 hybrid (FIPS 203
|
|
1031
|
+
* KEM with classical defense-in-depth) plus SHAKE256 KDF and
|
|
1032
|
+
* XChaCha20-Poly1305 AEAD. The 4-byte envelope header (magic + KEM
|
|
1033
|
+
* ID + cipher ID + KDF ID) is bound as AEAD AAD so an algorithm-
|
|
1034
|
+
* substitution attack on the header fails Poly1305 verification.
|
|
1035
|
+
* Pass `{ publicKey, ecPublicKey }` for the hybrid path; passing only
|
|
1036
|
+
* an ML-KEM PEM falls back to KEM-only and emits a one-shot
|
|
1037
|
+
* `system.crypto.hybrid_disabled` audit (operators wanting the silent
|
|
1038
|
+
* KEM-only path call `encryptMlkem768X25519` or seal manually).
|
|
1039
|
+
*
|
|
1040
|
+
* @example
|
|
1041
|
+
* var pair = b.crypto.generateEncryptionKeyPair();
|
|
1042
|
+
* var sealed = b.crypto.encrypt("PHI: patient-42 dx=...", {
|
|
1043
|
+
* publicKey: pair.publicKey,
|
|
1044
|
+
* ecPublicKey: pair.ecPublicKey,
|
|
1045
|
+
* });
|
|
1046
|
+
* typeof sealed;
|
|
1047
|
+
* // → "string" (base64 envelope)
|
|
1048
|
+
*
|
|
1049
|
+
* var plain = b.crypto.decrypt(sealed, {
|
|
1050
|
+
* privateKey: pair.privateKey,
|
|
1051
|
+
* ecPrivateKey: pair.ecPrivateKey,
|
|
1052
|
+
* });
|
|
1053
|
+
* // → "PHI: patient-42 dx=..."
|
|
1054
|
+
*/
|
|
1055
|
+
function encrypt(plaintext, publicKeys) {
|
|
1056
|
+
var mlkemPubPem = typeof publicKeys === "string" ? publicKeys : publicKeys.publicKey;
|
|
1057
|
+
var ecPubPem = typeof publicKeys === "string" ? null : publicKeys.ecPublicKey;
|
|
1058
|
+
if (!ecPubPem) {
|
|
1059
|
+
// Operator passed only an ML-KEM public key — silently dropping
|
|
1060
|
+
// the P-384 hybrid leg means the operator's defense-in-depth
|
|
1061
|
+
// posture (classical ECDH backstop on top of PQC KEM) is gone
|
|
1062
|
+
// without any signal. Audit ONCE per process (M2 audit-dedup —
|
|
1063
|
+
// pre-v0.8.22 every plain-KEM call emitted, pegging the audit
|
|
1064
|
+
// bus). Operators who genuinely want KEM-only should call
|
|
1065
|
+
// encryptMlkemOnly explicitly so this audit doesn't fire.
|
|
1066
|
+
if (!_hybridDisabledAuditEmitted) {
|
|
1067
|
+
_hybridDisabledAuditEmitted = true;
|
|
1068
|
+
setImmediate(function () {
|
|
1069
|
+
try {
|
|
1070
|
+
audit().safeEmit({
|
|
1071
|
+
action: "system.crypto.hybrid_disabled",
|
|
1072
|
+
outcome: "success",
|
|
1073
|
+
metadata: { reason: "no-ec-public-key", note: "encrypt() received only mlkem; ecPublicKey absent — call encryptMlkemOnly explicitly to silence (audited once per process)" },
|
|
1074
|
+
});
|
|
1075
|
+
} catch (_e) { /* drop-silent — best-effort */ }
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
return encryptMlkemOnly(plaintext, mlkemPubPem);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
var mlkemPub = nodeCrypto.createPublicKey(mlkemPubPem);
|
|
1082
|
+
var kem = nodeCrypto.encapsulate(mlkemPub);
|
|
1083
|
+
var ephEc = generateKeyPair("ec", {
|
|
1084
|
+
namedCurve: "P-384",
|
|
1085
|
+
publicKeyEncoding: { type: "spki", format: "der" },
|
|
1086
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
1087
|
+
});
|
|
1088
|
+
var ecSs = nodeCrypto.diffieHellman({
|
|
1089
|
+
privateKey: nodeCrypto.createPrivateKey(ephEc.privateKey),
|
|
1090
|
+
publicKey: nodeCrypto.createPublicKey(ecPubPem),
|
|
1091
|
+
});
|
|
1092
|
+
var key = kdf(Buffer.concat([kem.sharedKey, ecSs,
|
|
1093
|
+
_suiteFixedInfo(C.ACTIVE.KEM, C.ACTIVE.CIPHER, C.ACTIVE.KDF)]),
|
|
1094
|
+
C.BYTES.bytes(32));
|
|
1095
|
+
var nonce = generateBytes(C.BYTES.bytes(24));
|
|
1096
|
+
// Bind the 4-byte envelope header (MAGIC + kemId + cipherId + kdfId)
|
|
1097
|
+
// as AAD so a tampered header (algorithm-substitution attack) fails
|
|
1098
|
+
// the Poly1305 tag.
|
|
1099
|
+
var headerAad = Buffer.from([C.ENVELOPE_MAGIC, C.ACTIVE.KEM, C.ACTIVE.CIPHER, C.ACTIVE.KDF]);
|
|
1100
|
+
var ct = xchacha20poly1305(key, nonce, headerAad).encrypt(Buffer.from(plaintext, "utf8"));
|
|
1101
|
+
|
|
1102
|
+
var kemCtLen = Buffer.alloc(2); kemCtLen.writeUInt16BE(kem.ciphertext.length);
|
|
1103
|
+
var ecEphDer = ephEc.publicKey;
|
|
1104
|
+
var ecEphLen = Buffer.alloc(2); ecEphLen.writeUInt16BE(ecEphDer.length);
|
|
1105
|
+
|
|
1106
|
+
return Buffer.concat([
|
|
1107
|
+
headerAad,
|
|
1108
|
+
kemCtLen, kem.ciphertext, ecEphLen, ecEphDer, nonce, Buffer.from(ct),
|
|
1109
|
+
]).toString("base64");
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
function encryptMlkemOnly(plaintext, publicKeyPem) {
|
|
1113
|
+
var kem = nodeCrypto.encapsulate(nodeCrypto.createPublicKey(publicKeyPem));
|
|
1114
|
+
var key = kdf(Buffer.concat([kem.sharedKey,
|
|
1115
|
+
_suiteFixedInfo(C.KEM_IDS.ML_KEM_1024, C.ACTIVE.CIPHER, C.ACTIVE.KDF)]),
|
|
1116
|
+
C.BYTES.bytes(32));
|
|
1117
|
+
var nonce = generateBytes(C.BYTES.bytes(24));
|
|
1118
|
+
var headerAad = Buffer.from([C.ENVELOPE_MAGIC, C.KEM_IDS.ML_KEM_1024,
|
|
1119
|
+
C.ACTIVE.CIPHER, C.ACTIVE.KDF]);
|
|
1120
|
+
var ct = xchacha20poly1305(key, nonce, headerAad).encrypt(Buffer.from(plaintext, "utf8"));
|
|
1121
|
+
var kemCtLen = Buffer.alloc(2); kemCtLen.writeUInt16BE(kem.ciphertext.length);
|
|
1122
|
+
return Buffer.concat([
|
|
1123
|
+
headerAad,
|
|
1124
|
+
kemCtLen, kem.ciphertext, nonce, Buffer.from(ct),
|
|
1125
|
+
]).toString("base64");
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// ---- Envelope decrypt (dispatches on envelope IDs, supports both KEM IDs) ----
|
|
1129
|
+
/**
|
|
1130
|
+
* @primitive b.crypto.decrypt
|
|
1131
|
+
* @signature b.crypto.decrypt(ciphertext, privateKeys, opts?)
|
|
1132
|
+
* @since 0.1.0
|
|
1133
|
+
* @related b.crypto.encrypt, b.crypto.generateEncryptionKeyPair, b.crypto.decryptMlkem768X25519
|
|
1134
|
+
*
|
|
1135
|
+
* Opens a base64 envelope produced by `b.crypto.encrypt`. The
|
|
1136
|
+
* envelope header is parsed first and the decrypt path dispatches by
|
|
1137
|
+
* KEM ID — ML-KEM-1024 + P-384, ML-KEM-1024 KEM-only, or ML-KEM-768 +
|
|
1138
|
+
* X25519 — so old envelopes continue to decrypt under whichever suite
|
|
1139
|
+
* sealed them while new writes use the active suite. Throws on
|
|
1140
|
+
* malformed magic, unsupported cipher / KDF, or Poly1305 tag failure.
|
|
1141
|
+
* Pass `{ privateKey, ecPrivateKey }` for the default hybrid; the
|
|
1142
|
+
* ML-KEM-768 + X25519 KEM ID also requires `x25519PrivateKey`.
|
|
1143
|
+
*
|
|
1144
|
+
* ## Legacy 0xE1 envelopes (`opts.allowLegacy: true`)
|
|
1145
|
+
*
|
|
1146
|
+
* The framework's envelope magic byte was bumped from 0xE1 to 0xE2
|
|
1147
|
+
* pre-v1 to enforce a NIST SP 800-56C r2 §4.1 FixedInfo / RFC 9180
|
|
1148
|
+
* §5.1 suite-binding KDF input — SHAKE256 absorbs the suite-id triple
|
|
1149
|
+
* (kemId / cipherId / kdfId) plus the literal "blamejs/v1" label
|
|
1150
|
+
* alongside the shared secret(s), so the same key cannot be reused
|
|
1151
|
+
* across suites without distinct derived material. 0xE1 envelopes
|
|
1152
|
+
* lack this binding.
|
|
1153
|
+
*
|
|
1154
|
+
* By default 0xE1 envelopes are refused with a hard error directing
|
|
1155
|
+
* the operator to re-seal under 0xE2. Operators with at-rest data
|
|
1156
|
+
* sealed pre-bump (rare; the bump landed before any operator started
|
|
1157
|
+
* depending on the framework) pass `opts.allowLegacy: true` to read
|
|
1158
|
+
* the old envelope, then immediately re-seal via `b.crypto.encrypt`
|
|
1159
|
+
* to migrate. Each legacy decrypt emits a `crypto.decrypt.allow_legacy`
|
|
1160
|
+
* audit event so the migration window is visible in the audit log.
|
|
1161
|
+
*
|
|
1162
|
+
* @opts
|
|
1163
|
+
* allowLegacy: boolean // default false — when true, 0xE1 envelopes
|
|
1164
|
+
* // decrypt via the pre-FixedInfo KDF path
|
|
1165
|
+
*
|
|
1166
|
+
* @example
|
|
1167
|
+
* var pair = b.crypto.generateEncryptionKeyPair();
|
|
1168
|
+
* var sealed = b.crypto.encrypt("session-token=abc123", {
|
|
1169
|
+
* publicKey: pair.publicKey,
|
|
1170
|
+
* ecPublicKey: pair.ecPublicKey,
|
|
1171
|
+
* });
|
|
1172
|
+
* var opened = b.crypto.decrypt(sealed, {
|
|
1173
|
+
* privateKey: pair.privateKey,
|
|
1174
|
+
* ecPrivateKey: pair.ecPrivateKey,
|
|
1175
|
+
* });
|
|
1176
|
+
* // → "session-token=abc123"
|
|
1177
|
+
*
|
|
1178
|
+
* // Legacy 0xE1 migration:
|
|
1179
|
+
* var plaintext = b.crypto.decrypt(legacyBlob, oldKeys, { allowLegacy: true });
|
|
1180
|
+
* var resealed = b.crypto.encrypt(plaintext, newKeys); // now 0xE2
|
|
1181
|
+
*/
|
|
1182
|
+
function decrypt(ciphertext, privateKeys, opts) {
|
|
1183
|
+
var packed = Buffer.from(ciphertext, "base64");
|
|
1184
|
+
if (packed[0] === 0xE1) { // allow:raw-byte-literal — legacy envelope magic
|
|
1185
|
+
if (!opts || !opts.allowLegacy) {
|
|
1186
|
+
throw new Error("Invalid envelope: legacy 0xE1 format predates the FixedInfo " +
|
|
1187
|
+
"KDF binding (NIST SP 800-56C r2 §4.1) — re-seal data under the current envelope, " +
|
|
1188
|
+
"or pass { allowLegacy: true } to opt in to one-shot read for migration");
|
|
1189
|
+
}
|
|
1190
|
+
// Audit-emit every legacy decrypt so the migration window is
|
|
1191
|
+
// visible. Emit success ONLY on actual decrypt success; emit
|
|
1192
|
+
// failure on throw. Codex P2 PR #74 — pre-fix the audit fired
|
|
1193
|
+
// before decryptEnvelope() ran, so corrupted 0xE1 blobs / wrong
|
|
1194
|
+
// private keys / unsupported KEMs got logged as successful legacy
|
|
1195
|
+
// decrypts when the call actually threw, inflating real success
|
|
1196
|
+
// rates during migration windows. Audit module is top-of-file
|
|
1197
|
+
// lazy-loaded (var audit above) so this hot-path emit doesn't
|
|
1198
|
+
// re-resolve the require() cache on every legacy decrypt.
|
|
1199
|
+
function _emitLegacyAudit(outcome, extra) {
|
|
1200
|
+
setImmediate(function () {
|
|
1201
|
+
try {
|
|
1202
|
+
audit().safeEmit({
|
|
1203
|
+
action: "system.crypto.decrypt.allow_legacy",
|
|
1204
|
+
outcome: outcome,
|
|
1205
|
+
metadata: Object.assign({ magic: "0xE1", kemId: packed[1] }, extra || {}),
|
|
1206
|
+
});
|
|
1207
|
+
} catch (_e) { /* drop-silent — audit best-effort */ }
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
var plaintext;
|
|
1211
|
+
try {
|
|
1212
|
+
plaintext = decryptEnvelope(packed, privateKeys, { omitFixedInfo: true });
|
|
1213
|
+
} catch (e) {
|
|
1214
|
+
_emitLegacyAudit("failure", { reason: (e && e.message) || "decrypt threw" });
|
|
1215
|
+
throw e;
|
|
1216
|
+
}
|
|
1217
|
+
_emitLegacyAudit("success", {});
|
|
1218
|
+
return plaintext;
|
|
1219
|
+
}
|
|
1220
|
+
if (packed[0] !== C.ENVELOPE_MAGIC) {
|
|
1221
|
+
throw new Error("Invalid envelope: unsupported format");
|
|
1222
|
+
}
|
|
1223
|
+
// `opts.raw: true` returns the decrypted Buffer rather than the
|
|
1224
|
+
// utf8-decoded string. Callers carrying binary plaintext (JWE
|
|
1225
|
+
// experimental wrapper, future signed-blob carriers) opt in to keep
|
|
1226
|
+
// arbitrary bytes lossless; default stays utf8-string for backwards
|
|
1227
|
+
// compatibility with the existing API contract.
|
|
1228
|
+
return decryptEnvelope(packed, privateKeys,
|
|
1229
|
+
opts && opts.raw === true ? { raw: true } : undefined);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
function decryptEnvelope(packed, privateKeys, internalOpts) {
|
|
1233
|
+
var kemId = packed[1], cipherId = packed[2], kdfId = packed[3], pos = 4;
|
|
1234
|
+
|
|
1235
|
+
// The legacy 0xE1 envelope predates the FixedInfo / suite-binding
|
|
1236
|
+
// KDF input; the same wire format otherwise. The dispatcher passes
|
|
1237
|
+
// omitFixedInfo: true for the 0xE1 path and the KDF input below
|
|
1238
|
+
// skips the _suiteFixedInfo concat.
|
|
1239
|
+
var omitFixedInfo = !!(internalOpts && internalOpts.omitFixedInfo);
|
|
1240
|
+
|
|
1241
|
+
if (cipherId !== C.CIPHER_IDS.XCHACHA20_POLY1305) {
|
|
1242
|
+
throw new Error("Invalid envelope: unsupported cipher (only XChaCha20-Poly1305 supported)");
|
|
1243
|
+
}
|
|
1244
|
+
if (kdfId !== C.KDF_IDS.SHAKE256) {
|
|
1245
|
+
throw new Error("Invalid envelope: unsupported KDF (only SHAKE256 supported)");
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
var kemCtLen = packed.readUInt16BE(pos); pos += 2;
|
|
1249
|
+
var kemCt = packed.subarray(pos, pos + kemCtLen); pos += kemCtLen;
|
|
1250
|
+
|
|
1251
|
+
var mlkemPriv = nodeCrypto.createPrivateKey(
|
|
1252
|
+
typeof privateKeys === "string" ? privateKeys : privateKeys.privateKey
|
|
1253
|
+
);
|
|
1254
|
+
var mlkemSs = nodeCrypto.decapsulate(mlkemPriv, kemCt);
|
|
1255
|
+
var symmetricKey;
|
|
1256
|
+
var fixedInfo = omitFixedInfo ? Buffer.alloc(0) : _suiteFixedInfo(kemId, cipherId, kdfId);
|
|
1257
|
+
|
|
1258
|
+
if (kemId === C.KEM_IDS.ML_KEM_1024_P384) {
|
|
1259
|
+
var ecEphLen = packed.readUInt16BE(pos); pos += 2;
|
|
1260
|
+
var ecEphDer = packed.subarray(pos, pos + ecEphLen); pos += ecEphLen;
|
|
1261
|
+
var ecPrivPem = typeof privateKeys === "string" ? null : privateKeys.ecPrivateKey;
|
|
1262
|
+
if (!ecPrivPem) throw new Error("Hybrid KEM requires EC private key");
|
|
1263
|
+
var ecSs = nodeCrypto.diffieHellman({
|
|
1264
|
+
privateKey: nodeCrypto.createPrivateKey(ecPrivPem),
|
|
1265
|
+
publicKey: nodeCrypto.createPublicKey({ key: ecEphDer, type: "spki", format: "der" }),
|
|
1266
|
+
});
|
|
1267
|
+
symmetricKey = kdf(Buffer.concat([mlkemSs, ecSs, fixedInfo]), C.BYTES.bytes(32));
|
|
1268
|
+
} else if (kemId === C.KEM_IDS.ML_KEM_1024) {
|
|
1269
|
+
symmetricKey = kdf(Buffer.concat([mlkemSs, fixedInfo]), C.BYTES.bytes(32));
|
|
1270
|
+
} else if (kemId === C.KEM_IDS.ML_KEM_768_X25519) {
|
|
1271
|
+
// ML-KEM-768 + X25519 hybrid envelope. The mlkemPriv must be an
|
|
1272
|
+
// ML-KEM-768 key (not 1024); operators are responsible for passing
|
|
1273
|
+
// the correct keypair via privateKeys when the envelope was sealed
|
|
1274
|
+
// with this algorithm. Same length-prefixed shape as the P-384
|
|
1275
|
+
// hybrid: 2-byte ec-eph-len + DER X25519 pubkey + nonce + ct.
|
|
1276
|
+
var x25519EphLen = packed.readUInt16BE(pos); pos += 2;
|
|
1277
|
+
var x25519EphDer = packed.subarray(pos, pos + x25519EphLen); pos += x25519EphLen;
|
|
1278
|
+
var x25519PrivPem = typeof privateKeys === "string" ? null : privateKeys.x25519PrivateKey;
|
|
1279
|
+
if (!x25519PrivPem) throw new Error("ML-KEM-768 + X25519 hybrid envelope requires x25519PrivateKey");
|
|
1280
|
+
var x25519Ss = nodeCrypto.diffieHellman({
|
|
1281
|
+
privateKey: nodeCrypto.createPrivateKey(x25519PrivPem),
|
|
1282
|
+
publicKey: nodeCrypto.createPublicKey({ key: x25519EphDer, type: "spki", format: "der" }),
|
|
1283
|
+
});
|
|
1284
|
+
symmetricKey = kdf(Buffer.concat([mlkemSs, x25519Ss, fixedInfo]), C.BYTES.bytes(32));
|
|
1285
|
+
} else {
|
|
1286
|
+
throw new Error("Invalid envelope: unsupported KEM ID " + kemId);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
var nonce = packed.subarray(pos, pos + C.BYTES.bytes(24)); pos += C.BYTES.bytes(24);
|
|
1290
|
+
// Re-derive the 4-byte envelope-header AAD from the bytes we just
|
|
1291
|
+
// dispatched on. A tampered header (algorithm-substitution attack)
|
|
1292
|
+
// surfaces here as a Poly1305 tag verification failure.
|
|
1293
|
+
var headerAad = packed.subarray(0, 4); // allow:raw-byte-literal — envelope-header byte slice
|
|
1294
|
+
var plainBuf = Buffer.from(
|
|
1295
|
+
xchacha20poly1305(symmetricKey, nonce, headerAad).decrypt(packed.subarray(pos))
|
|
1296
|
+
);
|
|
1297
|
+
if (internalOpts && internalOpts.raw === true) return plainBuf;
|
|
1298
|
+
return plainBuf.toString("utf8");
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
// ---- Symmetric buffer encrypt/decrypt (for storage) ----
|
|
1302
|
+
//
|
|
1303
|
+
// Optional `aad` (additional authenticated data) is mixed into the
|
|
1304
|
+
// Poly1305 tag — encrypt-time and decrypt-time AAD must match exactly
|
|
1305
|
+
// or decrypt fails. Used by primitives that want encryption-context
|
|
1306
|
+
// binding (b.breakGlass.encryptCell binds (table, rowId, column) so a
|
|
1307
|
+
// ciphertext from row A literally cannot decrypt as row B even with
|
|
1308
|
+
// the same key).
|
|
1309
|
+
/**
|
|
1310
|
+
* @primitive b.crypto.encryptPacked
|
|
1311
|
+
* @signature b.crypto.encryptPacked(buffer, key, aad)
|
|
1312
|
+
* @since 0.1.0
|
|
1313
|
+
* @related b.crypto.decryptPacked, b.crypto.encrypt
|
|
1314
|
+
*
|
|
1315
|
+
* Symmetric (key-already-known) authenticated encryption. Returns a
|
|
1316
|
+
* self-describing Buffer: 1-byte format ID + 24-byte XChaCha20-
|
|
1317
|
+
* Poly1305 nonce + ciphertext+tag. Operators who already hold a
|
|
1318
|
+
* symmetric key (sealed-storage cell encryption, break-glass row
|
|
1319
|
+
* encryption) reach for this instead of the envelope variants. The
|
|
1320
|
+
* optional `aad` (additional authenticated data) is mixed into the
|
|
1321
|
+
* Poly1305 tag; encrypt-time and decrypt-time AAD must match exactly
|
|
1322
|
+
* or decryption fails. Wire it for context-binding (e.g. `(table,
|
|
1323
|
+
* rowId, column)` so a ciphertext from row A literally cannot decrypt
|
|
1324
|
+
* as row B even with the same key).
|
|
1325
|
+
*
|
|
1326
|
+
* @example
|
|
1327
|
+
* var key = b.crypto.generateBytes(32);
|
|
1328
|
+
* var data = Buffer.from("row-42 column-ssn", "utf8");
|
|
1329
|
+
* var aad = Buffer.from("patients|42|ssn", "utf8");
|
|
1330
|
+
* var packed = b.crypto.encryptPacked(data, key, aad);
|
|
1331
|
+
* var plain = b.crypto.decryptPacked(packed, key, aad);
|
|
1332
|
+
* plain.toString("utf8");
|
|
1333
|
+
* // → "row-42 column-ssn"
|
|
1334
|
+
*/
|
|
1335
|
+
function encryptPacked(buffer, key, aad) {
|
|
1336
|
+
var nonce = random(C.BYTES.bytes(24));
|
|
1337
|
+
var ct = xchacha20poly1305(key, nonce, aad ? Buffer.from(aad) : undefined).encrypt(buffer);
|
|
1338
|
+
return Buffer.concat([
|
|
1339
|
+
Buffer.from([C.FORMAT.XCHACHA20_POLY1305]),
|
|
1340
|
+
Buffer.from(nonce),
|
|
1341
|
+
Buffer.from(ct),
|
|
1342
|
+
]);
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
/**
|
|
1346
|
+
* @primitive b.crypto.decryptPacked
|
|
1347
|
+
* @signature b.crypto.decryptPacked(packed, key, aad)
|
|
1348
|
+
* @since 0.1.0
|
|
1349
|
+
* @related b.crypto.encryptPacked
|
|
1350
|
+
*
|
|
1351
|
+
* Inverse of `encryptPacked`. Reads the 1-byte format ID, extracts
|
|
1352
|
+
* the 24-byte XChaCha20-Poly1305 nonce, and decrypts the trailing
|
|
1353
|
+
* ciphertext under `key` + `aad`. Throws on unsupported format byte
|
|
1354
|
+
* or AAD / tag mismatch — operators wrap when a graceful per-cell
|
|
1355
|
+
* fallback is required.
|
|
1356
|
+
*
|
|
1357
|
+
* @example
|
|
1358
|
+
* var key = b.crypto.generateBytes(32);
|
|
1359
|
+
* var aad = Buffer.from("audit|2026-05-08", "utf8");
|
|
1360
|
+
* var pkt = b.crypto.encryptPacked(Buffer.from("hello", "utf8"), key, aad);
|
|
1361
|
+
* var open = b.crypto.decryptPacked(pkt, key, aad);
|
|
1362
|
+
* open.toString("utf8");
|
|
1363
|
+
* // → "hello"
|
|
1364
|
+
*/
|
|
1365
|
+
function decryptPacked(packed, key, aad) {
|
|
1366
|
+
if (packed[0] !== C.FORMAT.XCHACHA20_POLY1305) {
|
|
1367
|
+
throw new Error("Invalid packed format: unsupported version");
|
|
1368
|
+
}
|
|
1369
|
+
return Buffer.from(
|
|
1370
|
+
xchacha20poly1305(key, packed.subarray(1, 25), aad ? Buffer.from(aad) : undefined)
|
|
1371
|
+
.decrypt(packed.subarray(25))
|
|
1372
|
+
);
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// ---- ML-KEM-768 + X25519 hybrid (TLS-interop envelope) ----
|
|
1376
|
+
//
|
|
1377
|
+
// The IETF / Cloudflare / Chrome standardized hybrid for TLS 1.3
|
|
1378
|
+
// (codepoint 0x11EC). Smaller payload than ML-KEM-1024 + P-384
|
|
1379
|
+
// (~1.1 KB vs ~1.6 KB), wider interop with peers using the same
|
|
1380
|
+
// hybrid (Cloudflare Workers, Chrome, blamejs-on-the-other-side).
|
|
1381
|
+
//
|
|
1382
|
+
// Operators wire this when the recipient publishes ML-KEM-768 +
|
|
1383
|
+
// X25519 keys. Generation:
|
|
1384
|
+
//
|
|
1385
|
+
// var pair = b.crypto.generateMlkem768X25519KeyPair();
|
|
1386
|
+
// // → { mlkemPublicKey, mlkemPrivateKey,
|
|
1387
|
+
// // x25519PublicKey, x25519PrivateKey }
|
|
1388
|
+
//
|
|
1389
|
+
// var envelope = b.crypto.encryptMlkem768X25519(plaintext, {
|
|
1390
|
+
// mlkemPublicKey: recipient.mlkemPublicKey,
|
|
1391
|
+
// x25519PublicKey: recipient.x25519PublicKey,
|
|
1392
|
+
// });
|
|
1393
|
+
//
|
|
1394
|
+
// Decryption goes through the existing b.crypto.decrypt(envelope,
|
|
1395
|
+
// privateKeys) — the envelope-magic dispatch handles KEM_IDS.
|
|
1396
|
+
// ML_KEM_768_X25519. privateKeys MUST shape as { privateKey,
|
|
1397
|
+
// x25519PrivateKey } — privateKey is the ML-KEM-768 PEM, NOT the
|
|
1398
|
+
// default ML-KEM-1024.
|
|
1399
|
+
|
|
1400
|
+
/**
|
|
1401
|
+
* @primitive b.crypto.generateMlkem768X25519KeyPair
|
|
1402
|
+
* @signature b.crypto.generateMlkem768X25519KeyPair()
|
|
1403
|
+
* @since 0.7.28
|
|
1404
|
+
* @related b.crypto.encryptMlkem768X25519, b.crypto.decryptMlkem768X25519, b.crypto.generateEncryptionKeyPair
|
|
1405
|
+
*
|
|
1406
|
+
* Generates the IETF / Cloudflare / Chrome TLS 1.3 hybrid keypair
|
|
1407
|
+
* (codepoint 0x11EC): ML-KEM-768 (FIPS 203) + X25519 (RFC 7748).
|
|
1408
|
+
* Smaller payload than ML-KEM-1024 + P-384 (~1.1 KB vs ~1.6 KB) and
|
|
1409
|
+
* wider interop with peers using the same hybrid (Cloudflare
|
|
1410
|
+
* Workers, Chrome, browsers offering hybrid PQ key share). Returns
|
|
1411
|
+
* `{ mlkemPublicKey, mlkemPrivateKey, x25519PublicKey,
|
|
1412
|
+
* x25519PrivateKey }`.
|
|
1413
|
+
*
|
|
1414
|
+
* @example
|
|
1415
|
+
* var pair = b.crypto.generateMlkem768X25519KeyPair();
|
|
1416
|
+
* var sealed = b.crypto.encryptMlkem768X25519("interop payload", {
|
|
1417
|
+
* mlkemPublicKey: pair.mlkemPublicKey,
|
|
1418
|
+
* x25519PublicKey: pair.x25519PublicKey,
|
|
1419
|
+
* });
|
|
1420
|
+
* var plain = b.crypto.decryptMlkem768X25519(sealed, {
|
|
1421
|
+
* privateKey: pair.mlkemPrivateKey,
|
|
1422
|
+
* x25519PrivateKey: pair.x25519PrivateKey,
|
|
1423
|
+
* });
|
|
1424
|
+
* // → "interop payload"
|
|
1425
|
+
*/
|
|
1426
|
+
function generateMlkem768X25519KeyPair() {
|
|
1427
|
+
var mlkem = generateKeyPair("ml-kem-768");
|
|
1428
|
+
var x25519 = generateKeyPair("x25519");
|
|
1429
|
+
return {
|
|
1430
|
+
mlkemPublicKey: mlkem.publicKey,
|
|
1431
|
+
mlkemPrivateKey: mlkem.privateKey,
|
|
1432
|
+
x25519PublicKey: x25519.publicKey,
|
|
1433
|
+
x25519PrivateKey: x25519.privateKey,
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
/**
|
|
1438
|
+
* @primitive b.crypto.encryptMlkem768X25519
|
|
1439
|
+
* @signature b.crypto.encryptMlkem768X25519(plaintext, recipient)
|
|
1440
|
+
* @since 0.7.28
|
|
1441
|
+
* @related b.crypto.decryptMlkem768X25519, b.crypto.encrypt, b.crypto.generateMlkem768X25519KeyPair
|
|
1442
|
+
*
|
|
1443
|
+
* Seals `plaintext` under the IETF / Cloudflare / Chrome TLS 1.3
|
|
1444
|
+
* hybrid (ML-KEM-768 + X25519). Recipient shape is
|
|
1445
|
+
* `{ mlkemPublicKey, x25519PublicKey }` — both PEMs. Same envelope
|
|
1446
|
+
* wire format as the default hybrid; the KEM ID byte is
|
|
1447
|
+
* `KEM_IDS.ML_KEM_768_X25519` so `b.crypto.decrypt` dispatches
|
|
1448
|
+
* correctly on the receive side. Reach for this when the recipient
|
|
1449
|
+
* publishes ML-KEM-768 + X25519 keys (TLS-1.3 codepoint 0x11EC peers,
|
|
1450
|
+
* cross-stack interop with Cloudflare Workers or Chrome-side WebCrypto).
|
|
1451
|
+
*
|
|
1452
|
+
* @example
|
|
1453
|
+
* var pair = b.crypto.generateMlkem768X25519KeyPair();
|
|
1454
|
+
* var sealed = b.crypto.encryptMlkem768X25519("cross-stack message", {
|
|
1455
|
+
* mlkemPublicKey: pair.mlkemPublicKey,
|
|
1456
|
+
* x25519PublicKey: pair.x25519PublicKey,
|
|
1457
|
+
* });
|
|
1458
|
+
* typeof sealed;
|
|
1459
|
+
* // → "string" (base64 envelope, ~1.1 KB for short plaintexts)
|
|
1460
|
+
*/
|
|
1461
|
+
function encryptMlkem768X25519(plaintext, recipient) {
|
|
1462
|
+
if (!recipient || !recipient.mlkemPublicKey || !recipient.x25519PublicKey) {
|
|
1463
|
+
throw new Error("encryptMlkem768X25519 requires { mlkemPublicKey, x25519PublicKey }");
|
|
1464
|
+
}
|
|
1465
|
+
var mlkemPub = nodeCrypto.createPublicKey(recipient.mlkemPublicKey);
|
|
1466
|
+
var kem = nodeCrypto.encapsulate(mlkemPub);
|
|
1467
|
+
var ephX25519 = generateKeyPair("x25519", {
|
|
1468
|
+
publicKeyEncoding: { type: "spki", format: "der" },
|
|
1469
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
1470
|
+
});
|
|
1471
|
+
var x25519Ss = nodeCrypto.diffieHellman({
|
|
1472
|
+
privateKey: nodeCrypto.createPrivateKey(ephX25519.privateKey),
|
|
1473
|
+
publicKey: nodeCrypto.createPublicKey(recipient.x25519PublicKey),
|
|
1474
|
+
});
|
|
1475
|
+
var key = kdf(Buffer.concat([kem.sharedKey, x25519Ss,
|
|
1476
|
+
_suiteFixedInfo(C.KEM_IDS.ML_KEM_768_X25519, C.ACTIVE.CIPHER, C.ACTIVE.KDF)]),
|
|
1477
|
+
C.BYTES.bytes(32));
|
|
1478
|
+
var nonce = generateBytes(C.BYTES.bytes(24));
|
|
1479
|
+
var headerAad = Buffer.from([C.ENVELOPE_MAGIC, C.KEM_IDS.ML_KEM_768_X25519,
|
|
1480
|
+
C.ACTIVE.CIPHER, C.ACTIVE.KDF]);
|
|
1481
|
+
var ct = xchacha20poly1305(key, nonce, headerAad).encrypt(Buffer.from(plaintext, "utf8"));
|
|
1482
|
+
|
|
1483
|
+
var kemCtLen = Buffer.alloc(2); kemCtLen.writeUInt16BE(kem.ciphertext.length);
|
|
1484
|
+
var x25519EphDer = ephX25519.publicKey;
|
|
1485
|
+
var x25519EphLen = Buffer.alloc(2); x25519EphLen.writeUInt16BE(x25519EphDer.length);
|
|
1486
|
+
|
|
1487
|
+
return Buffer.concat([
|
|
1488
|
+
headerAad,
|
|
1489
|
+
kemCtLen, kem.ciphertext, x25519EphLen, x25519EphDer, nonce, Buffer.from(ct),
|
|
1490
|
+
]).toString("base64");
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
// Symmetric named-pair to encryptMlkem768X25519. Operators wiring the
|
|
1494
|
+
// IETF / Cloudflare / Chrome TLS-1.3 hybrid (codepoint 0x11EC) want
|
|
1495
|
+
// the encrypt + decrypt halves under symmetric, discoverable names.
|
|
1496
|
+
//
|
|
1497
|
+
// The generic b.crypto.decrypt already dispatches by KEM ID and
|
|
1498
|
+
// handles ML_KEM_768_X25519 envelopes correctly; this helper REJECTS
|
|
1499
|
+
// any other KEM ID at the head, so an operator who calls
|
|
1500
|
+
// decryptMlkem768X25519 with a ciphertext sealed under a different
|
|
1501
|
+
// algorithm gets a clear error rather than the generic "unsupported
|
|
1502
|
+
// KEM ID" path.
|
|
1503
|
+
//
|
|
1504
|
+
// recipient: { privateKey, x25519PrivateKey } — operator's keys
|
|
1505
|
+
// ciphertext: base64 envelope from encryptMlkem768X25519
|
|
1506
|
+
/**
|
|
1507
|
+
* @primitive b.crypto.decryptMlkem768X25519
|
|
1508
|
+
* @signature b.crypto.decryptMlkem768X25519(ciphertext, recipient)
|
|
1509
|
+
* @since 0.7.28
|
|
1510
|
+
* @related b.crypto.encryptMlkem768X25519, b.crypto.decrypt
|
|
1511
|
+
*
|
|
1512
|
+
* Symmetric named-pair to `encryptMlkem768X25519`. Rejects any
|
|
1513
|
+
* envelope whose KEM ID byte is not `ML_KEM_768_X25519` so an
|
|
1514
|
+
* operator who calls this with a ciphertext sealed under a different
|
|
1515
|
+
* algorithm gets a clear error rather than the generic dispatch path.
|
|
1516
|
+
* Recipient shape is `{ privateKey, x25519PrivateKey }` — `privateKey`
|
|
1517
|
+
* is the ML-KEM-768 PEM, NOT the framework default ML-KEM-1024.
|
|
1518
|
+
*
|
|
1519
|
+
* @example
|
|
1520
|
+
* var pair = b.crypto.generateMlkem768X25519KeyPair();
|
|
1521
|
+
* var sealed = b.crypto.encryptMlkem768X25519("interop", {
|
|
1522
|
+
* mlkemPublicKey: pair.mlkemPublicKey,
|
|
1523
|
+
* x25519PublicKey: pair.x25519PublicKey,
|
|
1524
|
+
* });
|
|
1525
|
+
* var plain = b.crypto.decryptMlkem768X25519(sealed, {
|
|
1526
|
+
* privateKey: pair.mlkemPrivateKey,
|
|
1527
|
+
* x25519PrivateKey: pair.x25519PrivateKey,
|
|
1528
|
+
* });
|
|
1529
|
+
* // → "interop"
|
|
1530
|
+
*/
|
|
1531
|
+
function decryptMlkem768X25519(ciphertext, recipient) {
|
|
1532
|
+
if (!recipient || typeof recipient !== "object" ||
|
|
1533
|
+
!recipient.privateKey || !recipient.x25519PrivateKey) {
|
|
1534
|
+
throw new Error("decryptMlkem768X25519 requires { privateKey, x25519PrivateKey } " +
|
|
1535
|
+
"(privateKey is the ML-KEM-768 PEM, x25519PrivateKey is the X25519 PEM)");
|
|
1536
|
+
}
|
|
1537
|
+
var packed = Buffer.from(ciphertext, "base64");
|
|
1538
|
+
if (packed[0] !== C.ENVELOPE_MAGIC) {
|
|
1539
|
+
throw new Error("decryptMlkem768X25519: invalid envelope (bad magic byte)");
|
|
1540
|
+
}
|
|
1541
|
+
if (packed[1] !== C.KEM_IDS.ML_KEM_768_X25519) {
|
|
1542
|
+
throw new Error("decryptMlkem768X25519: envelope KEM ID is " + packed[1] +
|
|
1543
|
+
", expected " + C.KEM_IDS.ML_KEM_768_X25519 +
|
|
1544
|
+
" (ML_KEM_768_X25519). Use b.crypto.decrypt for KEM-id dispatch.");
|
|
1545
|
+
}
|
|
1546
|
+
return decryptEnvelope(packed, recipient);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
// ---- Cert-peer envelope primitives ----
|
|
1550
|
+
//
|
|
1551
|
+
// The framework's default `encrypt` / `decrypt` source the recipient
|
|
1552
|
+
// from a published framework keypair (operator owns both halves). The
|
|
1553
|
+
// cert-peer variants source the recipient from a TLS peer cert (peer
|
|
1554
|
+
// owns the ECDH P-384 half) plus a peer-supplied ML-KEM-1024 pubkey.
|
|
1555
|
+
// Wire format is unchanged — the envelope dispatches on the same
|
|
1556
|
+
// version bytes and KEM ID. Only the input keys differ.
|
|
1557
|
+
//
|
|
1558
|
+
// Use cases beyond the b.middleware.apiEncrypt strategy:
|
|
1559
|
+
// - Sealed-storage records with peer recipients (operator A seals
|
|
1560
|
+
// to operator B's TLS cert + KEM pubkey).
|
|
1561
|
+
// - Cross-service messages between cert-identified peers without
|
|
1562
|
+
// a shared framework keypair.
|
|
1563
|
+
// - Audit log entries tagged with peer recipients.
|
|
1564
|
+
|
|
1565
|
+
function _extractEcdhP384FromCert(certDer) {
|
|
1566
|
+
// The cert's SubjectPublicKeyInfo carries the ECDH P-384 pubkey when
|
|
1567
|
+
// the cert is issued for that curve. node:crypto's X509Certificate
|
|
1568
|
+
// exposes `publicKey` as a KeyObject; we only export the SPKI as PEM
|
|
1569
|
+
// so the existing `encrypt` path consumes the same shape it accepts
|
|
1570
|
+
// for `ecPublicKey`.
|
|
1571
|
+
var cert = new nodeCrypto.X509Certificate(certDer);
|
|
1572
|
+
var keyObj = cert.publicKey;
|
|
1573
|
+
var details = keyObj.asymmetricKeyDetails || {};
|
|
1574
|
+
if (keyObj.asymmetricKeyType !== "ec" ||
|
|
1575
|
+
details.namedCurve !== "secp384r1") {
|
|
1576
|
+
var err = new Error(
|
|
1577
|
+
"cert public key is not ECDH P-384 (got asymmetricKeyType=" +
|
|
1578
|
+
keyObj.asymmetricKeyType + ", namedCurve=" + details.namedCurve + ")");
|
|
1579
|
+
err.code = "crypto/cert-key-not-ecdh-p384";
|
|
1580
|
+
throw err;
|
|
1581
|
+
}
|
|
1582
|
+
return keyObj.export({ type: "spki", format: "pem" });
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
// encryptEnvelopeAsCertPeer — produce a cert-bound envelope for the
|
|
1586
|
+
// peer identified by their TLS cert + ML-KEM-1024 pubkey.
|
|
1587
|
+
//
|
|
1588
|
+
// var envelope = b.crypto.encryptEnvelopeAsCertPeer(plaintext, {
|
|
1589
|
+
// peerCertDer: Buffer | Uint8Array, // peer's TLS cert (DER)
|
|
1590
|
+
// peerKemPubkey: string, // peer's ML-KEM-1024 pubkey PEM
|
|
1591
|
+
// });
|
|
1592
|
+
/**
|
|
1593
|
+
* @primitive b.crypto.encryptEnvelopeAsCertPeer
|
|
1594
|
+
* @signature b.crypto.encryptEnvelopeAsCertPeer(plaintext, opts)
|
|
1595
|
+
* @since 0.7.0
|
|
1596
|
+
* @related b.crypto.decryptEnvelopeAsCertPeer, b.crypto.encrypt
|
|
1597
|
+
*
|
|
1598
|
+
* Produces an envelope sealed to a peer identified by their TLS cert
|
|
1599
|
+
* (P-384 ECDH half) plus a peer-supplied ML-KEM-1024 pubkey. The wire
|
|
1600
|
+
* format is identical to `b.crypto.encrypt` — only the input keys
|
|
1601
|
+
* differ. Use for sealed-storage records with peer recipients,
|
|
1602
|
+
* cross-service messages between cert-identified peers without a
|
|
1603
|
+
* shared framework keypair, or audit-log entries tagged with peer
|
|
1604
|
+
* recipients. The cert must carry an ECDH P-384 SubjectPublicKeyInfo
|
|
1605
|
+
* — anything else throws `crypto/cert-key-not-ecdh-p384`.
|
|
1606
|
+
*
|
|
1607
|
+
* @opts
|
|
1608
|
+
* peerCertDer: Buffer, // peer's TLS cert as DER bytes (Buffer or Uint8Array)
|
|
1609
|
+
* peerKemPubkey: string, // peer's ML-KEM-1024 pubkey PEM (non-empty string)
|
|
1610
|
+
*
|
|
1611
|
+
* @example
|
|
1612
|
+
* var fs = require("fs");
|
|
1613
|
+
* var peerCertDer = fs.readFileSync("/etc/ssl/peer.cert.der");
|
|
1614
|
+
* var peerKemPubkey = fs.readFileSync("/etc/ssl/peer.mlkem.pem", "utf8");
|
|
1615
|
+
* var sealed = b.crypto.encryptEnvelopeAsCertPeer("cross-peer payload", {
|
|
1616
|
+
* peerCertDer: peerCertDer,
|
|
1617
|
+
* peerKemPubkey: peerKemPubkey,
|
|
1618
|
+
* });
|
|
1619
|
+
* typeof sealed;
|
|
1620
|
+
* // → "string" (base64 envelope)
|
|
1621
|
+
*/
|
|
1622
|
+
function encryptEnvelopeAsCertPeer(plaintext, opts) {
|
|
1623
|
+
if (!opts || typeof opts !== "object") {
|
|
1624
|
+
throw new Error("encryptEnvelopeAsCertPeer: opts object required");
|
|
1625
|
+
}
|
|
1626
|
+
if (!opts.peerCertDer) {
|
|
1627
|
+
var e1 = new Error("peerCertDer required (peer's TLS cert as DER bytes)");
|
|
1628
|
+
e1.code = "crypto/peer-cert-missing";
|
|
1629
|
+
throw e1;
|
|
1630
|
+
}
|
|
1631
|
+
if (typeof opts.peerKemPubkey !== "string") { // allow:inline-require-non-empty-string-validation — crypto module avoids validateOpts dependency to stay minimal
|
|
1632
|
+
var e2 = new Error("peerKemPubkey required (peer's ML-KEM-1024 pubkey PEM)");
|
|
1633
|
+
e2.code = "crypto/peer-kem-pubkey-missing";
|
|
1634
|
+
throw e2;
|
|
1635
|
+
}
|
|
1636
|
+
if (opts.peerKemPubkey.length === 0) {
|
|
1637
|
+
var e2b = new Error("peerKemPubkey is empty");
|
|
1638
|
+
e2b.code = "crypto/peer-kem-pubkey-missing";
|
|
1639
|
+
throw e2b;
|
|
1640
|
+
}
|
|
1641
|
+
var ecPubPem = _extractEcdhP384FromCert(opts.peerCertDer);
|
|
1642
|
+
return encrypt(plaintext, {
|
|
1643
|
+
publicKey: opts.peerKemPubkey,
|
|
1644
|
+
ecPublicKey: ecPubPem,
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
// decryptEnvelopeAsCertPeer — decrypt an envelope sealed to this
|
|
1649
|
+
// operator's TLS cert ECDH-pubkey + ML-KEM-1024 pubkey.
|
|
1650
|
+
//
|
|
1651
|
+
// var plaintext = b.crypto.decryptEnvelopeAsCertPeer(envelope, {
|
|
1652
|
+
// certPrivateKey: KeyObject | string, // this operator's cert P-384 priv
|
|
1653
|
+
// kemSecret: string, // this operator's ML-KEM-1024 priv PEM
|
|
1654
|
+
// });
|
|
1655
|
+
/**
|
|
1656
|
+
* @primitive b.crypto.decryptEnvelopeAsCertPeer
|
|
1657
|
+
* @signature b.crypto.decryptEnvelopeAsCertPeer(envelope, opts)
|
|
1658
|
+
* @since 0.7.0
|
|
1659
|
+
* @related b.crypto.encryptEnvelopeAsCertPeer, b.crypto.decrypt
|
|
1660
|
+
*
|
|
1661
|
+
* Decrypts an envelope sealed to this operator's TLS cert ECDH-pubkey
|
|
1662
|
+
* + ML-KEM-1024 pubkey. `certPrivateKey` accepts either a node:crypto
|
|
1663
|
+
* `KeyObject` (ECDH P-384, namedCurve secp384r1) or its PEM-encoded
|
|
1664
|
+
* pkcs8 string; `kemSecret` is always the ML-KEM-1024 PEM. A non-
|
|
1665
|
+
* P-384 cert key throws `crypto/cert-key-not-ecdh-p384`. Mirror of
|
|
1666
|
+
* `encryptEnvelopeAsCertPeer` for the receive side.
|
|
1667
|
+
*
|
|
1668
|
+
* @opts
|
|
1669
|
+
* certPrivateKey: object, // KeyObject or PEM string — ECDH P-384 priv (secp384r1)
|
|
1670
|
+
* kemSecret: string, // operator's ML-KEM-1024 priv PEM (non-empty)
|
|
1671
|
+
*
|
|
1672
|
+
* @example
|
|
1673
|
+
* var fs = require("fs");
|
|
1674
|
+
* var ourCertPriv = fs.readFileSync("/etc/ssl/our.cert.key.pem", "utf8");
|
|
1675
|
+
* var ourKemSecret = fs.readFileSync("/etc/ssl/our.mlkem.priv.pem", "utf8");
|
|
1676
|
+
* var sealed = "AaECA..."; // base64 envelope received from peer
|
|
1677
|
+
* var plain = b.crypto.decryptEnvelopeAsCertPeer(sealed, {
|
|
1678
|
+
* certPrivateKey: ourCertPriv,
|
|
1679
|
+
* kemSecret: ourKemSecret,
|
|
1680
|
+
* });
|
|
1681
|
+
* typeof plain;
|
|
1682
|
+
* // → "string"
|
|
1683
|
+
*/
|
|
1684
|
+
function decryptEnvelopeAsCertPeer(envelope, opts) {
|
|
1685
|
+
if (!opts || typeof opts !== "object") {
|
|
1686
|
+
throw new Error("decryptEnvelopeAsCertPeer: opts object required");
|
|
1687
|
+
}
|
|
1688
|
+
if (!opts.certPrivateKey) {
|
|
1689
|
+
var e1 = new Error("certPrivateKey required");
|
|
1690
|
+
e1.code = "crypto/cert-private-key-missing";
|
|
1691
|
+
throw e1;
|
|
1692
|
+
}
|
|
1693
|
+
if (typeof opts.kemSecret !== "string") { // allow:inline-require-non-empty-string-validation — crypto module avoids validateOpts dependency to stay minimal
|
|
1694
|
+
var e2 = new Error("kemSecret required (operator's ML-KEM-1024 priv PEM)");
|
|
1695
|
+
e2.code = "crypto/kem-secret-missing";
|
|
1696
|
+
throw e2;
|
|
1697
|
+
}
|
|
1698
|
+
if (opts.kemSecret.length === 0) {
|
|
1699
|
+
var e2b = new Error("kemSecret is empty");
|
|
1700
|
+
e2b.code = "crypto/kem-secret-missing";
|
|
1701
|
+
throw e2b;
|
|
1702
|
+
}
|
|
1703
|
+
// Normalize certPrivateKey to PEM string (existing decrypt accepts
|
|
1704
|
+
// PEM string).
|
|
1705
|
+
var ecPrivPem;
|
|
1706
|
+
if (typeof opts.certPrivateKey === "string") {
|
|
1707
|
+
ecPrivPem = opts.certPrivateKey;
|
|
1708
|
+
} else if (typeof opts.certPrivateKey.export === "function") {
|
|
1709
|
+
var details = opts.certPrivateKey.asymmetricKeyDetails || {};
|
|
1710
|
+
if (opts.certPrivateKey.asymmetricKeyType !== "ec" ||
|
|
1711
|
+
details.namedCurve !== "secp384r1") {
|
|
1712
|
+
var e3 = new Error(
|
|
1713
|
+
"certPrivateKey is not ECDH P-384 (got asymmetricKeyType=" +
|
|
1714
|
+
opts.certPrivateKey.asymmetricKeyType + ", namedCurve=" +
|
|
1715
|
+
details.namedCurve + ")");
|
|
1716
|
+
e3.code = "crypto/cert-key-not-ecdh-p384";
|
|
1717
|
+
throw e3;
|
|
1718
|
+
}
|
|
1719
|
+
ecPrivPem = opts.certPrivateKey.export({ type: "pkcs8", format: "pem" });
|
|
1720
|
+
} else {
|
|
1721
|
+
var e4 = new Error("certPrivateKey must be a KeyObject or PEM string");
|
|
1722
|
+
e4.code = "crypto/cert-private-key-bad-shape";
|
|
1723
|
+
throw e4;
|
|
1724
|
+
}
|
|
1725
|
+
return decrypt(envelope, {
|
|
1726
|
+
privateKey: opts.kemSecret,
|
|
1727
|
+
ecPrivateKey: ecPrivPem,
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
// Operator-audit accessor — exposes every supported KEM hybrid for
|
|
1732
|
+
// compliance audit visibility ("which envelopes does this deploy
|
|
1733
|
+
// accept on decrypt?").
|
|
1734
|
+
// ---- Certificate fingerprint helpers ----
|
|
1735
|
+
//
|
|
1736
|
+
// Operators pinning peer-cert fingerprints (mtls bootstrap, webhook
|
|
1737
|
+
// verification, certificate transparency cross-checks) want a stable
|
|
1738
|
+
// SHA3-512 hash of the DER bytes plus a colon-separated hex form that
|
|
1739
|
+
// matches what most operator tooling renders for X.509 fingerprints.
|
|
1740
|
+
// hashCertFingerprint accepts either a Buffer (DER) or a PEM string;
|
|
1741
|
+
// if PEM, the BEGIN/END envelope is stripped and the base64 body is
|
|
1742
|
+
// decoded before hashing. The hash is the framework's standard SHA3-
|
|
1743
|
+
// 512 (not SHA-256 — operators using OpenSSL's `-sha256` defaults can
|
|
1744
|
+
// keep their own SHA-256 hashes, this primitive is the framework-
|
|
1745
|
+
// canonical form). Returns { hex, colon } so callers can compare
|
|
1746
|
+
// against either rendering.
|
|
1747
|
+
function _pemToDer(pemOrDer) {
|
|
1748
|
+
if (Buffer.isBuffer(pemOrDer)) return pemOrDer;
|
|
1749
|
+
if (typeof pemOrDer !== "string") {
|
|
1750
|
+
throw new TypeError("crypto.hashCertFingerprint: input must be a Buffer (DER) or a PEM-encoded string");
|
|
1751
|
+
}
|
|
1752
|
+
// Bound the regex input. The /-----BEGIN .+? -----END/ pattern is
|
|
1753
|
+
// lazy-quantified, which CodeQL flags as polynomial-ReDoS
|
|
1754
|
+
// (js/polynomial-redos) when fed multi-MB attacker-controlled input
|
|
1755
|
+
// — every backtrack step is O(n) and the pattern is on a hot path
|
|
1756
|
+
// for mTLS bootstrap / webhook verification / peer-cert pinning.
|
|
1757
|
+
// 64 KiB caps the largest plausible PEM (a P-384 cert + chain) at
|
|
1758
|
+
// ~3× margin while refusing pathological inputs outright.
|
|
1759
|
+
if (pemOrDer.length > C.BYTES.kib(64)) {
|
|
1760
|
+
throw new TypeError(
|
|
1761
|
+
"crypto.hashCertFingerprint: PEM input exceeds 64 KiB (" +
|
|
1762
|
+
pemOrDer.length + " bytes); refuse oversized input to avoid " +
|
|
1763
|
+
"polynomial-ReDoS on the BEGIN/END marker regex"
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
var match = pemOrDer.match(/-----BEGIN [A-Z0-9 ]+-----([\s\S]+?)-----END [A-Z0-9 ]+-----/);
|
|
1767
|
+
if (!match) {
|
|
1768
|
+
throw new TypeError("crypto.hashCertFingerprint: PEM input lacks BEGIN/END markers");
|
|
1769
|
+
}
|
|
1770
|
+
return Buffer.from(match[1].replace(/\s+/g, ""), "base64");
|
|
1771
|
+
}
|
|
1772
|
+
/**
|
|
1773
|
+
* @primitive b.crypto.hashCertFingerprint
|
|
1774
|
+
* @signature b.crypto.hashCertFingerprint(pemOrDer)
|
|
1775
|
+
* @since 0.7.0
|
|
1776
|
+
* @related b.crypto.isCertRevoked, b.crypto.sha3Hash
|
|
1777
|
+
*
|
|
1778
|
+
* Computes a stable SHA3-512 fingerprint of an X.509 certificate.
|
|
1779
|
+
* Accepts either DER bytes (Buffer) or a PEM string (BEGIN/END
|
|
1780
|
+
* envelope is stripped, base64 body decoded). Returns
|
|
1781
|
+
* `{ hex, colon }` so callers can compare against either rendering
|
|
1782
|
+
* style — lowercase hex (concise, log-friendly) or uppercase
|
|
1783
|
+
* colon-separated hex (matches `openssl x509 -fingerprint` output
|
|
1784
|
+
* shape). Use for peer-cert pinning, mTLS bootstrap allowlists,
|
|
1785
|
+
* webhook verification, certificate-transparency cross-checks.
|
|
1786
|
+
*
|
|
1787
|
+
* @example
|
|
1788
|
+
* var fs = require("fs");
|
|
1789
|
+
* var pem = fs.readFileSync("/etc/ssl/peer.cert.pem", "utf8");
|
|
1790
|
+
* var fp = b.crypto.hashCertFingerprint(pem);
|
|
1791
|
+
* fp.hex.length;
|
|
1792
|
+
* // → 128 (SHA3-512 = 64 bytes hex-encoded)
|
|
1793
|
+
* fp.colon.split(":").length;
|
|
1794
|
+
* // → 64 (one byte per group)
|
|
1795
|
+
*/
|
|
1796
|
+
function hashCertFingerprint(pemOrDer) {
|
|
1797
|
+
var der = _pemToDer(pemOrDer);
|
|
1798
|
+
var digest = hash(der, "sha3-512");
|
|
1799
|
+
var hex = digest.toString("hex");
|
|
1800
|
+
// Colon-separated, uppercase — matches openssl x509 -fingerprint
|
|
1801
|
+
// output style (which is SHA-1 by default, but the rendering shape
|
|
1802
|
+
// operators expect is the same).
|
|
1803
|
+
var colon = hex.toUpperCase().match(/.{2}/g).join(":");
|
|
1804
|
+
return { hex: hex, colon: colon };
|
|
1805
|
+
}
|
|
1806
|
+
// Compares a peer's PEM/DER cert against an allowlist of pinned
|
|
1807
|
+
// fingerprints. Allowlist entries may be the colon form, the lower-
|
|
1808
|
+
// case hex form, or both — every comparison runs through
|
|
1809
|
+
// timingSafeEqual to avoid leaking which entry matched.
|
|
1810
|
+
/**
|
|
1811
|
+
* @primitive b.crypto.isCertRevoked
|
|
1812
|
+
* @signature b.crypto.isCertRevoked(pemOrDer, denyList)
|
|
1813
|
+
* @since 0.7.0
|
|
1814
|
+
* @related b.crypto.hashCertFingerprint, b.crypto.timingSafeEqual
|
|
1815
|
+
*
|
|
1816
|
+
* Returns `true` when the cert's SHA3-512 fingerprint matches any
|
|
1817
|
+
* entry in `denyList`. `denyList` entries may be the colon-separated
|
|
1818
|
+
* uppercase hex form, the lowercase hex form, or both — every
|
|
1819
|
+
* comparison runs through `crypto.timingSafeEqual` so the answer
|
|
1820
|
+
* doesn't leak which entry matched. Use for cert-transparency-style
|
|
1821
|
+
* deny lists, revoked-peer sweeps, or compromised-CA blocking.
|
|
1822
|
+
*
|
|
1823
|
+
* @example
|
|
1824
|
+
* var fs = require("fs");
|
|
1825
|
+
* var pem = fs.readFileSync("/etc/ssl/peer.cert.pem", "utf8");
|
|
1826
|
+
* var deny = ["DEADBEEF:CAFEBABE:1234:5678:..."];
|
|
1827
|
+
* var revoked = b.crypto.isCertRevoked(pem, deny);
|
|
1828
|
+
* // → false (when the fingerprint is not in the deny list)
|
|
1829
|
+
*/
|
|
1830
|
+
function isCertRevoked(pemOrDer, denyList) {
|
|
1831
|
+
if (!Array.isArray(denyList)) {
|
|
1832
|
+
throw new TypeError("crypto.isCertRevoked: denyList must be an array of fingerprint strings");
|
|
1833
|
+
}
|
|
1834
|
+
var fp = hashCertFingerprint(pemOrDer);
|
|
1835
|
+
var fpHex = Buffer.from(fp.hex, "hex");
|
|
1836
|
+
var fpColon = Buffer.from(fp.colon);
|
|
1837
|
+
for (var i = 0; i < denyList.length; i++) {
|
|
1838
|
+
var entry = denyList[i];
|
|
1839
|
+
if (typeof entry !== "string" || entry.length === 0) continue;
|
|
1840
|
+
var normalized = entry.indexOf(":") !== -1 ? entry.toUpperCase() : entry.toLowerCase();
|
|
1841
|
+
var normalizedBuf = entry.indexOf(":") !== -1 ? Buffer.from(normalized) : Buffer.from(normalized, "hex");
|
|
1842
|
+
var compareBuf = entry.indexOf(":") !== -1 ? fpColon : fpHex;
|
|
1843
|
+
if (normalizedBuf.length === compareBuf.length &&
|
|
1844
|
+
nodeCrypto.timingSafeEqual(normalizedBuf, compareBuf)) {
|
|
1845
|
+
return true;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
return false;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
var SUPPORTED_KEM_ALGORITHMS = Object.freeze([
|
|
1852
|
+
{ id: "ml-kem-1024", envelopeId: C.KEM_IDS.ML_KEM_1024, description: "ML-KEM-1024 KEM-only (legacy single-component)" },
|
|
1853
|
+
{ id: "ml-kem-1024-p384", envelopeId: C.KEM_IDS.ML_KEM_1024_P384, description: "ML-KEM-1024 + ECDH P-384 hybrid (framework default)" },
|
|
1854
|
+
{ id: "ml-kem-768-x25519", envelopeId: C.KEM_IDS.ML_KEM_768_X25519, description: "ML-KEM-768 + X25519 hybrid (IETF / Cloudflare / Chrome TLS 1.3 codepoint 0x11EC)" },
|
|
1855
|
+
]);
|
|
1856
|
+
|
|
1857
|
+
// Note: legacy 0xE1 envelope minting (used only by test round-trip
|
|
1858
|
+
// coverage) lives at `lib/_test/crypto-fixtures.js` —
|
|
1859
|
+
// `mintLegacyEnvelope0xE1`. The function is NOT auto-exported on
|
|
1860
|
+
// `b.crypto.*` because (a) operator code has no production use for
|
|
1861
|
+
// it (the framework's only contract is READING pre-bump 0xE1 data
|
|
1862
|
+
// via `decrypt(..., { allowLegacy: true })`), and (b) exposing a
|
|
1863
|
+
// mint helper widens the attack surface of the `allowLegacy: true`
|
|
1864
|
+
// decrypt path. Tests require it directly:
|
|
1865
|
+
//
|
|
1866
|
+
// var fixtures = require("blamejs/lib/_test/crypto-fixtures");
|
|
1867
|
+
// var blob = fixtures.mintLegacyEnvelope0xE1(plaintext, recipient);
|
|
1868
|
+
|
|
1869
|
+
module.exports = {
|
|
1870
|
+
sri: sri,
|
|
1871
|
+
// Hashing
|
|
1872
|
+
sha3Hash: sha3Hash,
|
|
1873
|
+
hmacSha3: hmacSha3,
|
|
1874
|
+
hashFile: hashFile,
|
|
1875
|
+
hashFilesParallel: hashFilesParallel,
|
|
1876
|
+
hashStream: hashStream,
|
|
1877
|
+
namespaceHash: namespaceHash,
|
|
1878
|
+
kdf: kdf,
|
|
1879
|
+
// Comparison
|
|
1880
|
+
timingSafeEqual: timingSafeEqual,
|
|
1881
|
+
// Cert fingerprint helpers
|
|
1882
|
+
hashCertFingerprint: hashCertFingerprint,
|
|
1883
|
+
isCertRevoked: isCertRevoked,
|
|
1884
|
+
// Random
|
|
1885
|
+
generateBytes: generateBytes,
|
|
1886
|
+
generateToken: generateToken,
|
|
1887
|
+
randomInt: randomInt,
|
|
1888
|
+
toBase64Url: toBase64Url,
|
|
1889
|
+
fromBase64Url: fromBase64Url,
|
|
1890
|
+
// Keys
|
|
1891
|
+
generateEncryptionKeyPair: generateEncryptionKeyPair,
|
|
1892
|
+
generateSigningKeyPair: generateSigningKeyPair,
|
|
1893
|
+
generateMlkem768X25519KeyPair: generateMlkem768X25519KeyPair,
|
|
1894
|
+
// Signatures
|
|
1895
|
+
sign: sign,
|
|
1896
|
+
verify: verify,
|
|
1897
|
+
// Envelope encrypt/decrypt
|
|
1898
|
+
encrypt: encrypt,
|
|
1899
|
+
decrypt: decrypt,
|
|
1900
|
+
encryptMlkem768X25519: encryptMlkem768X25519,
|
|
1901
|
+
decryptMlkem768X25519: decryptMlkem768X25519,
|
|
1902
|
+
encryptEnvelopeAsCertPeer: encryptEnvelopeAsCertPeer,
|
|
1903
|
+
decryptEnvelopeAsCertPeer: decryptEnvelopeAsCertPeer,
|
|
1904
|
+
SUPPORTED_KEM_ALGORITHMS: SUPPORTED_KEM_ALGORITHMS,
|
|
1905
|
+
// Symmetric buffer encrypt/decrypt
|
|
1906
|
+
encryptPacked: encryptPacked,
|
|
1907
|
+
decryptPacked: decryptPacked,
|
|
1908
|
+
};
|