@blamejs/blamejs-shop 0.4.68 → 0.4.70
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 +4 -0
- package/lib/admin.js +8 -6
- package/lib/asset-manifest.json +1 -1
- package/lib/giftcards.js +29 -5
- package/lib/security-middleware.js +65 -23
- package/lib/storefront.js +10 -7
- package/lib/vendor/MANIFEST.json +319 -267
- package/lib/vendor/blamejs/CHANGELOG.md +2 -0
- package/lib/vendor/blamejs/api-snapshot.json +58 -5
- package/lib/vendor/blamejs/examples/wiki/README.md +1 -1
- package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +9 -8
- package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +10 -9
- package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +4 -3
- package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +33 -17
- package/lib/vendor/blamejs/examples/wiki/routes/admin.js +7 -10
- package/lib/vendor/blamejs/examples/wiki/server.js +5 -4
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +5 -0
- package/lib/vendor/blamejs/lib/a2a-tasks.js +38 -6
- package/lib/vendor/blamejs/lib/agent-event-bus.js +13 -0
- package/lib/vendor/blamejs/lib/agent-idempotency.js +5 -1
- package/lib/vendor/blamejs/lib/agent-snapshot.js +32 -2
- package/lib/vendor/blamejs/lib/ai-aedt-bias-audit.js +2 -1
- package/lib/vendor/blamejs/lib/ai-content-detect.js +1 -3
- package/lib/vendor/blamejs/lib/ai-frontier-protocol.js +1 -1
- package/lib/vendor/blamejs/lib/ai-model-manifest.js +1 -1
- package/lib/vendor/blamejs/lib/ai-output.js +16 -7
- package/lib/vendor/blamejs/lib/api-snapshot.js +4 -1
- package/lib/vendor/blamejs/lib/app-shutdown.js +7 -1
- package/lib/vendor/blamejs/lib/archive-gz.js +9 -0
- package/lib/vendor/blamejs/lib/archive-read.js +9 -7
- package/lib/vendor/blamejs/lib/archive-tar-read.js +51 -8
- package/lib/vendor/blamejs/lib/archive.js +4 -2
- package/lib/vendor/blamejs/lib/asn1-der.js +70 -22
- package/lib/vendor/blamejs/lib/atomic-file.js +204 -2
- package/lib/vendor/blamejs/lib/audit-chain.js +54 -5
- package/lib/vendor/blamejs/lib/audit-daily-review.js +12 -2
- package/lib/vendor/blamejs/lib/audit-sign.js +2 -1
- package/lib/vendor/blamejs/lib/audit-tools.js +108 -23
- package/lib/vendor/blamejs/lib/audit.js +7 -2
- package/lib/vendor/blamejs/lib/auth/access-lock.js +2 -2
- package/lib/vendor/blamejs/lib/auth/bot-challenge.js +1 -1
- package/lib/vendor/blamejs/lib/auth/ciba.js +43 -4
- package/lib/vendor/blamejs/lib/auth/dpop.js +6 -1
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +5 -1
- package/lib/vendor/blamejs/lib/auth/jwt.js +2 -2
- package/lib/vendor/blamejs/lib/auth/lockout.js +18 -2
- package/lib/vendor/blamejs/lib/auth/passkey.js +1 -1
- package/lib/vendor/blamejs/lib/auth/password.js +1 -1
- package/lib/vendor/blamejs/lib/auth/saml.js +33 -13
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +24 -4
- package/lib/vendor/blamejs/lib/auth/status-list.js +14 -2
- package/lib/vendor/blamejs/lib/auth/step-up.js +9 -1
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +21 -2
- package/lib/vendor/blamejs/lib/backup/bundle.js +7 -2
- package/lib/vendor/blamejs/lib/backup/crypto.js +23 -8
- package/lib/vendor/blamejs/lib/backup/index.js +41 -20
- package/lib/vendor/blamejs/lib/backup/manifest.js +7 -1
- package/lib/vendor/blamejs/lib/break-glass.js +41 -22
- package/lib/vendor/blamejs/lib/cbor.js +34 -11
- package/lib/vendor/blamejs/lib/cdn-cache-control.js +7 -3
- package/lib/vendor/blamejs/lib/cert.js +5 -3
- package/lib/vendor/blamejs/lib/cli.js +5 -1
- package/lib/vendor/blamejs/lib/cloud-events.js +3 -2
- package/lib/vendor/blamejs/lib/cluster-storage.js +7 -3
- package/lib/vendor/blamejs/lib/codepoint-class.js +17 -0
- package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -1
- package/lib/vendor/blamejs/lib/compliance-sanctions.js +9 -7
- package/lib/vendor/blamejs/lib/compliance.js +1 -1
- package/lib/vendor/blamejs/lib/config-drift.js +22 -8
- package/lib/vendor/blamejs/lib/content-credentials.js +11 -8
- package/lib/vendor/blamejs/lib/content-digest.js +11 -4
- package/lib/vendor/blamejs/lib/cookies.js +10 -2
- package/lib/vendor/blamejs/lib/cose.js +20 -0
- package/lib/vendor/blamejs/lib/crdt.js +2 -1
- package/lib/vendor/blamejs/lib/crypto-field.js +29 -23
- package/lib/vendor/blamejs/lib/crypto.js +18 -4
- package/lib/vendor/blamejs/lib/csp.js +4 -0
- package/lib/vendor/blamejs/lib/daemon.js +4 -1
- package/lib/vendor/blamejs/lib/data-act.js +27 -4
- package/lib/vendor/blamejs/lib/db-file-lifecycle.js +14 -6
- package/lib/vendor/blamejs/lib/db-query.js +69 -9
- package/lib/vendor/blamejs/lib/db.js +32 -15
- package/lib/vendor/blamejs/lib/dora.js +43 -13
- package/lib/vendor/blamejs/lib/dr-runbook.js +1 -1
- package/lib/vendor/blamejs/lib/dsa.js +2 -1
- package/lib/vendor/blamejs/lib/dsr.js +22 -8
- package/lib/vendor/blamejs/lib/early-hints.js +19 -0
- package/lib/vendor/blamejs/lib/eat.js +5 -1
- package/lib/vendor/blamejs/lib/external-db.js +60 -4
- package/lib/vendor/blamejs/lib/fda-21cfr11.js +30 -5
- package/lib/vendor/blamejs/lib/flag-providers.js +6 -2
- package/lib/vendor/blamejs/lib/forms.js +1 -1
- package/lib/vendor/blamejs/lib/gate-contract.js +46 -5
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +18 -9
- package/lib/vendor/blamejs/lib/graphql-federation.js +17 -4
- package/lib/vendor/blamejs/lib/guard-all.js +2 -2
- package/lib/vendor/blamejs/lib/guard-dsn.js +1 -1
- package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
- package/lib/vendor/blamejs/lib/guard-html.js +9 -11
- package/lib/vendor/blamejs/lib/guard-imap-command.js +1 -1
- package/lib/vendor/blamejs/lib/guard-jmap.js +1 -1
- package/lib/vendor/blamejs/lib/guard-json.js +14 -6
- package/lib/vendor/blamejs/lib/guard-mail-move.js +1 -1
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +1 -1
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +1 -1
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +1 -1
- package/lib/vendor/blamejs/lib/guard-svg.js +8 -9
- package/lib/vendor/blamejs/lib/html-balance.js +7 -3
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +33 -12
- package/lib/vendor/blamejs/lib/http-client.js +225 -53
- package/lib/vendor/blamejs/lib/iab-tcf.js +3 -2
- package/lib/vendor/blamejs/lib/importmap-integrity.js +41 -1
- package/lib/vendor/blamejs/lib/incident-report.js +9 -6
- package/lib/vendor/blamejs/lib/json-patch.js +1 -1
- package/lib/vendor/blamejs/lib/json-path.js +24 -3
- package/lib/vendor/blamejs/lib/jtd.js +2 -2
- package/lib/vendor/blamejs/lib/legal-hold.js +24 -8
- package/lib/vendor/blamejs/lib/log.js +2 -2
- package/lib/vendor/blamejs/lib/mail-agent.js +2 -2
- package/lib/vendor/blamejs/lib/mail-arf.js +1 -1
- package/lib/vendor/blamejs/lib/mail-auth.js +3 -3
- package/lib/vendor/blamejs/lib/mail-bimi.js +16 -16
- package/lib/vendor/blamejs/lib/mail-bounce.js +3 -3
- package/lib/vendor/blamejs/lib/mail-crypto-smime.js +71 -6
- package/lib/vendor/blamejs/lib/mail-deploy.js +9 -5
- package/lib/vendor/blamejs/lib/mail-greylist.js +2 -4
- package/lib/vendor/blamejs/lib/mail-helo.js +2 -4
- package/lib/vendor/blamejs/lib/mail-journal.js +11 -8
- package/lib/vendor/blamejs/lib/mail-mdn.js +8 -4
- package/lib/vendor/blamejs/lib/mail-rbl.js +2 -4
- package/lib/vendor/blamejs/lib/mail-scan.js +3 -5
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +4 -1
- package/lib/vendor/blamejs/lib/mail-server-registry.js +1 -1
- package/lib/vendor/blamejs/lib/mail-server-tls.js +9 -2
- package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -4
- package/lib/vendor/blamejs/lib/mail-store-fts.js +1 -1
- package/lib/vendor/blamejs/lib/mail.js +22 -2
- package/lib/vendor/blamejs/lib/markup-tokenizer.js +24 -0
- package/lib/vendor/blamejs/lib/mcp.js +6 -4
- package/lib/vendor/blamejs/lib/mdoc.js +26 -3
- package/lib/vendor/blamejs/lib/metrics.js +14 -3
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +2 -2
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +10 -4
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +26 -18
- package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +5 -1
- package/lib/vendor/blamejs/lib/middleware/compression.js +9 -0
- package/lib/vendor/blamejs/lib/middleware/cors.js +32 -23
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +60 -21
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -4
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +28 -4
- package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +61 -30
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +25 -16
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +24 -6
- package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +6 -3
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +2 -2
- package/lib/vendor/blamejs/lib/money.js +1 -1
- package/lib/vendor/blamejs/lib/mtls-ca.js +10 -6
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +1 -1
- package/lib/vendor/blamejs/lib/network-dns.js +9 -2
- package/lib/vendor/blamejs/lib/network-dnssec.js +2 -1
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +23 -5
- package/lib/vendor/blamejs/lib/network-tls.js +27 -5
- package/lib/vendor/blamejs/lib/network-tsig.js +2 -2
- package/lib/vendor/blamejs/lib/nis2-report.js +1 -1
- package/lib/vendor/blamejs/lib/nist-crosswalk.js +1 -1
- package/lib/vendor/blamejs/lib/ntp-check.js +28 -0
- package/lib/vendor/blamejs/lib/numeric-bounds.js +9 -0
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +1 -2
- package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +4 -2
- package/lib/vendor/blamejs/lib/object-store/gcs.js +6 -4
- package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -2
- package/lib/vendor/blamejs/lib/object-store/http-request.js +30 -1
- package/lib/vendor/blamejs/lib/object-store/local.js +37 -17
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +1 -2
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +20 -4
- package/lib/vendor/blamejs/lib/outbox.js +11 -4
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +1 -1
- package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +21 -3
- package/lib/vendor/blamejs/lib/queue-local.js +10 -3
- package/lib/vendor/blamejs/lib/redact.js +7 -3
- package/lib/vendor/blamejs/lib/request-helpers.js +201 -23
- package/lib/vendor/blamejs/lib/resource-access-lock.js +3 -3
- package/lib/vendor/blamejs/lib/restore-bundle.js +46 -18
- package/lib/vendor/blamejs/lib/restore-rollback.js +10 -4
- package/lib/vendor/blamejs/lib/restore.js +19 -0
- package/lib/vendor/blamejs/lib/retention.js +20 -4
- package/lib/vendor/blamejs/lib/router.js +17 -4
- package/lib/vendor/blamejs/lib/safe-ical.js +2 -2
- package/lib/vendor/blamejs/lib/safe-icap.js +1 -1
- package/lib/vendor/blamejs/lib/safe-json.js +44 -0
- package/lib/vendor/blamejs/lib/safe-sieve.js +1 -1
- package/lib/vendor/blamejs/lib/safe-vcard.js +1 -1
- package/lib/vendor/blamejs/lib/sandbox-worker.js +6 -0
- package/lib/vendor/blamejs/lib/sandbox.js +1 -1
- package/lib/vendor/blamejs/lib/scheduler.js +17 -1
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +16 -0
- package/lib/vendor/blamejs/lib/session.js +27 -3
- package/lib/vendor/blamejs/lib/sql.js +3 -3
- package/lib/vendor/blamejs/lib/static.js +65 -13
- package/lib/vendor/blamejs/lib/template.js +7 -5
- package/lib/vendor/blamejs/lib/tenant-quota.js +52 -19
- package/lib/vendor/blamejs/lib/tsa.js +5 -2
- package/lib/vendor/blamejs/lib/vault/index.js +5 -0
- package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +22 -26
- package/lib/vendor/blamejs/lib/vault/passphrase-source.js +8 -3
- package/lib/vendor/blamejs/lib/vault/rotate.js +13 -18
- package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +4 -1
- package/lib/vendor/blamejs/lib/vc.js +1 -1
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +10 -10
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +23 -10
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5498 -5494
- package/lib/vendor/blamejs/lib/webhook.js +16 -1
- package/lib/vendor/blamejs/lib/websocket.js +1 -1
- package/lib/vendor/blamejs/lib/worm.js +1 -1
- package/lib/vendor/blamejs/lib/ws-client.js +57 -46
- package/lib/vendor/blamejs/lib/x509-chain.js +44 -0
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.15.14.json +122 -0
- package/lib/vendor/blamejs/scripts/check-vendor-currency.js +119 -4
- package/lib/vendor/blamejs/test/00-primitives.js +5 -1
- package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +18 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +42 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +47 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-gz.test.js +24 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-hardening.test.js +160 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-open-nofollow.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-excl.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-stream.test.js +181 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-corrupted-anchor.test.js +65 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-incremental-verify.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +48 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +13 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +122 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +5 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +62 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +12 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cluster-storage.test.js +40 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +146 -5
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +14 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compression-range.test.js +115 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +17 -5
- package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +27 -5
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +20 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/dpop-alg-kty.test.js +64 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +43 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +33 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +12 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +72 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-throttle-transform.test.js +88 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +25 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +20 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-header-injection.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +63 -9
- package/lib/vendor/blamejs/test/layer-0-primitives/mdoc.test.js +41 -14
- package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +61 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/object-store-range-header.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +35 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/output-header-hardening.test.js +102 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parser-verify-hardening.test.js +191 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/proto-shadow-allowlist.test.js +120 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +75 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/restore-blob-remap.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention-sweep-termination.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-body-validation.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-json-stringify-for-script.test.js +43 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +48 -5
- package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +23 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +54 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +24 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +42 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +7 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/template-escape-html.test.js +43 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +15 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-default-store.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vendor-currency-classify.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +22 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/x509-chain-ca-enforcement.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +34 -0
- package/package.json +1 -1
|
@@ -42,6 +42,10 @@ var audit = lazyRequire(function () { return require("../audit"); });
|
|
|
42
42
|
var observability = lazyRequire(function () { return require("../observability"); });
|
|
43
43
|
|
|
44
44
|
var DEFAULT_METHODS = Object.freeze(["POST", "PUT", "DELETE", "PATCH"]);
|
|
45
|
+
// Monotonic per-process counter giving each fetchMetadata mount a unique
|
|
46
|
+
// idempotency id (see GATE_ID in create) so a stricter sub-route instance is
|
|
47
|
+
// not silently disabled by an earlier lenient one sharing a global flag.
|
|
48
|
+
var _fmGateSeq = 0;
|
|
45
49
|
|
|
46
50
|
// Sec-Fetch-Dest request-destination vocabulary (Fetch Standard §3.2.6
|
|
47
51
|
// "destination", https://fetch.spec.whatwg.org/#concept-request-destination;
|
|
@@ -81,7 +85,7 @@ function _validateDestList(list, label) {
|
|
|
81
85
|
// the typo surfaces before it silently fails to match at request time.
|
|
82
86
|
if (!Array.isArray(list)) return;
|
|
83
87
|
for (var i = 0; i < list.length; i += 1) {
|
|
84
|
-
if (!KNOWN_DEST_SET
|
|
88
|
+
if (!Object.prototype.hasOwnProperty.call(KNOWN_DEST_SET, list[i])) {
|
|
85
89
|
throw new Error("middleware.fetchMetadata: " + label + "[" + i +
|
|
86
90
|
"] is not a known Sec-Fetch-Dest value (got '" + String(list[i]) +
|
|
87
91
|
"'). Known destinations: " + KNOWN_DESTINATIONS.join(", ") + ".");
|
|
@@ -206,8 +210,26 @@ function create(opts) {
|
|
|
206
210
|
}
|
|
207
211
|
}
|
|
208
212
|
var allowedNavigate = opts.allowedNavigate !== false;
|
|
213
|
+
// An empty methods array is truthy, so `opts.methods || DEFAULT_METHODS`
|
|
214
|
+
// would keep `[]` and `methods.indexOf(req.method) === -1` would be true for
|
|
215
|
+
// EVERY request — silently turning the gate into a pass-through. Reject a
|
|
216
|
+
// present-but-empty/garbage list at config time (fail-fast, don't degrade
|
|
217
|
+
// the gate to a no-op).
|
|
218
|
+
if (opts.methods !== undefined) {
|
|
219
|
+
if (!Array.isArray(opts.methods) || opts.methods.length === 0 ||
|
|
220
|
+
!opts.methods.every(function (m) { return typeof m === "string" && m.length > 0; })) {
|
|
221
|
+
throw new Error("middleware.fetchMetadata: opts.methods must be a non-empty array of HTTP method tokens (omit it for the POST/PUT/DELETE/PATCH default)");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
209
224
|
var methods = (opts.methods || DEFAULT_METHODS).map(function (m) { return m.toUpperCase(); });
|
|
210
225
|
var auditOn = opts.audit !== false;
|
|
226
|
+
// Per-instance idempotency id: a request carries a Set of gates that have
|
|
227
|
+
// already run. The OLD shared `req._fetchMetadataChecked` boolean let the
|
|
228
|
+
// FIRST fetch-metadata mount (e.g. the lenient app-level default) permanently
|
|
229
|
+
// disable a STRICTER instance layered on a sub-route. Keying by a unique id
|
|
230
|
+
// lets each distinct mount run once while the SAME instance mounted twice
|
|
231
|
+
// still no-ops.
|
|
232
|
+
var GATE_ID = "fm:" + (_fmGateSeq++);
|
|
211
233
|
|
|
212
234
|
function _emitDenied(req, reason) {
|
|
213
235
|
if (!auditOn) return;
|
|
@@ -223,9 +245,11 @@ function create(opts) {
|
|
|
223
245
|
}
|
|
224
246
|
|
|
225
247
|
return function fetchMetadata(req, res, next) {
|
|
226
|
-
// Idempotent:
|
|
227
|
-
|
|
228
|
-
req.
|
|
248
|
+
// Idempotent PER INSTANCE: the same mount running twice on a request is a
|
|
249
|
+
// no-op, but a distinct (e.g. stricter sub-route) instance still evaluates.
|
|
250
|
+
if (!req._fetchMetadataGates) req._fetchMetadataGates = Object.create(null);
|
|
251
|
+
if (req._fetchMetadataGates[GATE_ID]) return next();
|
|
252
|
+
req._fetchMetadataGates[GATE_ID] = true;
|
|
229
253
|
if (_shouldSkip(req)) return next();
|
|
230
254
|
if (methods.indexOf(req.method) === -1) return next();
|
|
231
255
|
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
* the wiki example default).
|
|
17
17
|
*
|
|
18
18
|
* var fence = b.middleware.networkAllowlist({
|
|
19
|
-
* paths:
|
|
20
|
-
* allowedCidrs:
|
|
21
|
-
*
|
|
22
|
-
* denyStatus:
|
|
23
|
-
* denyBody:
|
|
24
|
-
* audit:
|
|
19
|
+
* paths: ["/admin", "/admin/", "/healthz/internal"],
|
|
20
|
+
* allowedCidrs: ["10.0.0.0/8", "192.168.0.0/16", "::1/128"],
|
|
21
|
+
* trustedProxies: ["10.0.0.0/8"], // peer-gate XFF to your proxy range
|
|
22
|
+
* denyStatus: 404, // default — reveal nothing about the gate
|
|
23
|
+
* denyBody: "Not Found", // default
|
|
24
|
+
* audit: b.audit, // default: null — emits network.gate.denied
|
|
25
25
|
* });
|
|
26
26
|
*
|
|
27
27
|
* router.use(fence);
|
|
@@ -29,9 +29,11 @@
|
|
|
29
29
|
* Behaviour:
|
|
30
30
|
* - The middleware is path-scoped: requests whose pathname doesn't
|
|
31
31
|
* start with any of `paths` pass through unchanged. Hot-path-cheap.
|
|
32
|
-
* - Requests on a gated path get their client IP resolved
|
|
33
|
-
*
|
|
34
|
-
*
|
|
32
|
+
* - Requests on a gated path get their client IP resolved peer-gated:
|
|
33
|
+
* the socket address by default, or — when `trustedProxies` /
|
|
34
|
+
* `clientIpResolver` is set — X-Forwarded-For honored only from a
|
|
35
|
+
* trusted proxy peer. A bare `trustProxy` is refused at construction
|
|
36
|
+
* because it would let a direct caller forge an allowed address.
|
|
35
37
|
* - The IP is checked against the CIDR allowlist using
|
|
36
38
|
* b.ssrfGuard.cidrContains. A miss returns denyStatus + denyBody
|
|
37
39
|
* and audits the rejection. Default 404 hides the gate's
|
|
@@ -84,38 +86,47 @@ function _validateCidr(cidr) {
|
|
|
84
86
|
* authorization prevents unauthorized USERS from reaching sensitive
|
|
85
87
|
* routes; this middleware adds a NETWORK-layer fence so a credential
|
|
86
88
|
* leak doesn't compromise the gate. Path-scoped — requests outside
|
|
87
|
-
* the configured prefixes pass through hot-path-cheap.
|
|
88
|
-
* client IP
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
89
|
+
* the configured prefixes pass through hot-path-cheap. Checks the
|
|
90
|
+
* resolved client IP against the CIDR allowlist via
|
|
91
|
+
* `b.ssrfGuard.cidrContains` and refuses misses with HTTP 404 by
|
|
92
|
+
* default (hides the gate from probes). Throws at create-time on
|
|
93
|
+
* malformed opts.
|
|
94
|
+
*
|
|
95
|
+
* Client-IP resolution is peer-gated. By default only the socket
|
|
96
|
+
* address is used — X-Forwarded-For is attacker-forgeable, so trusting
|
|
97
|
+
* it bare would let a direct caller spoof an allowed IP through the
|
|
98
|
+
* gate. Behind a reverse proxy, declare it with `trustedProxies`
|
|
99
|
+
* (CIDRs — XFF is then honored only when the immediate peer is one of
|
|
100
|
+
* them) or own resolution entirely with `clientIpResolver(req)`. A bare
|
|
101
|
+
* `trustProxy` is refused at construction.
|
|
92
102
|
*
|
|
93
103
|
* @opts
|
|
94
104
|
* {
|
|
95
|
-
* paths:
|
|
96
|
-
* allowedCidrs:
|
|
97
|
-
* deniedCidrs:
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
105
|
+
* paths: string[], // pathname prefixes, required
|
|
106
|
+
* allowedCidrs: string[], // required
|
|
107
|
+
* deniedCidrs: string[],
|
|
108
|
+
* trustedProxies: string[], // CIDRs of your reverse proxies — peer-gates X-Forwarded-For
|
|
109
|
+
* clientIpResolver: function(req): string|null, // own client-IP resolution
|
|
110
|
+
* denyStatus: number, // default 404
|
|
111
|
+
* denyBody: string, // default "Not Found"
|
|
112
|
+
* audit: object,
|
|
113
|
+
* onDeny: function(req, res, info): void, // own the refusal; info = { status, reason, clientIp, route }
|
|
114
|
+
* problemDetails: boolean, // default false — emit RFC 9457 application/problem+json instead of text/plain
|
|
104
115
|
* }
|
|
105
116
|
*
|
|
106
117
|
* @example
|
|
107
118
|
* var b = require("@blamejs/core");
|
|
108
119
|
* var app = b.router.create();
|
|
109
120
|
* app.use(b.middleware.networkAllowlist({
|
|
110
|
-
* paths:
|
|
111
|
-
* allowedCidrs:
|
|
112
|
-
*
|
|
121
|
+
* paths: ["/admin"],
|
|
122
|
+
* allowedCidrs: ["10.0.0.0/8", "::1/128"],
|
|
123
|
+
* trustedProxies: ["10.0.0.0/8"], // your reverse proxy's range
|
|
113
124
|
* }));
|
|
114
125
|
*/
|
|
115
126
|
function create(opts) {
|
|
116
127
|
opts = opts || {};
|
|
117
128
|
validateOpts(opts, [
|
|
118
|
-
"paths", "allowedCidrs", "deniedCidrs", "trustProxy",
|
|
129
|
+
"paths", "allowedCidrs", "deniedCidrs", "trustProxy", "trustedProxies", "clientIpResolver",
|
|
119
130
|
"denyStatus", "denyBody", "audit", "onDeny", "problemDetails",
|
|
120
131
|
], "middleware.networkAllowlist");
|
|
121
132
|
|
|
@@ -148,10 +159,30 @@ function create(opts) {
|
|
|
148
159
|
}
|
|
149
160
|
}
|
|
150
161
|
|
|
162
|
+
// Client-IP resolution for an access-control gate must be peer-gated:
|
|
163
|
+
// a bare `trustProxy` honors X-Forwarded-For from any caller, so a client
|
|
164
|
+
// connecting directly can forge an allowed address and walk through the
|
|
165
|
+
// gate. Operators behind a reverse proxy declare it via `trustedProxies`
|
|
166
|
+
// (CIDRs of their proxies — XFF is then peer-gated) or own resolution
|
|
167
|
+
// entirely via `clientIpResolver`. We refuse, at construction, the
|
|
168
|
+
// spoofable combination of `trustProxy` without either.
|
|
169
|
+
var _ipResolver;
|
|
170
|
+
try {
|
|
171
|
+
_ipResolver = requestHelpers.trustedClientIp({
|
|
172
|
+
trustedProxies: opts.trustedProxies,
|
|
173
|
+
clientIpResolver: opts.clientIpResolver,
|
|
174
|
+
});
|
|
175
|
+
} catch (e) { throw _err("BAD_OPT", e.message); }
|
|
176
|
+
var trustProxyOpt = opts.trustProxy === true || typeof opts.trustProxy === "number";
|
|
177
|
+
if (trustProxyOpt && !_ipResolver.peerGated) {
|
|
178
|
+
throw _err("BAD_OPT",
|
|
179
|
+
"trustProxy is spoofable for an access-control gate — X-Forwarded-For from a " +
|
|
180
|
+
"direct caller would be trusted. Declare your reverse proxies via " +
|
|
181
|
+
"trustedProxies: [\"10.0.0.0/8\", …] (peer-gated XFF) or supply clientIpResolver(req).");
|
|
182
|
+
}
|
|
183
|
+
|
|
151
184
|
var paths = opts.paths.slice();
|
|
152
185
|
var allowedCidrs = opts.allowedCidrs.slice();
|
|
153
|
-
var trustProxy = opts.trustProxy === true || typeof opts.trustProxy === "number"
|
|
154
|
-
? opts.trustProxy : false;
|
|
155
186
|
var denyStatus = typeof opts.denyStatus === "number" ? opts.denyStatus : 404;
|
|
156
187
|
if (denyStatus < 400 || denyStatus >= 600 || Math.floor(denyStatus) !== denyStatus) {
|
|
157
188
|
throw _err("BAD_OPT", "denyStatus must be a 4xx or 5xx integer, got " + denyStatus);
|
|
@@ -212,7 +243,7 @@ function create(opts) {
|
|
|
212
243
|
var pathname = req.pathname || (req.url || "").split("?")[0];
|
|
213
244
|
if (!_matchesPath(pathname)) return next();
|
|
214
245
|
|
|
215
|
-
var ip =
|
|
246
|
+
var ip = _ipResolver.resolve(req);
|
|
216
247
|
if (!ip) {
|
|
217
248
|
// Fail closed: a request we can't even derive an IP for shouldn't
|
|
218
249
|
// bypass the gate.
|
|
@@ -118,17 +118,6 @@ function _conflictRefs(dialect, table) {
|
|
|
118
118
|
var audit = lazyRequire(function () { return require("../audit"); });
|
|
119
119
|
var logger = lazyRequire(function () { return require("../log").boot("rate-limit"); });
|
|
120
120
|
|
|
121
|
-
// `_clientIp` defers to `requestHelpers.clientIp`, threading the
|
|
122
|
-
// per-middleware `trustProxy` opt. Default refuses forwarded headers
|
|
123
|
-
// (returning the socket address only) — operators behind a sanitizing
|
|
124
|
-
// reverse proxy opt in via `trustProxy: true` (or a hop count).
|
|
125
|
-
function _clientIpFor(trustProxy) {
|
|
126
|
-
return function (req) {
|
|
127
|
-
var ip = requestHelpers.clientIp(req, { trustProxy: trustProxy });
|
|
128
|
-
return ip || "unknown";
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
121
|
// Reject NaN / Infinity / negative / non-positive / non-number at create
|
|
133
122
|
// time so a misconfigured rate-limit can't silently degrade to "no
|
|
134
123
|
// limit" or produce divide-by-zero verdicts at request time.
|
|
@@ -457,7 +446,9 @@ function _resolveBackend(opts) {
|
|
|
457
446
|
* limit: number,
|
|
458
447
|
* windowMs: number,
|
|
459
448
|
* pruneIntervalMs: number,
|
|
460
|
-
*
|
|
449
|
+
* trustedProxies: string|string[], // CIDRs of your reverse proxies — peer-gates X-Forwarded-For for the IP key
|
|
450
|
+
* clientIpResolver: function(req): string|null, // own the rate-limit key's client IP
|
|
451
|
+
* trustProxy: boolean|number, // legacy; refused with the default IP key (spoofable) — use trustedProxies
|
|
461
452
|
* }
|
|
462
453
|
*
|
|
463
454
|
* @example
|
|
@@ -475,15 +466,33 @@ function create(opts) {
|
|
|
475
466
|
validateOpts(opts, [
|
|
476
467
|
"keyFn", "statusOnLimit", "bodyOnLimit", "onDeny", "problemDetails",
|
|
477
468
|
"header", "headerPrefix", "skipPaths", "scope",
|
|
478
|
-
"backend", "trustProxy", "algorithm",
|
|
469
|
+
"backend", "trustProxy", "trustedProxies", "clientIpResolver", "algorithm",
|
|
479
470
|
// memory backend (token-bucket)
|
|
480
471
|
"burst", "refillPerSecond",
|
|
481
472
|
// memory backend (fixed-window) + cluster backend
|
|
482
473
|
"max", "limit", "windowMs", "pruneIntervalMs",
|
|
483
474
|
], "middleware.rateLimit");
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
475
|
+
// Peer-gated client-IP resolution. The default key (and the audit-actor
|
|
476
|
+
// IP) is the client address; a bare trustProxy would let a caller forge
|
|
477
|
+
// X-Forwarded-For to evade their own limit or poison a victim's bucket.
|
|
478
|
+
// Operators behind a proxy declare trustedProxies (CIDRs) or own
|
|
479
|
+
// resolution via clientIpResolver. A bare trustProxy is refused when the
|
|
480
|
+
// default IP key is in use (no keyFn) — it would be spoofable.
|
|
481
|
+
var _ipResolver;
|
|
482
|
+
try {
|
|
483
|
+
_ipResolver = requestHelpers.trustedClientIp({
|
|
484
|
+
trustedProxies: opts.trustedProxies,
|
|
485
|
+
clientIpResolver: opts.clientIpResolver,
|
|
486
|
+
});
|
|
487
|
+
} catch (e) { throw new Error("middleware.rateLimit: " + e.message); }
|
|
488
|
+
var trustProxyBare = opts.trustProxy === true || typeof opts.trustProxy === "number";
|
|
489
|
+
if (trustProxyBare && !_ipResolver.peerGated && !opts.keyFn) {
|
|
490
|
+
throw new Error("middleware.rateLimit: trustProxy is spoofable — a caller can forge " +
|
|
491
|
+
"X-Forwarded-For to evade the limit or poison another IP's bucket. Declare your " +
|
|
492
|
+
"reverse proxies via trustedProxies: [\"10.0.0.0/8\", …], supply clientIpResolver(req), " +
|
|
493
|
+
"or set your own keyFn.");
|
|
494
|
+
}
|
|
495
|
+
var _clientIp = function (req) { return _ipResolver.resolve(req) || "unknown"; };
|
|
487
496
|
var keyFn = opts.keyFn || _clientIp;
|
|
488
497
|
var statusOnLimit = opts.statusOnLimit || 429;
|
|
489
498
|
var bodyOnLimit = opts.bodyOnLimit !== undefined ? opts.bodyOnLimit : "Too Many Requests";
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// + /Schemas surfaces backed by operator-supplied CRUD callbacks.
|
|
5
5
|
|
|
6
6
|
var framework_error = require("../framework-error");
|
|
7
|
+
var numericBounds = require("../numeric-bounds");
|
|
7
8
|
var pick = require("../pick");
|
|
8
9
|
var validateOpts = require("../validate-opts");
|
|
9
10
|
var safeJson = require("../safe-json");
|
|
@@ -609,7 +610,7 @@ function _anyDependencyFailed(refs, plan, executed, bulkIdMap) {
|
|
|
609
610
|
// RFC 7644 §3.7 — failOnErrors is an OPTIONAL integer >= 1. Absent /
|
|
610
611
|
// non-conforming values mean "process every operation" (null).
|
|
611
612
|
function _parseFailOnErrors(value) {
|
|
612
|
-
if (
|
|
613
|
+
if (!numericBounds.isPositiveFiniteInt(value)) {
|
|
613
614
|
return null;
|
|
614
615
|
}
|
|
615
616
|
return value;
|
|
@@ -210,7 +210,9 @@ function _validatePermissionsPolicy(value) {
|
|
|
210
210
|
* acceptCh: string|false,
|
|
211
211
|
* criticalCh: string|false,
|
|
212
212
|
* reportingEndpoints: object,
|
|
213
|
-
*
|
|
213
|
+
* trustedProxies: string|string[], // CIDRs of your reverse proxies — peer-gates X-Forwarded-Proto for HSTS
|
|
214
|
+
* protocolResolver: function(req): "http"|"https", // own the HTTPS decision
|
|
215
|
+
* trustProxy: boolean|number, // legacy; refused unless paired with trustedProxies/protocolResolver (spoofable)
|
|
214
216
|
* coopReportOnly: string, // default: off — monitor-mode COOP
|
|
215
217
|
* coepReportOnly: string, // default: off — monitor-mode COEP
|
|
216
218
|
* documentPolicyReportOnly: string, // default: off — monitor-mode Document-Policy
|
|
@@ -231,6 +233,7 @@ function create(opts) {
|
|
|
231
233
|
"hsts", "contentTypeOptions", "frameOptions", "referrerPolicy",
|
|
232
234
|
"permissionsPolicy", "coop", "coep", "corp",
|
|
233
235
|
"originAgentCluster", "dnsPrefetchControl", "csp", "trustProxy",
|
|
236
|
+
"trustedProxies", "protocolResolver",
|
|
234
237
|
"reportingEndpoints", "documentPolicy", "criticalCh", "acceptCh",
|
|
235
238
|
"coopReportOnly", "coepReportOnly", "documentPolicyReportOnly",
|
|
236
239
|
"requireDocumentPolicy", "serviceWorkerAllowed",
|
|
@@ -238,8 +241,23 @@ function create(opts) {
|
|
|
238
241
|
if (opts.permissionsPolicy && typeof opts.permissionsPolicy === "string") {
|
|
239
242
|
_validatePermissionsPolicy(opts.permissionsPolicy);
|
|
240
243
|
}
|
|
241
|
-
|
|
242
|
-
|
|
244
|
+
// HSTS is emitted only on HTTPS responses; behind a proxy that comes from
|
|
245
|
+
// X-Forwarded-Proto. A bare trustProxy trusts the forgeable header from any
|
|
246
|
+
// caller, so a direct request forging "http" could suppress HSTS on a real
|
|
247
|
+
// HTTPS response (SSL-strip window). Peer-gate it via trustedProxies, or own
|
|
248
|
+
// the decision via protocolResolver; a bare trustProxy is refused.
|
|
249
|
+
var _proto;
|
|
250
|
+
try {
|
|
251
|
+
_proto = requestHelpers.trustedProtocol({
|
|
252
|
+
trustedProxies: opts.trustedProxies,
|
|
253
|
+
protocolResolver: opts.protocolResolver,
|
|
254
|
+
});
|
|
255
|
+
} catch (e) { throw new TypeError("middleware.securityHeaders: " + e.message); }
|
|
256
|
+
if ((opts.trustProxy === true || typeof opts.trustProxy === "number") && !_proto.peerGated) {
|
|
257
|
+
throw new TypeError("middleware.securityHeaders: trustProxy is spoofable for the HSTS " +
|
|
258
|
+
"decision — a direct caller could forge X-Forwarded-Proto to suppress HSTS. Declare your " +
|
|
259
|
+
"reverse proxies via trustedProxies: [\"10.0.0.0/8\", …] or supply protocolResolver(req).");
|
|
260
|
+
}
|
|
243
261
|
var hsts = opts.hsts === undefined ? "max-age=63072000; includeSubDomains; preload" : opts.hsts;
|
|
244
262
|
var ctOpts = opts.contentTypeOptions === undefined ? "nosniff" : opts.contentTypeOptions;
|
|
245
263
|
var frameOpts = opts.frameOptions === undefined ? "DENY" : opts.frameOptions;
|
|
@@ -317,9 +335,9 @@ function create(opts) {
|
|
|
317
335
|
// RFC 6797 §7.2: HSTS over plain HTTP is meaningless (UAs ignore
|
|
318
336
|
// it). Skip the header on non-TLS requests so dev-over-HTTP doesn't
|
|
319
337
|
// surface confusing "Strict-Transport-Security on http://" lines.
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
if (hsts &&
|
|
338
|
+
// Peer-gated protocol resolution — X-Forwarded-Proto honored only from a
|
|
339
|
+
// trusted proxy (trustedProxies / protocolResolver), else the TLS socket.
|
|
340
|
+
if (hsts && _proto.resolve(req) === "https") {
|
|
323
341
|
res.setHeader("Strict-Transport-Security", hsts);
|
|
324
342
|
}
|
|
325
343
|
if (ctOpts) res.setHeader("X-Content-Type-Options", ctOpts);
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
|
|
67
67
|
var validateOpts = require("../validate-opts");
|
|
68
68
|
var safeBuffer = require("../safe-buffer");
|
|
69
|
+
var safeJson = require("../safe-json");
|
|
69
70
|
|
|
70
71
|
// Per W3C draft + Chromium implementation. `immediate` triggers the
|
|
71
72
|
// speculation as soon as the rules are seen; `conservative` waits
|
|
@@ -129,7 +130,7 @@ function _validateRules(rules, label) {
|
|
|
129
130
|
throw new TypeError(label + "." + actionKey + "[" + ei +
|
|
130
131
|
"].where must be a `where` clause object (W3C draft, e.g. { href_matches: \"/path/*\" })");
|
|
131
132
|
}
|
|
132
|
-
if (typeof rule.eagerness !== "string" || !EAGERNESS_LEVELS
|
|
133
|
+
if (typeof rule.eagerness !== "string" || !Object.prototype.hasOwnProperty.call(EAGERNESS_LEVELS, rule.eagerness)) {
|
|
133
134
|
throw new TypeError(label + "." + actionKey + "[" + ei +
|
|
134
135
|
"].eagerness must be one of: " + Object.keys(EAGERNESS_LEVELS).join(", "));
|
|
135
136
|
}
|
|
@@ -245,8 +246,10 @@ function create(opts) {
|
|
|
245
246
|
}
|
|
246
247
|
|
|
247
248
|
// Pre-built inline JSON. The body is small (rules objects are
|
|
248
|
-
// typically ~200 bytes);
|
|
249
|
-
|
|
249
|
+
// typically ~200 bytes); stringify once and cache. Uses the
|
|
250
|
+
// <script>-safe serializer so a rules value containing "</script>"
|
|
251
|
+
// (or U+2028/U+2029) cannot break out of the injected element.
|
|
252
|
+
var inlineJson = inline ? safeJson.stringifyForScript(rulesObj) : null;
|
|
250
253
|
|
|
251
254
|
return function speculationRules(req, res, next) {
|
|
252
255
|
if (!inline) {
|
|
@@ -399,7 +399,7 @@ function create(opts) {
|
|
|
399
399
|
|
|
400
400
|
var extensions = Array.isArray(opts.extensions) ? opts.extensions.slice() : DEFAULT_EXTENSIONS.slice();
|
|
401
401
|
for (var i = 0; i < extensions.length; i++) {
|
|
402
|
-
if (!KNOWN_EXTENSIONS
|
|
402
|
+
if (!Object.prototype.hasOwnProperty.call(KNOWN_EXTENSIONS, extensions[i])) {
|
|
403
403
|
throw new TusError("tus/bad-opts",
|
|
404
404
|
"middleware.tusUpload: unknown extension '" + extensions[i] + "'");
|
|
405
405
|
}
|
|
@@ -416,7 +416,7 @@ function create(opts) {
|
|
|
416
416
|
var checksumAlgorithmSet = {};
|
|
417
417
|
for (var j = 0; j < checksumAlgorithms.length; j++) {
|
|
418
418
|
var algo = checksumAlgorithms[j];
|
|
419
|
-
if (!KNOWN_CHECKSUM_ALGORITHMS
|
|
419
|
+
if (!Object.prototype.hasOwnProperty.call(KNOWN_CHECKSUM_ALGORITHMS, algo)) {
|
|
420
420
|
throw new TusError("tus/bad-opts",
|
|
421
421
|
"middleware.tusUpload: unknown checksum algorithm '" + algo + "'");
|
|
422
422
|
}
|
|
@@ -412,7 +412,7 @@ function roundMinor(minor, step, mode) {
|
|
|
412
412
|
throw new MoneyError("money/bad-minor-units",
|
|
413
413
|
"minor must be an integer (BigInt or safe integer Number); got " + (typeof minor));
|
|
414
414
|
}
|
|
415
|
-
if (!INCREMENT_MODES
|
|
415
|
+
if (!Object.prototype.hasOwnProperty.call(INCREMENT_MODES, mode)) {
|
|
416
416
|
throw new MoneyError("money/bad-rounding-mode",
|
|
417
417
|
"mode must be one of half-even | half-up | half-down | ceiling | floor; got " + String(mode));
|
|
418
418
|
}
|
|
@@ -211,7 +211,7 @@ function create(opts) {
|
|
|
211
211
|
var paths = _resolvePaths(opts.dataDir, opts.paths);
|
|
212
212
|
var vault = opts.vault || null;
|
|
213
213
|
var caKeySealedMode = (opts.caKeySealedMode || "required").toLowerCase();
|
|
214
|
-
if (!VALID_SEAL_MODES
|
|
214
|
+
if (!Object.prototype.hasOwnProperty.call(VALID_SEAL_MODES, caKeySealedMode)) {
|
|
215
215
|
throw new MtlsCaError("mtls-ca/bad-mode",
|
|
216
216
|
"caKeySealedMode must be 'required' or 'disabled' " +
|
|
217
217
|
"(legacy 'auto' was removed — it defaulted to plaintext-on-disk)");
|
|
@@ -246,7 +246,7 @@ function create(opts) {
|
|
|
246
246
|
current: generation,
|
|
247
247
|
};
|
|
248
248
|
}
|
|
249
|
-
var pem =
|
|
249
|
+
var pem = atomicFile.fdSafeReadSync(paths.caCert, { maxBytes: C.BYTES.mib(1) });
|
|
250
250
|
var gen = parseGeneration(pem);
|
|
251
251
|
return {
|
|
252
252
|
exists: true,
|
|
@@ -272,7 +272,9 @@ function create(opts) {
|
|
|
272
272
|
"CA_KEY_SEALED='required' but " + paths.caKeySealed + " does not exist");
|
|
273
273
|
}
|
|
274
274
|
_requireVault("sealed CA key load");
|
|
275
|
-
|
|
275
|
+
// Cap + fd-bound CA-private-key read. NO refuseSymlink: caKeySealed may be
|
|
276
|
+
// an operator-absolute path on a k8s/KMS secret volume that symlinks it.
|
|
277
|
+
var sealedBytes = atomicFile.fdSafeReadSync(paths.caKeySealed, { maxBytes: C.BYTES.kib(64), encoding: "utf8" }).trim();
|
|
276
278
|
var pem = vault.unseal(sealedBytes);
|
|
277
279
|
if (!pem) {
|
|
278
280
|
throw new MtlsCaError("mtls-ca/unseal-failed",
|
|
@@ -285,7 +287,9 @@ function create(opts) {
|
|
|
285
287
|
throw new MtlsCaError("mtls-ca/plain-required",
|
|
286
288
|
"caKeySealedMode='disabled' but " + paths.caKey + " does not exist");
|
|
287
289
|
}
|
|
288
|
-
|
|
290
|
+
// Cap + fd-bound plaintext CA-private-key read (disabled mode = dev opt-out).
|
|
291
|
+
// NO refuseSymlink (operator-absolute path may symlink).
|
|
292
|
+
return atomicFile.fdSafeReadSync(paths.caKey, { maxBytes: C.BYTES.kib(64) });
|
|
289
293
|
}
|
|
290
294
|
|
|
291
295
|
function loadCert() {
|
|
@@ -293,7 +297,7 @@ function create(opts) {
|
|
|
293
297
|
throw new MtlsCaError("mtls-ca/missing-cert",
|
|
294
298
|
"no CA cert on disk at " + paths.caCert);
|
|
295
299
|
}
|
|
296
|
-
return
|
|
300
|
+
return atomicFile.fdSafeReadSync(paths.caCert, { maxBytes: C.BYTES.mib(1) });
|
|
297
301
|
}
|
|
298
302
|
|
|
299
303
|
// Atomic commit: write .tmp + atomic rename for both key and cert.
|
|
@@ -446,7 +450,7 @@ function create(opts) {
|
|
|
446
450
|
// safeJson.parse caps depth + size + protects against
|
|
447
451
|
// proto-pollution; a tampered or truncated file shouldn't be able to
|
|
448
452
|
// corrupt the rotator process.
|
|
449
|
-
var json = safeJson.parse(
|
|
453
|
+
var json = safeJson.parse(atomicFile.fdSafeReadSync(paths.revocations, { maxBytes: C.BYTES.mib(16), encoding: "utf8" }),
|
|
450
454
|
{ maxBytes: C.BYTES.mib(16) });
|
|
451
455
|
return (json && Array.isArray(json.revocations)) ? json.revocations : [];
|
|
452
456
|
} catch (e) {
|
|
@@ -179,7 +179,7 @@ var QTYPE_BY_NAME = Object.freeze({
|
|
|
179
179
|
function create(opts) {
|
|
180
180
|
opts = opts || {};
|
|
181
181
|
var profile = opts.profile || (opts.posture && safeDns.compliancePosture(opts.posture)) || DEFAULT_PROFILE;
|
|
182
|
-
if (!safeDns.PROFILES
|
|
182
|
+
if (!Object.prototype.hasOwnProperty.call(safeDns.PROFILES, profile)) {
|
|
183
183
|
throw new ResolverError("resolver/bad-profile",
|
|
184
184
|
"create: unknown profile '" + profile + "'");
|
|
185
185
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var dns = require("node:dns");
|
|
4
|
+
var numericBounds = require("./numeric-bounds");
|
|
4
5
|
var net = require("node:net");
|
|
5
6
|
var https = require("node:https");
|
|
6
7
|
var nodeTls = require("node:tls");
|
|
@@ -347,10 +348,16 @@ function _decodeDnsAnswer(buf, qtype) {
|
|
|
347
348
|
for (var a = 0; a < ancount; a++) {
|
|
348
349
|
_skipDnsName(buf, state);
|
|
349
350
|
var off = state.off;
|
|
351
|
+
// Bound the RR fixed header (10 bytes: type+class+ttl+rdlen) and the rdata
|
|
352
|
+
// before indexing — ancount comes from the (untrusted upstream) header, so a
|
|
353
|
+
// truncated reply would otherwise over-read into a raw RangeError. Mirrors
|
|
354
|
+
// the hardened _decodeDnsAnswerRaw guards.
|
|
355
|
+
if (off + 10 > buf.length) throw new DnsError("dns/bad-reply", "answer record truncated");
|
|
350
356
|
var rtype = buf.readUInt16BE(off); off += 2;
|
|
351
357
|
off += 2;
|
|
352
358
|
off += 4;
|
|
353
359
|
var rdlen = buf.readUInt16BE(off); off += 2;
|
|
360
|
+
if (off + rdlen > buf.length) throw new DnsError("dns/bad-reply", "answer rdata truncated");
|
|
354
361
|
if (rtype === qtype && qtype === 1 && rdlen === 4) {
|
|
355
362
|
addrs.push(buf[off] + "." + buf[off + 1] + "." + buf[off + 2] + "." + buf[off + 3]);
|
|
356
363
|
} else if (rtype === qtype && qtype === DNS_QTYPE_AAAA && rdlen === IPV6_ADDR_BYTES) {
|
|
@@ -1851,7 +1858,7 @@ var DS_DIGEST_TYPES = Object.freeze({
|
|
|
1851
1858
|
});
|
|
1852
1859
|
|
|
1853
1860
|
function classifyDnskeyAlgorithm(algorithm) {
|
|
1854
|
-
if (
|
|
1861
|
+
if (!numericBounds.isFiniteInt(algorithm)) {
|
|
1855
1862
|
return null;
|
|
1856
1863
|
}
|
|
1857
1864
|
var row = DNSKEY_ALGORITHMS[algorithm];
|
|
@@ -1874,7 +1881,7 @@ function classifyDnskeyAlgorithm(algorithm) {
|
|
|
1874
1881
|
}
|
|
1875
1882
|
|
|
1876
1883
|
function classifyDsDigestType(digestType) {
|
|
1877
|
-
if (
|
|
1884
|
+
if (!numericBounds.isFiniteInt(digestType)) {
|
|
1878
1885
|
return null;
|
|
1879
1886
|
}
|
|
1880
1887
|
var row = DS_DIGEST_TYPES[digestType];
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
47
|
var nodeCrypto = require("node:crypto");
|
|
48
|
+
var numericBounds = require("./numeric-bounds");
|
|
48
49
|
var bCrypto = require("./crypto");
|
|
49
50
|
var safeBuffer = require("./safe-buffer");
|
|
50
51
|
var validateOpts = require("./validate-opts");
|
|
@@ -515,7 +516,7 @@ function nsec3Hash(name, opts) {
|
|
|
515
516
|
validateOpts(opts, ["salt", "iterations"], "dnssec.nsec3Hash");
|
|
516
517
|
var salt = _bytes(opts.salt, "salt");
|
|
517
518
|
var iters = opts.iterations;
|
|
518
|
-
if (
|
|
519
|
+
if (!numericBounds.isNonNegativeFiniteInt(iters)) {
|
|
519
520
|
throw new DnssecError("dnssec/bad-iterations", "dnssec.nsec3Hash: iterations must be a non-negative integer");
|
|
520
521
|
}
|
|
521
522
|
return _nsec3HashWire(_canonicalName(name), salt, iters);
|
|
@@ -176,6 +176,15 @@ async function mtaStsFetch(domain, opts) {
|
|
|
176
176
|
rejectUnauthorized: true,
|
|
177
177
|
});
|
|
178
178
|
} catch (_e) {
|
|
179
|
+
// RFC 8461 opportunistic fallback: a policy that can't be fetched — a
|
|
180
|
+
// network error, OR (with rejectUnauthorized:true + pinned servername
|
|
181
|
+
// above) a TLS-validation failure that signals a possible MITM of the
|
|
182
|
+
// policy endpoint — yields "no enforceable policy", so the sender
|
|
183
|
+
// proceeds without MTA-STS. This is the documented TOFU limitation for an
|
|
184
|
+
// UN-cached first fetch only: a valid cached policy is honored by the
|
|
185
|
+
// _getStsCache().wrap() wrapper and never reaches this catch, and the TLS
|
|
186
|
+
// failure itself is independently audited by httpClient's TLS layer — so
|
|
187
|
+
// this is a deliberate opportunistic fallback, not a silent swallow.
|
|
179
188
|
return null;
|
|
180
189
|
}
|
|
181
190
|
if (res.statusCode === 404) return null; // HTTP 404
|
|
@@ -403,23 +412,32 @@ function _selectorBytes(certDer, selector) {
|
|
|
403
412
|
return null;
|
|
404
413
|
}
|
|
405
414
|
|
|
415
|
+
// Constant-time byte-compare for TLSA association data. The TLSA record is
|
|
416
|
+
// public DNS so there is no secret to leak via timing, but the framework
|
|
417
|
+
// compares all crypto material (digests, certs) in constant time so the
|
|
418
|
+
// boundary stays uniform and can't regress into a leaky compare elsewhere.
|
|
419
|
+
function _constEqBytes(a, b) {
|
|
420
|
+
// bCrypto.timingSafeEqual is the length-tolerant constant-time wrapper.
|
|
421
|
+
return Buffer.isBuffer(a) && Buffer.isBuffer(b) && bCrypto.timingSafeEqual(a, b);
|
|
422
|
+
}
|
|
423
|
+
|
|
406
424
|
function _matchTlsaAgainstCert(rec, certDer) {
|
|
407
425
|
// Returns null on no-match, or { ok: true, mtypeLabel } on match.
|
|
408
426
|
var bytes = _selectorBytes(certDer, rec.selector);
|
|
409
427
|
if (!bytes) return null;
|
|
410
|
-
var dataHex =
|
|
428
|
+
var dataHex = (typeof rec.dataHex === "string" ? rec.dataHex : "").toLowerCase();
|
|
429
|
+
var want = Buffer.from(dataHex, "hex");
|
|
411
430
|
// RFC 6698 §2.1.3 matching types — Full byte match (0) or hashed
|
|
412
431
|
// comparison via SHA two-family (1 short / 2 long digest).
|
|
413
432
|
if (rec.mtype === 0) {
|
|
414
|
-
return bytes
|
|
415
|
-
? { ok: true, mtype: "Full" } : null;
|
|
433
|
+
return _constEqBytes(bytes, want) ? { ok: true, mtype: "Full" } : null;
|
|
416
434
|
}
|
|
417
435
|
if (rec.mtype === 1) {
|
|
418
|
-
return
|
|
436
|
+
return _constEqBytes(nodeCrypto.createHash("sha256").update(bytes).digest(), want)
|
|
419
437
|
? { ok: true, mtype: "SHA-256" } : null;
|
|
420
438
|
}
|
|
421
439
|
if (rec.mtype === 2) {
|
|
422
|
-
return
|
|
440
|
+
return _constEqBytes(nodeCrypto.createHash("sha512").update(bytes).digest(), want)
|
|
423
441
|
? { ok: true, mtype: "SHA-512" } : null;
|
|
424
442
|
}
|
|
425
443
|
return null;
|