@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
|
@@ -716,6 +716,9 @@ function _stripCrossOriginAuth(headers) {
|
|
|
716
716
|
* responseMode: "buffer", // "buffer" | "stream" | "always-resolve"
|
|
717
717
|
* maxResponseBytes: undefined, // 16 MiB control / 1 GiB GET defaults; ignored in "stream"
|
|
718
718
|
* onChunk: undefined, // (chunk: Buffer) => void — fires per response chunk
|
|
719
|
+
* maxBytesPerSec: undefined, // token-bucket bandwidth cap (bytes/sec) — paces BOTH the download response and the upload body with backpressure
|
|
720
|
+
* downloadTransform: undefined, // Transform | () => Transform | array — interpose on the response stream (e.g. a hashing or progress Transform)
|
|
721
|
+
* uploadTransform: undefined, // Transform | () => Transform | array — interpose on the request body before the wire
|
|
719
722
|
* signal: undefined, // AbortSignal — propagated to req / stream
|
|
720
723
|
* errorClass: HttpClientError, // FrameworkError subclass for thrown errors
|
|
721
724
|
* observer: undefined, // (stage, info) => void — lifecycle hook
|
|
@@ -733,6 +736,132 @@ function _stripCrossOriginAuth(headers) {
|
|
|
733
736
|
* });
|
|
734
737
|
* // → { statusCode: 200, headers: { "content-type": "application/json", ... }, body: <Buffer> }
|
|
735
738
|
*/
|
|
739
|
+
// Token-bucket bandwidth throttle as a Transform. Splits each chunk to the
|
|
740
|
+
// credit available, releasing at most `bytesPerSec` per second (1s burst
|
|
741
|
+
// capacity). Because `_transform`'s callback is not called until the whole
|
|
742
|
+
// chunk has been released, backpressure propagates upstream — on a download
|
|
743
|
+
// the socket pauses, on an upload the body source pauses. Wired into both the
|
|
744
|
+
// response (download) and request-body (upload) pipelines so the helpers'
|
|
745
|
+
// SSRF guard / DNS pinning / byte caps / atomic-rename are preserved.
|
|
746
|
+
function _throttleStream(bytesPerSec) {
|
|
747
|
+
var capacity = bytesPerSec; // allow at most 1s worth of burst
|
|
748
|
+
var tokens = capacity;
|
|
749
|
+
var last = Date.now();
|
|
750
|
+
function refill() {
|
|
751
|
+
var now = Date.now();
|
|
752
|
+
if (now > last) {
|
|
753
|
+
tokens = Math.min(capacity, tokens + ((now - last) / 1000) * bytesPerSec);
|
|
754
|
+
last = now;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
return new nodeStream.Transform({
|
|
758
|
+
transform: function (chunk, _enc, cb) {
|
|
759
|
+
var self = this;
|
|
760
|
+
var offset = 0;
|
|
761
|
+
function pump() {
|
|
762
|
+
refill();
|
|
763
|
+
if (offset >= chunk.length) { cb(); return; }
|
|
764
|
+
var avail = Math.floor(tokens);
|
|
765
|
+
if (avail >= 1) {
|
|
766
|
+
var n = Math.min(chunk.length - offset, avail);
|
|
767
|
+
tokens -= n;
|
|
768
|
+
self.push(chunk.subarray(offset, offset + n));
|
|
769
|
+
offset += n;
|
|
770
|
+
if (offset >= chunk.length) { cb(); return; }
|
|
771
|
+
setImmediate(pump); // more bytes, maybe more credit already
|
|
772
|
+
} else {
|
|
773
|
+
// ms to accrue one more byte of credit = (deficit / rate) seconds.
|
|
774
|
+
var waitMs = Math.ceil(C.TIME.seconds((1 - tokens) / bytesPerSec)) + 1;
|
|
775
|
+
var t = setTimeout(pump, waitMs);
|
|
776
|
+
if (t && typeof t.unref === "function") t.unref();
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
pump();
|
|
780
|
+
},
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// Validate + normalize a transform opt into an array. Each entry may be a
|
|
785
|
+
// Transform stream instance OR a `() => Transform` factory (the factory form is
|
|
786
|
+
// retry/redirect-safe — a single Transform instance can only be piped once, so
|
|
787
|
+
// a fresh one is built per attempt). Returns { ok: [...] } or { err: Error }.
|
|
788
|
+
function _coerceTransforms(value, errorClass, name) {
|
|
789
|
+
if (value === undefined || value === null) return { ok: [] };
|
|
790
|
+
var list = Array.isArray(value) ? value : [value];
|
|
791
|
+
for (var i = 0; i < list.length; i++) {
|
|
792
|
+
var t = list[i];
|
|
793
|
+
var isFactory = typeof t === "function";
|
|
794
|
+
var isTransform = t && typeof t.pipe === "function" && typeof t.write === "function";
|
|
795
|
+
if (!isFactory && !isTransform) {
|
|
796
|
+
return { err: _makeError(errorClass, "BAD_ARG",
|
|
797
|
+
name + " must be a Transform stream or a () => Transform factory (or an array of them)", true) };
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return { ok: list };
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Resolve a transform entry to a fresh stream instance (call the factory form).
|
|
804
|
+
function _resolveStage(t) { return typeof t === "function" ? t() : t; }
|
|
805
|
+
|
|
806
|
+
// Compose the response (download) stream: source → [throttle?] → [transforms…]
|
|
807
|
+
// → observe(progress + onChunk). Every stage is a Transform so backpressure
|
|
808
|
+
// flows from the consumer back to the socket (the throttle paces it). Returns
|
|
809
|
+
// `source` unchanged when nothing is interposed (preserves the bare-stream
|
|
810
|
+
// contract). A stage error propagates downstream so the returned body emits it.
|
|
811
|
+
function _buildDownloadStream(source, emitDownload, onChunk, throttleBps, transforms) {
|
|
812
|
+
var stages = [];
|
|
813
|
+
if (throttleBps) stages.push(_throttleStream(throttleBps));
|
|
814
|
+
for (var i = 0; i < transforms.length; i++) stages.push(_resolveStage(transforms[i]));
|
|
815
|
+
if (stages.length === 0 && !emitDownload && !onChunk) return source;
|
|
816
|
+
var observe = new nodeStream.Transform({
|
|
817
|
+
transform: function (chunk, _enc, cb) {
|
|
818
|
+
if (emitDownload) emitDownload(chunk.length);
|
|
819
|
+
if (onChunk) { try { onChunk(chunk); } catch (_e) { /* operator hook — drop-silent */ } }
|
|
820
|
+
cb(null, chunk);
|
|
821
|
+
},
|
|
822
|
+
});
|
|
823
|
+
var chain = [source].concat(stages).concat([observe]);
|
|
824
|
+
for (var c = 0; c < chain.length - 1; c++) {
|
|
825
|
+
var src = chain[c], dst = chain[c + 1];
|
|
826
|
+
src.on("error", (function (d) { return function (e) { d.destroy(e); }; })(dst));
|
|
827
|
+
src.pipe(dst);
|
|
828
|
+
}
|
|
829
|
+
return observe;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Build the upload throttle/transform stages (parallel to the download side).
|
|
833
|
+
function _uploadStages(throttleBps, transforms) {
|
|
834
|
+
var stages = [];
|
|
835
|
+
if (throttleBps) stages.push(_throttleStream(throttleBps));
|
|
836
|
+
for (var i = 0; i < transforms.length; i++) stages.push(_resolveStage(transforms[i]));
|
|
837
|
+
return stages;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// Pipe a body (stream | Buffer | string) through throttle/transform stages into
|
|
841
|
+
// the request sink, pacing the upload and emitting progress on bytes delivered
|
|
842
|
+
// to the sink. Used only when a throttle/transform is configured; the plain
|
|
843
|
+
// no-stages path keeps its original direct write. A stage/source error tears
|
|
844
|
+
// down the request via onBodyError.
|
|
845
|
+
function _pipeThrottledUpload(body, sink, stages, emitUpload, onBodyError) {
|
|
846
|
+
var source = (body && typeof body.pipe === "function")
|
|
847
|
+
? body
|
|
848
|
+
: nodeStream.Readable.from(Buffer.isBuffer(body) ? body : Buffer.from(String(body), "utf8"));
|
|
849
|
+
var observe = new nodeStream.Transform({
|
|
850
|
+
transform: function (chunk, _enc, cb) {
|
|
851
|
+
if (emitUpload) emitUpload(chunk.length);
|
|
852
|
+
cb(null, chunk);
|
|
853
|
+
},
|
|
854
|
+
});
|
|
855
|
+
var chain = [source].concat(stages).concat([observe]);
|
|
856
|
+
for (var c = 0; c < chain.length - 1; c++) {
|
|
857
|
+
var s = chain[c], d = chain[c + 1];
|
|
858
|
+
s.on("error", (function (dd) { return function (e) { dd.destroy(e); }; })(d));
|
|
859
|
+
s.pipe(d);
|
|
860
|
+
}
|
|
861
|
+
observe.on("error", onBodyError);
|
|
862
|
+
observe.pipe(sink);
|
|
863
|
+
}
|
|
864
|
+
|
|
736
865
|
function request(opts) {
|
|
737
866
|
if (!opts || !opts.url) {
|
|
738
867
|
return Promise.reject(_makeError(opts && opts.errorClass, "BAD_ARG", "url is required", true));
|
|
@@ -765,6 +894,20 @@ function request(opts) {
|
|
|
765
894
|
return Promise.reject(_makeError(opts.errorClass, "BAD_ARG",
|
|
766
895
|
"onChunk must be a function (chunk: Buffer) -> void", true));
|
|
767
896
|
}
|
|
897
|
+
// Bandwidth cap + transform interpose (download response + upload request
|
|
898
|
+
// body) — validated here, derived per-attempt in _requestSingle. maxBytesPerSec
|
|
899
|
+
// paces BOTH legs; downloadTransform / uploadTransform interpose custom
|
|
900
|
+
// Transform(s) (instance or () => Transform factory) on the respective leg.
|
|
901
|
+
if (opts.maxBytesPerSec !== undefined && opts.maxBytesPerSec !== null) {
|
|
902
|
+
if (typeof opts.maxBytesPerSec !== "number" || !isFinite(opts.maxBytesPerSec) || opts.maxBytesPerSec <= 0) {
|
|
903
|
+
return Promise.reject(_makeError(opts.errorClass, "BAD_ARG",
|
|
904
|
+
"maxBytesPerSec must be a positive finite number (bytes/sec)", true));
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
var _dlChk = _coerceTransforms(opts.downloadTransform, opts.errorClass, "downloadTransform");
|
|
908
|
+
if (_dlChk.err) return Promise.reject(_dlChk.err);
|
|
909
|
+
var _ulChk = _coerceTransforms(opts.uploadTransform, opts.errorClass, "uploadTransform");
|
|
910
|
+
if (_ulChk.err) return Promise.reject(_ulChk.err);
|
|
768
911
|
if (opts.jar !== undefined && opts.jar !== null) {
|
|
769
912
|
if (typeof opts.jar !== "object" ||
|
|
770
913
|
typeof opts.jar.cookieHeaderFor !== "function" ||
|
|
@@ -1379,6 +1522,12 @@ function _requestSingle(opts) {
|
|
|
1379
1522
|
// ---- _requestH1: existing node:http(s) path ----
|
|
1380
1523
|
|
|
1381
1524
|
function _requestH1(transport, u, opts) {
|
|
1525
|
+
// Bandwidth/transform interpose — opts validated in request(); derived fresh
|
|
1526
|
+
// per attempt (each builds its own throttle + resolves transform factories, so
|
|
1527
|
+
// a retry / redirect never reuses a consumed Transform).
|
|
1528
|
+
var throttleBps = opts.maxBytesPerSec || null; // validated in request(); positive number or absent
|
|
1529
|
+
var downloadTransforms = _coerceTransforms(opts.downloadTransform, opts.errorClass, "downloadTransform").ok;
|
|
1530
|
+
var uploadTransforms = _coerceTransforms(opts.uploadTransform, opts.errorClass, "uploadTransform").ok;
|
|
1382
1531
|
return new Promise(function (resolve, reject) {
|
|
1383
1532
|
var method = (opts.method || "GET").toUpperCase();
|
|
1384
1533
|
var headers = Object.assign({}, opts.headers || {});
|
|
@@ -1397,7 +1546,12 @@ function _requestH1(transport, u, opts) {
|
|
|
1397
1546
|
return;
|
|
1398
1547
|
}
|
|
1399
1548
|
|
|
1400
|
-
if (Buffer.isBuffer(opts.body)) {
|
|
1549
|
+
if (Buffer.isBuffer(opts.body) && uploadTransforms.length === 0) {
|
|
1550
|
+
// A size-changing uploadTransform (gzip / encrypt / frame) makes the
|
|
1551
|
+
// original buffer length wrong, so the server would truncate extra bytes
|
|
1552
|
+
// or wait for bytes that never arrive. Omit Content-Length in that case
|
|
1553
|
+
// and let the body be chunked, framed on the actual transformed bytes. A
|
|
1554
|
+
// throttle alone preserves size, so Content-Length stays valid then.
|
|
1401
1555
|
headers["Content-Length"] = opts.body.length;
|
|
1402
1556
|
}
|
|
1403
1557
|
// CVE-2026-22036 mitigation — refuse compressed responses by
|
|
@@ -1465,35 +1619,30 @@ function _requestH1(transport, u, opts) {
|
|
|
1465
1619
|
_rejectStreamHttpError(res, opts.errorClass, res.statusCode, res.statusMessage || "", _reject);
|
|
1466
1620
|
return;
|
|
1467
1621
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
// surfaces the error through their own pipe handler.
|
|
1477
|
-
var passthrough = new nodeStream.PassThrough();
|
|
1478
|
-
res.on("data", function (chunk) {
|
|
1479
|
-
_emitDownload(chunk.length);
|
|
1480
|
-
if (onChunk) {
|
|
1481
|
-
try { onChunk(chunk); }
|
|
1482
|
-
catch (_e) { /* operator-supplied hook — drop-silent */ }
|
|
1483
|
-
}
|
|
1484
|
-
passthrough.write(chunk);
|
|
1485
|
-
});
|
|
1486
|
-
res.on("end", function () { passthrough.end(); });
|
|
1487
|
-
res.on("error", function (e) { passthrough.destroy(e); });
|
|
1488
|
-
return _resolve({ statusCode: res.statusCode, headers: res.headers, body: passthrough });
|
|
1489
|
-
}
|
|
1490
|
-
return _resolve({ statusCode: res.statusCode, headers: res.headers, body: res });
|
|
1622
|
+
// Compose the response stream with the optional bandwidth throttle +
|
|
1623
|
+
// custom transforms + progress/onChunk observation. Each is a Transform
|
|
1624
|
+
// so backpressure reaches the socket; onChunk sees the bytes in order
|
|
1625
|
+
// (for hash-as-you-go) and a throw from it is dropped. Returns `res`
|
|
1626
|
+
// unchanged when nothing is interposed (bare-stream contract).
|
|
1627
|
+
var body = _buildDownloadStream(
|
|
1628
|
+
res, onDownloadProgress ? _emitDownload : null, onChunk, throttleBps, downloadTransforms);
|
|
1629
|
+
return _resolve({ statusCode: res.statusCode, headers: res.headers, body: body });
|
|
1491
1630
|
}
|
|
1492
1631
|
|
|
1493
1632
|
var collector = safeBuffer.boundedChunkCollector({ maxBytes: maxResponseBytes });
|
|
1494
1633
|
var capExceeded = false;
|
|
1495
1634
|
|
|
1496
|
-
|
|
1635
|
+
// Route the buffered read through the SAME throttle + transform pipeline
|
|
1636
|
+
// as stream mode, so maxBytesPerSec and downloadTransform apply in buffer
|
|
1637
|
+
// and always-resolve modes too (both documented to pace / transform the
|
|
1638
|
+
// download regardless of how the body is consumed). With nothing
|
|
1639
|
+
// interposed this returns `res` unchanged, so the plain path is identical.
|
|
1640
|
+
// The cap now bounds post-transform bytes — strictly safer for a
|
|
1641
|
+
// decompressing transform. Progress + onChunk fire inside the pipeline.
|
|
1642
|
+
var dlSource = _buildDownloadStream(
|
|
1643
|
+
res, onDownloadProgress ? _emitDownload : null, onChunk, throttleBps, downloadTransforms);
|
|
1644
|
+
|
|
1645
|
+
dlSource.on("data", function (chunk) {
|
|
1497
1646
|
if (capExceeded) return;
|
|
1498
1647
|
try { collector.push(chunk); }
|
|
1499
1648
|
catch (_e) {
|
|
@@ -1503,13 +1652,8 @@ function _requestH1(transport, u, opts) {
|
|
|
1503
1652
|
"response body exceeds " + maxResponseBytes + " bytes", true));
|
|
1504
1653
|
return;
|
|
1505
1654
|
}
|
|
1506
|
-
_emitDownload(chunk.length);
|
|
1507
|
-
if (onChunk) {
|
|
1508
|
-
try { onChunk(chunk); }
|
|
1509
|
-
catch (_e) { /* operator-supplied hook — drop-silent */ }
|
|
1510
|
-
}
|
|
1511
1655
|
});
|
|
1512
|
-
|
|
1656
|
+
dlSource.on("end", function () {
|
|
1513
1657
|
if (capExceeded) return;
|
|
1514
1658
|
var buf = collector.result();
|
|
1515
1659
|
if (observer) observer("response:end", {
|
|
@@ -1539,7 +1683,7 @@ function _requestH1(transport, u, opts) {
|
|
|
1539
1683
|
_isPermanentStatus(res.statusCode), res.statusCode));
|
|
1540
1684
|
}
|
|
1541
1685
|
});
|
|
1542
|
-
|
|
1686
|
+
dlSource.on("error", function (e) {
|
|
1543
1687
|
if (capExceeded) return;
|
|
1544
1688
|
if (observer) observer("error", { phase: "response", message: e.message });
|
|
1545
1689
|
_reject(_makeError(opts.errorClass, e.code || "RES_ERROR", e.message, false));
|
|
@@ -1583,7 +1727,17 @@ function _requestH1(transport, u, opts) {
|
|
|
1583
1727
|
catch (_e) { /* progress hooks are best-effort */ }
|
|
1584
1728
|
}
|
|
1585
1729
|
|
|
1586
|
-
|
|
1730
|
+
var ulStages = _uploadStages(throttleBps, uploadTransforms);
|
|
1731
|
+
if (opts.body != null && opts.body !== "" && ulStages.length > 0) {
|
|
1732
|
+
// Pace / transform the upload body through the stages, into req.
|
|
1733
|
+
_pipeThrottledUpload(opts.body, req, ulStages,
|
|
1734
|
+
onUploadProgress ? _emitUpload : null,
|
|
1735
|
+
function (e) {
|
|
1736
|
+
try { req.destroy(); } catch (_) { /* best-effort req teardown */ }
|
|
1737
|
+
_reject(_makeError(opts.errorClass, "REQ_BODY_ERROR",
|
|
1738
|
+
"request body stream error: " + e.message, false));
|
|
1739
|
+
});
|
|
1740
|
+
} else if (opts.body && typeof opts.body.pipe === "function") {
|
|
1587
1741
|
if (onUploadProgress) {
|
|
1588
1742
|
opts.body.on("data", function (c) { _emitUpload(c.length); });
|
|
1589
1743
|
}
|
|
@@ -1618,6 +1772,10 @@ function _requestH1(transport, u, opts) {
|
|
|
1618
1772
|
// ---- _requestH2: node:http2 path ----
|
|
1619
1773
|
|
|
1620
1774
|
function _requestH2(transport, u, opts) {
|
|
1775
|
+
// Bandwidth/transform interpose — see _requestH1; derived fresh per attempt.
|
|
1776
|
+
var throttleBps = opts.maxBytesPerSec || null; // validated in request(); positive number or absent
|
|
1777
|
+
var downloadTransforms = _coerceTransforms(opts.downloadTransform, opts.errorClass, "downloadTransform").ok;
|
|
1778
|
+
var uploadTransforms = _coerceTransforms(opts.uploadTransform, opts.errorClass, "uploadTransform").ok;
|
|
1621
1779
|
return new Promise(function (resolve, reject) {
|
|
1622
1780
|
var method = (opts.method || "GET").toUpperCase();
|
|
1623
1781
|
var responseMode = opts.responseMode || "buffer";
|
|
@@ -1637,7 +1795,13 @@ function _requestH2(transport, u, opts) {
|
|
|
1637
1795
|
}
|
|
1638
1796
|
|
|
1639
1797
|
var headers = _toH2Headers(method, u, opts.headers || {});
|
|
1640
|
-
|
|
1798
|
+
// Omit content-length when a size-changing uploadTransform is interposed —
|
|
1799
|
+
// the original buffer length no longer frames the transformed body (HTTP/2
|
|
1800
|
+
// frames via DATA + END_STREAM, so no header is required). A throttle alone
|
|
1801
|
+
// keeps the size, so the length stays valid then.
|
|
1802
|
+
if (Buffer.isBuffer(opts.body) && uploadTransforms.length === 0) {
|
|
1803
|
+
headers["content-length"] = String(opts.body.length);
|
|
1804
|
+
}
|
|
1641
1805
|
|
|
1642
1806
|
if (observer) observer("request:start", { method: method, url: String(opts.url), protocol: "h2" });
|
|
1643
1807
|
|
|
@@ -1681,24 +1845,29 @@ function _requestH2(transport, u, opts) {
|
|
|
1681
1845
|
_rejectStreamHttpError(stream, opts.errorClass, statusCode, "", _reject);
|
|
1682
1846
|
return;
|
|
1683
1847
|
}
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
stream.on("data", function (chunk) {
|
|
1687
|
-
try { onChunkH2(chunk); }
|
|
1688
|
-
catch (_e) { /* operator-supplied hook — drop-silent */ }
|
|
1689
|
-
passthroughH2.write(chunk);
|
|
1690
|
-
});
|
|
1691
|
-
stream.on("end", function () { passthroughH2.end(); });
|
|
1692
|
-
stream.on("error", function (e) { passthroughH2.destroy(e); });
|
|
1693
|
-
return _resolve({ statusCode: statusCode, headers: responseHeaders, body: passthroughH2 });
|
|
1694
|
-
}
|
|
1695
|
-
return _resolve({ statusCode: statusCode, headers: responseHeaders, body: stream });
|
|
1848
|
+
var bodyH2 = _buildDownloadStream(stream, null, onChunkH2, throttleBps, downloadTransforms);
|
|
1849
|
+
return _resolve({ statusCode: statusCode, headers: responseHeaders, body: bodyH2 });
|
|
1696
1850
|
}
|
|
1697
1851
|
|
|
1698
1852
|
var collector = safeBuffer.boundedChunkCollector({ maxBytes: maxResponseBytes });
|
|
1699
1853
|
var capExceeded = false;
|
|
1700
1854
|
|
|
1701
|
-
|
|
1855
|
+
// Apply the throttle + transform pipeline in buffer / always-resolve mode
|
|
1856
|
+
// too (matches H1 + the documented contract); returns `stream` unchanged
|
|
1857
|
+
// when nothing is interposed. onChunk fires inside the pipeline.
|
|
1858
|
+
var dlH2 = _buildDownloadStream(stream, null, onChunkH2, throttleBps, downloadTransforms);
|
|
1859
|
+
// When a stage is interposed, a transform error surfaces on the pipeline
|
|
1860
|
+
// tail, not the raw h2 stream — reject on it. The plain path (dlH2 ===
|
|
1861
|
+
// stream) is already covered by the stream-level error handler below.
|
|
1862
|
+
if (dlH2 !== stream) {
|
|
1863
|
+
dlH2.on("error", function (e) {
|
|
1864
|
+
if (capExceeded) return;
|
|
1865
|
+
if (observer) observer("error", { phase: "stream", message: e.message });
|
|
1866
|
+
_reject(_makeError(opts.errorClass, e.code || "H2_STREAM_ERROR", e.message, false));
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
dlH2.on("data", function (chunk) {
|
|
1702
1871
|
if (capExceeded) return;
|
|
1703
1872
|
try { collector.push(chunk); }
|
|
1704
1873
|
catch (_e) {
|
|
@@ -1708,12 +1877,8 @@ function _requestH2(transport, u, opts) {
|
|
|
1708
1877
|
"response body exceeds " + maxResponseBytes + " bytes", true));
|
|
1709
1878
|
return;
|
|
1710
1879
|
}
|
|
1711
|
-
if (onChunkH2) {
|
|
1712
|
-
try { onChunkH2(chunk); }
|
|
1713
|
-
catch (_e) { /* operator-supplied hook — drop-silent */ }
|
|
1714
|
-
}
|
|
1715
1880
|
});
|
|
1716
|
-
|
|
1881
|
+
dlH2.on("end", function () {
|
|
1717
1882
|
if (capExceeded) return;
|
|
1718
1883
|
var buf = collector.result();
|
|
1719
1884
|
if (observer) observer("response:end", {
|
|
@@ -1751,7 +1916,14 @@ function _requestH2(transport, u, opts) {
|
|
|
1751
1916
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
1752
1917
|
}
|
|
1753
1918
|
|
|
1754
|
-
|
|
1919
|
+
var ulStagesH2 = _uploadStages(throttleBps, uploadTransforms);
|
|
1920
|
+
if (opts.body != null && opts.body !== "" && ulStagesH2.length > 0) {
|
|
1921
|
+
_pipeThrottledUpload(opts.body, stream, ulStagesH2, null, function (e) {
|
|
1922
|
+
try { stream.close(http2.constants.NGHTTP2_INTERNAL_ERROR); } catch (_) { /* best-effort h2 stream cancel */ }
|
|
1923
|
+
_reject(_makeError(opts.errorClass, "REQ_BODY_ERROR",
|
|
1924
|
+
"request body stream error: " + e.message, false));
|
|
1925
|
+
});
|
|
1926
|
+
} else if (opts.body && typeof opts.body.pipe === "function") {
|
|
1755
1927
|
opts.body.on("error", function (e) {
|
|
1756
1928
|
try { stream.close(http2.constants.NGHTTP2_INTERNAL_ERROR); } catch (_) { /* best-effort h2 stream cancel */ }
|
|
1757
1929
|
_reject(_makeError(opts.errorClass, "REQ_BODY_ERROR",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
|
|
97
97
|
var audit = require("./audit");
|
|
98
98
|
var bCrypto = require("./crypto");
|
|
99
|
+
var numericBounds = require("./numeric-bounds");
|
|
99
100
|
var { defineClass } = require("./framework-error");
|
|
100
101
|
var IabTcfError = defineClass("IabTcfError", { alwaysPermanent: true });
|
|
101
102
|
|
|
@@ -521,7 +522,7 @@ function _idArray(x) {
|
|
|
521
522
|
var seen = Object.create(null);
|
|
522
523
|
var out = [];
|
|
523
524
|
list.forEach(function (id) {
|
|
524
|
-
if (
|
|
525
|
+
if (!numericBounds.isPositiveFiniteInt(id)) {
|
|
525
526
|
throw IabTcfError.factory("iab-tcf/bad-value", "iabTcf.encode: vendor/purpose ids must be positive integers, got " + id);
|
|
526
527
|
}
|
|
527
528
|
if (!seen[id]) { seen[id] = 1; out.push(id); }
|
|
@@ -554,7 +555,7 @@ function _decisec(t) {
|
|
|
554
555
|
function _bitWriter() {
|
|
555
556
|
var bits = "";
|
|
556
557
|
function writeInt(v, n) {
|
|
557
|
-
if (
|
|
558
|
+
if (!numericBounds.isNonNegativeFiniteInt(v)) throw IabTcfError.factory("iab-tcf/bad-value", "iabTcf.encode: expected a non-negative integer, got " + v);
|
|
558
559
|
if (v >= Math.pow(2, n)) throw IabTcfError.factory("iab-tcf/value-overflow", "iabTcf.encode: " + v + " does not fit in " + n + " bits");
|
|
559
560
|
bits += v.toString(2).padStart(n, "0");
|
|
560
561
|
}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
var validateOpts = require("./validate-opts");
|
|
24
24
|
var bCrypto = require("./crypto");
|
|
25
|
+
var safeJson = require("./safe-json");
|
|
25
26
|
var { defineClass } = require("./framework-error");
|
|
26
27
|
|
|
27
28
|
var ImportmapError = defineClass("ImportmapError", { alwaysPermanent: true });
|
|
@@ -46,7 +47,9 @@ var ImportmapError = defineClass("ImportmapError", { alwaysPermanent: true });
|
|
|
46
47
|
* "@org/lib": { url: "/static/lib.js", body: fileBytes },
|
|
47
48
|
* },
|
|
48
49
|
* });
|
|
49
|
-
*
|
|
50
|
+
* // Embed with the <script>-safe helper — NEVER raw JSON.stringify, which
|
|
51
|
+
* // does not escape "</script>" in a module url and breaks out of the tag.
|
|
52
|
+
* res.end(b.importmapIntegrity.scriptTag(im));
|
|
50
53
|
*/
|
|
51
54
|
function build(opts) {
|
|
52
55
|
opts = validateOpts.requireObject(opts, "importmapIntegrity.build",
|
|
@@ -84,7 +87,44 @@ function build(opts) {
|
|
|
84
87
|
return { imports: imports, integrity: integrity };
|
|
85
88
|
}
|
|
86
89
|
|
|
90
|
+
/**
|
|
91
|
+
* @primitive b.importmapIntegrity.scriptTag
|
|
92
|
+
* @signature b.importmapIntegrity.scriptTag(importmap, opts?)
|
|
93
|
+
* @since 0.15.14
|
|
94
|
+
* @status stable
|
|
95
|
+
* @related b.importmapIntegrity.build, b.safeJson.stringifyForScript
|
|
96
|
+
*
|
|
97
|
+
* Render an import-map object (from `build`) as a ready-to-embed
|
|
98
|
+
* `<script type="importmap">…</script>` tag using the `<script>`-safe
|
|
99
|
+
* JSON serializer. Raw `JSON.stringify` does not escape `</script>` in a
|
|
100
|
+
* module url, so concatenating it into the page lets a `</script>` in a
|
|
101
|
+
* url close the element and inject markup — this escapes `< > &` (and the
|
|
102
|
+
* U+2028 / U+2029 separators) so no url can break out.
|
|
103
|
+
*
|
|
104
|
+
* @opts
|
|
105
|
+
* nonce: string, // CSP nonce added as nonce="…" on the <script>
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* res.end(b.importmapIntegrity.scriptTag(im, { nonce: req.cspNonce }));
|
|
109
|
+
*/
|
|
110
|
+
function scriptTag(importmap, opts) {
|
|
111
|
+
opts = opts || {};
|
|
112
|
+
var nonceAttr = "";
|
|
113
|
+
if (typeof opts.nonce === "string" && opts.nonce.length > 0) {
|
|
114
|
+
// The nonce is operator-supplied (a CSP per-request token); reject any
|
|
115
|
+
// value that could itself break the attribute rather than escape it.
|
|
116
|
+
if (/[^A-Za-z0-9+/=_-]/.test(opts.nonce)) {
|
|
117
|
+
throw new ImportmapError("importmap/bad-nonce",
|
|
118
|
+
"scriptTag: opts.nonce must be a base64/token string");
|
|
119
|
+
}
|
|
120
|
+
nonceAttr = ' nonce="' + opts.nonce + '"';
|
|
121
|
+
}
|
|
122
|
+
return '<script type="importmap"' + nonceAttr + '>' +
|
|
123
|
+
safeJson.stringifyForScript(importmap) + "</script>";
|
|
124
|
+
}
|
|
125
|
+
|
|
87
126
|
module.exports = {
|
|
88
127
|
build: build,
|
|
128
|
+
scriptTag: scriptTag,
|
|
89
129
|
ImportmapError: ImportmapError,
|
|
90
130
|
};
|
|
@@ -93,12 +93,15 @@ var REGIME_DEADLINES = Object.freeze({
|
|
|
93
93
|
intermediate: C.TIME.hours(72),
|
|
94
94
|
final: C.TIME.days(30),
|
|
95
95
|
}),
|
|
96
|
-
// DORA (EU Digital Operational Resilience Act)
|
|
97
|
-
// within 4h of
|
|
98
|
-
// within
|
|
96
|
+
// DORA (EU Digital Operational Resilience Act) Art. 19 + RTS (EU)
|
|
97
|
+
// 2024/1772 Art. 5: initial within 4h of classifying the incident as
|
|
98
|
+
// major (outer bound 24h from awareness), intermediate within 72h of the
|
|
99
|
+
// initial notification, final within 1 month of the intermediate report.
|
|
100
|
+
// (intermediate was 24h here, contradicting lib/dora.js's 72h — the RTS
|
|
101
|
+
// value is 72h from the initial notification; aligned.)
|
|
99
102
|
dora: Object.freeze({
|
|
100
103
|
initial: C.TIME.hours(4),
|
|
101
|
-
intermediate: C.TIME.hours(
|
|
104
|
+
intermediate: C.TIME.hours(72),
|
|
102
105
|
final: C.TIME.days(30),
|
|
103
106
|
}),
|
|
104
107
|
// CRA (EU Cyber Resilience Act) Article 14: early warning within
|
|
@@ -206,7 +209,7 @@ function create(opts) {
|
|
|
206
209
|
}
|
|
207
210
|
|
|
208
211
|
async function _recordStage(incidentId, stage, payload) {
|
|
209
|
-
if (!VALID_STAGES
|
|
212
|
+
if (!Object.prototype.hasOwnProperty.call(VALID_STAGES, stage)) {
|
|
210
213
|
throw new IncidentReportError("incident-report/bad-stage",
|
|
211
214
|
"incident.report._recordStage: stage must be one of " + Object.keys(VALID_STAGES).join(", "));
|
|
212
215
|
}
|
|
@@ -358,7 +361,7 @@ function createDeadlineClock(opts) {
|
|
|
358
361
|
function untrack(id) { return tracked.delete(id); }
|
|
359
362
|
|
|
360
363
|
function acknowledgeSubmission(id, stage, info) {
|
|
361
|
-
if (!VALID_STAGES
|
|
364
|
+
if (!Object.prototype.hasOwnProperty.call(VALID_STAGES, stage)) {
|
|
362
365
|
throw new IncidentReportError("incident-report/bad-stage",
|
|
363
366
|
"createDeadlineClock.acknowledgeSubmission: stage must be one of " + Object.keys(VALID_STAGES).join(", "));
|
|
364
367
|
}
|
|
@@ -157,7 +157,7 @@ function apply(doc, operations) {
|
|
|
157
157
|
var work = structuredClone(doc);
|
|
158
158
|
for (var i = 0; i < operations.length; i += 1) {
|
|
159
159
|
var op = operations[i];
|
|
160
|
-
if (!op || typeof op !== "object" || typeof op.op !== "string" || !OPS
|
|
160
|
+
if (!op || typeof op !== "object" || typeof op.op !== "string" || !Object.prototype.hasOwnProperty.call(OPS, op.op)) {
|
|
161
161
|
throw new JsonPatchError("json-patch/bad-op", "jsonPatch.apply: operations[" + i + "] has an invalid 'op'");
|
|
162
162
|
}
|
|
163
163
|
if (typeof op.path !== "string") throw new JsonPatchError("json-patch/bad-op", "jsonPatch.apply: operations[" + i + "] is missing 'path'");
|
|
@@ -35,6 +35,7 @@ var { defineClass } = require("./framework-error");
|
|
|
35
35
|
var JsonPathError = defineClass("JsonPathError", { alwaysPermanent: true });
|
|
36
36
|
|
|
37
37
|
var MAX_DESCEND_NODES = 1000000; // DoS ceiling on nodes visited by a descendant walk
|
|
38
|
+
var MAX_TOTAL_NODES = 1000000; // DoS ceiling on the running nodelist across ALL segments (chained wildcard/slice/filter cross-product)
|
|
38
39
|
|
|
39
40
|
// ---------------------------------------------------------------------------
|
|
40
41
|
// Parser — recursive descent over the RFC 9535 ABNF.
|
|
@@ -46,7 +47,20 @@ function _isDigit(c) { return c >= "0" && c <= "9"; }
|
|
|
46
47
|
function _isNameFirst(c) { var cc = c.charCodeAt(0); return (c >= "A" && c <= "Z") || (c >= "a" && c <= "z") || c === "_" || cc >= 0x80; }
|
|
47
48
|
function _isNameChar(c) { return _isNameFirst(c) || _isDigit(c); }
|
|
48
49
|
|
|
49
|
-
function _Parser(s) { this.s = s; this.i = 0; }
|
|
50
|
+
function _Parser(s) { this.s = s; this.i = 0; this._depth = 0; }
|
|
51
|
+
|
|
52
|
+
// Nesting-depth cap for the filter-expression recursion (parens + `!`). Without
|
|
53
|
+
// it, a deeply-nested filter like `?(((((...)))))` recurses until V8 throws a
|
|
54
|
+
// raw RangeError ("Maximum call stack size exceeded") that escapes JsonPathError
|
|
55
|
+
// handling — a DoS / unhandled-crash lever on attacker-supplied JSONPath.
|
|
56
|
+
var MAX_FILTER_DEPTH = 200;
|
|
57
|
+
_Parser.prototype._descend = function () {
|
|
58
|
+
if (++this._depth > MAX_FILTER_DEPTH) {
|
|
59
|
+
throw new JsonPathError("json-path/filter-too-deep",
|
|
60
|
+
"jsonPath: filter expression nesting exceeds " + MAX_FILTER_DEPTH);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
_Parser.prototype._ascend = function () { this._depth -= 1; };
|
|
50
64
|
_Parser.prototype.err = function (msg) { throw new JsonPathError("json-path/invalid", "jsonPath: " + msg + " at index " + this.i); };
|
|
51
65
|
_Parser.prototype.peek = function () { return this.i < this.s.length ? this.s.charAt(this.i) : ""; };
|
|
52
66
|
_Parser.prototype.eat = function (c) { if (this.peek() !== c) this.err("expected '" + c + "'"); this.i += 1; };
|
|
@@ -226,9 +240,9 @@ _Parser.prototype.parseLogicalAnd = function () {
|
|
|
226
240
|
};
|
|
227
241
|
_Parser.prototype.parseBasic = function () {
|
|
228
242
|
this.skipBlank();
|
|
229
|
-
if (this.peek() === "!") { this.i += 1; this.skipBlank(); var inner = this.parseBasic(); this._requireTestable(inner); return { type: "not", e: inner, vtype: "logical" }; }
|
|
243
|
+
if (this.peek() === "!") { this.i += 1; this.skipBlank(); this._descend(); var inner = this.parseBasic(); this._ascend(); this._requireTestable(inner); return { type: "not", e: inner, vtype: "logical" }; }
|
|
230
244
|
if (this.peek() === "(") {
|
|
231
|
-
this.i += 1; this.skipBlank(); var e = this.parseLogicalOr(); this.skipBlank(); this.eat(")");
|
|
245
|
+
this.i += 1; this.skipBlank(); this._descend(); var e = this.parseLogicalOr(); this._ascend(); this.skipBlank(); this.eat(")");
|
|
232
246
|
return e;
|
|
233
247
|
}
|
|
234
248
|
// comparison or test
|
|
@@ -436,6 +450,13 @@ function _evalSegments(segments, root) {
|
|
|
436
450
|
base = acc;
|
|
437
451
|
}
|
|
438
452
|
base.forEach(function (nd) { seg.selectors.forEach(function (sel) { _applySelector(sel, nd, root, next); }); });
|
|
453
|
+
// Cap the running nodelist across the WHOLE query, not just per descendant
|
|
454
|
+
// walk: chained wildcard/slice/filter selectors multiply the nodelist each
|
|
455
|
+
// segment ([*][*][*]…), an OOM lever the per-`_descend` budget never sees.
|
|
456
|
+
if (next.length > MAX_TOTAL_NODES) {
|
|
457
|
+
throw new JsonPathError("json-path/too-large",
|
|
458
|
+
"jsonPath: nodelist exceeded " + MAX_TOTAL_NODES + " nodes (chained selector cross-product)");
|
|
459
|
+
}
|
|
439
460
|
nodes = next;
|
|
440
461
|
}
|
|
441
462
|
return nodes;
|
|
@@ -58,7 +58,7 @@ function _checkSchema(schema, root, isRoot) {
|
|
|
58
58
|
if (!_isPlainObject(schema)) throw new JtdError("jtd/bad-schema", "jtd: schema must be an object");
|
|
59
59
|
if (!isRoot && Object.prototype.hasOwnProperty.call(schema, "definitions")) throw new JtdError("jtd/bad-schema", "jtd: 'definitions' is allowed only at the root");
|
|
60
60
|
Object.keys(schema).forEach(function (k) {
|
|
61
|
-
if (FORM_KEYWORDS.indexOf(k) === -1 && !SHARED_KEYWORDS
|
|
61
|
+
if (FORM_KEYWORDS.indexOf(k) === -1 && !Object.prototype.hasOwnProperty.call(SHARED_KEYWORDS, k) && k !== "additionalProperties" && k !== "mapping") throw new JtdError("jtd/bad-schema", "jtd: unknown keyword '" + k + "'");
|
|
62
62
|
});
|
|
63
63
|
if (Object.prototype.hasOwnProperty.call(schema, "nullable") && typeof schema.nullable !== "boolean") throw new JtdError("jtd/bad-schema", "jtd: 'nullable' must be a boolean");
|
|
64
64
|
if (Object.prototype.hasOwnProperty.call(schema, "metadata") && !_isPlainObject(schema.metadata)) throw new JtdError("jtd/bad-schema", "jtd: 'metadata' must be an object");
|
|
@@ -75,7 +75,7 @@ function _checkSchema(schema, root, isRoot) {
|
|
|
75
75
|
if ("ref" in schema) {
|
|
76
76
|
if (typeof schema.ref !== "string" || !root.definitions || !Object.prototype.hasOwnProperty.call(root.definitions, schema.ref)) throw new JtdError("jtd/bad-schema", "jtd: 'ref' must name a key in the root definitions");
|
|
77
77
|
}
|
|
78
|
-
if ("type" in schema && !TYPES
|
|
78
|
+
if ("type" in schema && !Object.prototype.hasOwnProperty.call(TYPES, schema.type)) throw new JtdError("jtd/bad-schema", "jtd: unknown type '" + schema.type + "'");
|
|
79
79
|
if ("enum" in schema) {
|
|
80
80
|
if (!Array.isArray(schema.enum) || schema.enum.length === 0) throw new JtdError("jtd/bad-schema", "jtd: 'enum' must be a non-empty array");
|
|
81
81
|
var seen = Object.create(null);
|
|
@@ -210,19 +210,34 @@ function create(opts) {
|
|
|
210
210
|
_ensureSchema();
|
|
211
211
|
var hash = _hashSubject(sid);
|
|
212
212
|
var placeSelBuilt = sql.select(HOLD_TABLE, SQL_OPTS)
|
|
213
|
-
.columns(["placedAt"])
|
|
213
|
+
.columns(["placedAt", "retainUntil"])
|
|
214
214
|
.where("subjectIdHash", hash)
|
|
215
215
|
.toSql();
|
|
216
216
|
var placeSelStmt = db.prepare(placeSelBuilt.sql);
|
|
217
217
|
var existing = placeSelStmt.get.apply(placeSelStmt, placeSelBuilt.params);
|
|
218
|
+
var nowMs = Date.now();
|
|
219
|
+
var renewedFromLapsed = false;
|
|
218
220
|
if (existing) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
// A LAPSED hold (retainUntil sunset already passed → isHeld() is already
|
|
222
|
+
// false) must not block a fresh placement: otherwise a subject whose hold
|
|
223
|
+
// expired cannot be re-held when new litigation arises, leaving the data
|
|
224
|
+
// both unprotected (isHeld false) and erasable by retention. Replace the
|
|
225
|
+
// lapsed row with the new hold. An ACTIVE hold still rejects as before.
|
|
226
|
+
var existingLapsed = existing.retainUntil && existing.retainUntil < nowMs;
|
|
227
|
+
if (!existingLapsed) {
|
|
228
|
+
_emit("legalhold.place_rejected",
|
|
229
|
+
{ subjectId: sid, reason: "already-held",
|
|
230
|
+
existingSince: existing.placedAt },
|
|
231
|
+
"denied");
|
|
232
|
+
return { error: "already-held", placedAt: existing.placedAt };
|
|
233
|
+
}
|
|
234
|
+
renewedFromLapsed = true;
|
|
235
|
+
var lapseDelBuilt = sql.delete(HOLD_TABLE, SQL_OPTS)
|
|
236
|
+
.where("subjectIdHash", hash)
|
|
237
|
+
.toSql();
|
|
238
|
+
var lapseDelStmt = db.prepare(lapseDelBuilt.sql);
|
|
239
|
+
lapseDelStmt.run.apply(lapseDelStmt, lapseDelBuilt.params);
|
|
224
240
|
}
|
|
225
|
-
var nowMs = Date.now();
|
|
226
241
|
var placeInsBuilt = sql.insert(HOLD_TABLE, SQL_OPTS)
|
|
227
242
|
.values(cryptoField.sealRow(HOLD_TABLE, {
|
|
228
243
|
subjectIdHash: hash,
|
|
@@ -242,9 +257,10 @@ function create(opts) {
|
|
|
242
257
|
citation: args.citation || null,
|
|
243
258
|
retainUntil: args.retainUntil || null,
|
|
244
259
|
placedBy: args.placedBy || null,
|
|
260
|
+
renewedFromLapsed: renewedFromLapsed,
|
|
245
261
|
knownCitation: args.citation && KNOWN_CITATIONS.indexOf(args.citation) !== -1 },
|
|
246
262
|
"success");
|
|
247
|
-
return { placed: true, placedAt: nowMs };
|
|
263
|
+
return { placed: true, placedAt: nowMs, renewedFromLapsed: renewedFromLapsed };
|
|
248
264
|
}
|
|
249
265
|
|
|
250
266
|
function release(subjectId, args) {
|