@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
|
@@ -354,6 +354,49 @@ function stringify(value, opts) {
|
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
+
/**
|
|
358
|
+
* @primitive b.safeJson.stringifyForScript
|
|
359
|
+
* @signature b.safeJson.stringifyForScript(value, opts?)
|
|
360
|
+
* @since 0.15.14
|
|
361
|
+
* @status stable
|
|
362
|
+
* @related b.safeJson.stringify
|
|
363
|
+
*
|
|
364
|
+
* Like `b.safeJson.stringify` but safe to embed verbatim inside an
|
|
365
|
+
* inline `<script>` element. Raw `JSON.stringify` does not escape `<`,
|
|
366
|
+
* `>`, or `&`, so a string value containing `</script>` (or `<!--`)
|
|
367
|
+
* closes the surrounding script element and injects markup; the
|
|
368
|
+
* Unicode line/paragraph separators U+2028 / U+2029 are also illegal
|
|
369
|
+
* unescaped in a script context on older parsers. This escapes all of
|
|
370
|
+
* them to their equivalent `\uXXXX` JSON escapes — the parsed value is
|
|
371
|
+
* byte-identical, but no substring can break out of a `<script>` block.
|
|
372
|
+
*
|
|
373
|
+
* @opts
|
|
374
|
+
* indent: number | string, // forwarded to b.safeJson.stringify
|
|
375
|
+
* allowProto:boolean, // forwarded
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* var json = b.safeJson.stringifyForScript({ url: "/a</script>x" });
|
|
379
|
+
* res.end('<script type="importmap">' + json + '</script>');
|
|
380
|
+
* // → the "</script>" inside the value is emitted as "</script>"
|
|
381
|
+
*/
|
|
382
|
+
function stringifyForScript(value, opts) {
|
|
383
|
+
var json = stringify(value, opts);
|
|
384
|
+
// BS is a single backslash built at runtime so this source carries no
|
|
385
|
+
// escape literals (they round-trip badly through tooling). Escape < > &
|
|
386
|
+
// so the JSON cannot close / comment-open the surrounding inline
|
|
387
|
+
// <script>; escape U+2028 / U+2029 (illegal unescaped in a script on
|
|
388
|
+
// older parsers). The parsed value is unchanged.
|
|
389
|
+
var BS = String.fromCharCode(92);
|
|
390
|
+
json = json.replace(/[<>&]/g, function (c) {
|
|
391
|
+
if (c === "<") return BS + "u003c";
|
|
392
|
+
if (c === ">") return BS + "u003e";
|
|
393
|
+
return BS + "u0026";
|
|
394
|
+
});
|
|
395
|
+
json = json.split(String.fromCharCode(0x2028)).join(BS + "u2028");
|
|
396
|
+
json = json.split(String.fromCharCode(0x2029)).join(BS + "u2029");
|
|
397
|
+
return json;
|
|
398
|
+
}
|
|
399
|
+
|
|
357
400
|
// Walk the value, substituting any references that would create a cycle
|
|
358
401
|
// with `replacement`. Uses an active-stack Set so SHARED non-circular
|
|
359
402
|
// subtrees are preserved (only true cycles are replaced).
|
|
@@ -930,6 +973,7 @@ module.exports = {
|
|
|
930
973
|
parse: parse,
|
|
931
974
|
parseOrDefault: parseOrDefault,
|
|
932
975
|
stringify: stringify,
|
|
976
|
+
stringifyForScript: stringifyForScript,
|
|
933
977
|
canonical: canonical,
|
|
934
978
|
validate: validate,
|
|
935
979
|
registerFormat: registerFormat,
|
|
@@ -133,7 +133,7 @@ function _resolveProfile(opts) {
|
|
|
133
133
|
if (!opts) return "strict";
|
|
134
134
|
if (typeof opts.profile === "string") return opts.profile;
|
|
135
135
|
if (typeof opts.compliancePosture === "string") {
|
|
136
|
-
return COMPLIANCE_POSTURES[opts.compliancePosture] || "strict";
|
|
136
|
+
return (Object.prototype.hasOwnProperty.call(COMPLIANCE_POSTURES, opts.compliancePosture) && COMPLIANCE_POSTURES[opts.compliancePosture]) || "strict";
|
|
137
137
|
}
|
|
138
138
|
return "strict";
|
|
139
139
|
}
|
|
@@ -361,7 +361,7 @@ function _parseVcard(lines, startIdx, caps, extraProps) {
|
|
|
361
361
|
"safeVcard.parse: nested BEGIN inside VCARD (vCard does not support sub-components)");
|
|
362
362
|
}
|
|
363
363
|
var pn = ln.name;
|
|
364
|
-
if (!KNOWN_PROPERTIES
|
|
364
|
+
if (!Object.prototype.hasOwnProperty.call(KNOWN_PROPERTIES, pn) && !extraProps[pn] && pn.indexOf("X-") !== 0) {
|
|
365
365
|
throw new SafeVcardError("safe-vcard/unknown-property",
|
|
366
366
|
"safeVcard.parse: unknown property '" + pn +
|
|
367
367
|
"' (extend via opts.extraProperties or use X- prefix)");
|
|
@@ -63,6 +63,12 @@ var workerThreads = require("node:worker_threads");
|
|
|
63
63
|
"setInterval", "clearInterval",
|
|
64
64
|
"queueMicrotask",
|
|
65
65
|
"global",
|
|
66
|
+
// WebAssembly linear memory is allocated OUTSIDE the V8 heap, so the
|
|
67
|
+
// worker's maxOldGenerationSizeMb cap (derived from opts.maxBytes) does
|
|
68
|
+
// NOT bound `new WebAssembly.Memory(...).grow(N)` — operator source could
|
|
69
|
+
// commit multi-GiB of off-heap RAM under a tiny maxBytes (CWE-770). It is
|
|
70
|
+
// not in KNOWN_SAFE_BUILTINS so no `allowed` opt can re-expose it.
|
|
71
|
+
"WebAssembly",
|
|
66
72
|
];
|
|
67
73
|
for (var k = 0; k < NODE_BUILTINS.length; k += 1) {
|
|
68
74
|
var nm = NODE_BUILTINS[k];
|
|
@@ -133,7 +133,7 @@ function _validateAllowed(allowed) {
|
|
|
133
133
|
throw new SandboxError("sandbox/bad-allowed",
|
|
134
134
|
"sandbox.run: opts.allowed[" + i + "] must be a non-empty identifier string");
|
|
135
135
|
}
|
|
136
|
-
if (!KNOWN_SAFE_BUILTINS
|
|
136
|
+
if (!Object.prototype.hasOwnProperty.call(KNOWN_SAFE_BUILTINS, name)) {
|
|
137
137
|
throw new SandboxError("sandbox/bad-allowed",
|
|
138
138
|
"sandbox.run: opts.allowed[" + i + "] = " + JSON.stringify(name) +
|
|
139
139
|
" is not in the sandbox built-in allowlist " +
|
|
@@ -177,7 +177,7 @@ function parseCron(expr) {
|
|
|
177
177
|
"cron expression must be a non-empty string", true);
|
|
178
178
|
}
|
|
179
179
|
var trimmed = expr.trim();
|
|
180
|
-
if (CRON_SHORTHANDS
|
|
180
|
+
if (Object.prototype.hasOwnProperty.call(CRON_SHORTHANDS, trimmed.toLowerCase())) {
|
|
181
181
|
trimmed = CRON_SHORTHANDS[trimmed.toLowerCase()];
|
|
182
182
|
}
|
|
183
183
|
var fields = trimmed.split(/\s+/);
|
|
@@ -711,8 +711,24 @@ function create(opts) {
|
|
|
711
711
|
});
|
|
712
712
|
}
|
|
713
713
|
|
|
714
|
+
// Node coerces a setTimeout delay greater than the 32-bit signed max
|
|
715
|
+
// (2147483647 ms ≈ 24.8 days) to 1 ms — so a far-future task would fire
|
|
716
|
+
// immediately, and an interval longer than the max would tight-loop. Wait
|
|
717
|
+
// the max chunk, then re-arm for the remainder WITHOUT firing.
|
|
718
|
+
var TIMEOUT_MAX_MS = 2147483647;
|
|
719
|
+
|
|
714
720
|
function _arm(task) {
|
|
715
721
|
var delay = Math.max(0, task.nextRun - Date.now());
|
|
722
|
+
if (delay > TIMEOUT_MAX_MS) {
|
|
723
|
+
var tc = setTimeout(function () {
|
|
724
|
+
timers.delete(tc);
|
|
725
|
+
if (!started) return;
|
|
726
|
+
_arm(task); // re-arm for the remaining delay; do NOT fire yet
|
|
727
|
+
}, TIMEOUT_MAX_MS);
|
|
728
|
+
if (typeof tc.unref === "function") tc.unref();
|
|
729
|
+
timers.add(tc);
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
716
732
|
var t = setTimeout(function () {
|
|
717
733
|
timers.delete(t);
|
|
718
734
|
if (!started) return;
|
|
@@ -181,6 +181,14 @@ function verify(assetPath, signaturePath, pubkeyPem) {
|
|
|
181
181
|
var signature;
|
|
182
182
|
try {
|
|
183
183
|
var sigStat = nodeFs.fstatSync(sigFd);
|
|
184
|
+
// Bound the alloc: the largest supported signature (ML-DSA-87) is ~4.6 KB;
|
|
185
|
+
// 64 KiB is far above any legitimate sig and stops Buffer.allocUnsafe(stat.size)
|
|
186
|
+
// from OOM-ing if signaturePath is pointed at a giant file. Zero-dep by
|
|
187
|
+
// contract — inline literal, cannot import C.BYTES.
|
|
188
|
+
if (sigStat.size > 64 * 1024) { // allow:raw-byte-literal — zero-dep module
|
|
189
|
+
throw new Error("standalone-verifier.verify: signature file implausibly large (" +
|
|
190
|
+
sigStat.size + " bytes)");
|
|
191
|
+
}
|
|
184
192
|
signature = Buffer.allocUnsafe(sigStat.size);
|
|
185
193
|
if (sigStat.size > 0) nodeFs.readSync(sigFd, signature, 0, sigStat.size, 0);
|
|
186
194
|
} finally {
|
|
@@ -219,6 +227,14 @@ function verify(assetPath, signaturePath, pubkeyPem) {
|
|
|
219
227
|
// to come from the same {0..assetStat.size} range fixed at open
|
|
220
228
|
// time.
|
|
221
229
|
var assetStat = nodeFs.fstatSync(assetFd);
|
|
230
|
+
// Bound the asset alloc before Buffer.allocUnsafe(assetStat.size): a self-update
|
|
231
|
+
// bundle (SEA) is intentionally large, so the ceiling is generous (2 GiB), but
|
|
232
|
+
// it stops a signaturePath/assetPath pointed at an unbounded file from OOM-ing
|
|
233
|
+
// the verifier before any byte is hashed. Zero-dep by contract — inline literal.
|
|
234
|
+
if (assetStat.size > 2 * 1024 * 1024 * 1024) { // allow:raw-byte-literal — zero-dep module, 2 GiB asset ceiling
|
|
235
|
+
throw new Error("standalone-verifier.verify: asset implausibly large (" +
|
|
236
|
+
assetStat.size + " bytes) — exceeds the 2 GiB self-update ceiling");
|
|
237
|
+
}
|
|
222
238
|
var sha256 = nodeCrypto.createHash("sha256");
|
|
223
239
|
var sha3 = nodeCrypto.createHash("sha3-512");
|
|
224
240
|
var verifier = (alg === "ecdsa-p384") ? nodeCrypto.createVerify("sha3-512") : null;
|
|
@@ -843,8 +843,16 @@ async function destroyAllForUser(userId) {
|
|
|
843
843
|
// userId is sealed; look up via derived userIdHash.
|
|
844
844
|
var lookup = cryptoField.lookupHash(SESSION_TABLE, "userId", userId);
|
|
845
845
|
if (!lookup) {
|
|
846
|
+
// The session table's userIdHash derived-hash schema is registered during
|
|
847
|
+
// b.db.init(). A pluggable-store consumer (b.session.useStore) who never
|
|
848
|
+
// called b.db.init() lands here first — surface that, not just an opaque
|
|
849
|
+
// "framework misconfigured", since destroyAllForUser still needs b.db for
|
|
850
|
+
// the userIdHash index + the stateless valid-from boundary.
|
|
846
851
|
throw _err("MISCONFIGURED",
|
|
847
|
-
"the session table
|
|
852
|
+
"session.destroyAllForUser: the session table's userIdHash derived-hash schema is " +
|
|
853
|
+
"not registered. It is registered during b.db.init() — call b.db.init() at boot even " +
|
|
854
|
+
"when session data lives in a pluggable store (b.session.useStore). If b.db is already " +
|
|
855
|
+
"initialized, the session table schema is misconfigured.",
|
|
848
856
|
true);
|
|
849
857
|
}
|
|
850
858
|
// Dual-read across the keyed-MAC flip: a pre-v0.15.0 session row carries
|
|
@@ -860,8 +868,24 @@ async function destroyAllForUser(userId) {
|
|
|
860
868
|
var result = await _currentStore().execute(built.sql, built.params);
|
|
861
869
|
// Also raise the stateless valid-from boundary so a "logout everywhere"
|
|
862
870
|
// revokes the operator's stateless tokens (sealed cookies / JWTs checked via
|
|
863
|
-
// b.session.check) too, not only the store-backed rows just deleted.
|
|
864
|
-
|
|
871
|
+
// b.session.check) too, not only the store-backed rows just deleted. This
|
|
872
|
+
// bump writes to the FRAMEWORK db (clusterStorage); a pluggable-store consumer
|
|
873
|
+
// (b.session.useStore) who never ran b.db.init() would otherwise surface the
|
|
874
|
+
// opaque "db/not-initialized" here, after the store delete already succeeded.
|
|
875
|
+
// Rethrow it as a session-specific, actionable error.
|
|
876
|
+
try {
|
|
877
|
+
await bump(userId);
|
|
878
|
+
} catch (e) {
|
|
879
|
+
if (e && e.code === "db/not-initialized") {
|
|
880
|
+
throw _err("MISCONFIGURED",
|
|
881
|
+
"session.destroyAllForUser raises the stateless valid-from boundary (so a " +
|
|
882
|
+
"logout-everywhere also revokes sealed-cookie / JWT sessions), which requires " +
|
|
883
|
+
"b.db.init() — call it at boot even when session data lives in a pluggable " +
|
|
884
|
+
"store (b.session.useStore). The store-backed rows were already deleted; rerun " +
|
|
885
|
+
"after b.db.init() to also raise the stateless boundary.", true);
|
|
886
|
+
}
|
|
887
|
+
throw e;
|
|
888
|
+
}
|
|
865
889
|
return result.rowCount || 0;
|
|
866
890
|
}
|
|
867
891
|
|
|
@@ -439,7 +439,7 @@ class SqlFunction {
|
|
|
439
439
|
throw _err("b.sql.fn(name): name must be a string", "sql-builder/bad-fn");
|
|
440
440
|
}
|
|
441
441
|
var key = name.toUpperCase();
|
|
442
|
-
if (SQL_FUNCTIONS
|
|
442
|
+
if (!Object.prototype.hasOwnProperty.call(SQL_FUNCTIONS, key)) {
|
|
443
443
|
throw _err("b.sql.fn(name): '" + name + "' is not an allowlisted SQL function " +
|
|
444
444
|
"(NOW / CURRENT_TIMESTAMP / CURRENT_DATE / CURRENT_TIME); a bound value uses a ? " +
|
|
445
445
|
"placeholder, an arbitrary expression uses a guarded raw fragment", "sql-builder/bad-fn");
|
|
@@ -513,7 +513,7 @@ function _castType(type, dialect) {
|
|
|
513
513
|
throw _err("cast type must be a non-empty string", "sql-builder/bad-cast");
|
|
514
514
|
}
|
|
515
515
|
var key = type.toLowerCase();
|
|
516
|
-
if (CAST_TYPES
|
|
516
|
+
if (!Object.prototype.hasOwnProperty.call(CAST_TYPES, key)) {
|
|
517
517
|
throw _err("cast type '" + type + "' is not on the allowlist (jsonb / json / " +
|
|
518
518
|
"interval / uuid / text / int / bigint / timestamptz / boolean)", "sql-builder/bad-cast");
|
|
519
519
|
}
|
|
@@ -3519,7 +3519,7 @@ var catalog = Object.freeze({
|
|
|
3519
3519
|
* b.sql.pragma("journal_mode").sql; // -> 'PRAGMA journal_mode' (read)
|
|
3520
3520
|
*/
|
|
3521
3521
|
function pragma(verb, arg) {
|
|
3522
|
-
if (typeof verb !== "string" || CATALOG_PRAGMA_VERBS
|
|
3522
|
+
if (typeof verb !== "string" || !Object.prototype.hasOwnProperty.call(CATALOG_PRAGMA_VERBS, verb)) {
|
|
3523
3523
|
throw _err("pragma: verb '" + verb + "' is not on the allowlist (journal_mode / " +
|
|
3524
3524
|
"synchronous / wal_checkpoint); a PRAGMA outside this set is refused by design",
|
|
3525
3525
|
"sql-builder/bad-pragma");
|
|
@@ -42,6 +42,7 @@ var nodeFs = require("node:fs");
|
|
|
42
42
|
var fsp = require("node:fs/promises");
|
|
43
43
|
var nodeCrypto = require("node:crypto");
|
|
44
44
|
var nodePath = require("node:path");
|
|
45
|
+
var atomicFile = require("./atomic-file");
|
|
45
46
|
var C = require("./constants");
|
|
46
47
|
var gateContract = require("./gate-contract");
|
|
47
48
|
var lazyRequire = require("./lazy-require");
|
|
@@ -240,10 +241,16 @@ async function _readMeta(root, candidate) {
|
|
|
240
241
|
var sri = nodeCrypto.createHash("sha384");
|
|
241
242
|
var sha3 = nodeCrypto.createHash("sha3-512");
|
|
242
243
|
await new Promise(function (resolve, reject) {
|
|
243
|
-
// The path
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
|
|
244
|
+
// The path is the confined output of `_assertInsideRoot(root, candidate)`
|
|
245
|
+
// above (lexical resolve + root-prefix containment). Open it O_NOFOLLOW and
|
|
246
|
+
// stream from that fd: lexical confinement still leaves a window where a
|
|
247
|
+
// symlink swapped in at the final component after the check would be
|
|
248
|
+
// followed by a plain createReadStream (CWE-22 / CWE-367); O_NOFOLLOW refuses
|
|
249
|
+
// it. The open throws synchronously on a symlink (ELOOP) / missing file —
|
|
250
|
+
// reject the hash promise so the caller falls back exactly as on a read error.
|
|
251
|
+
var s;
|
|
252
|
+
try { s = nodeFs.createReadStream(absPath, { fd: atomicFile.openNoFollowSync(absPath) }); }
|
|
253
|
+
catch (e) { reject(e); return; }
|
|
247
254
|
s.on("data", function (chunk) { sri.update(chunk); sha3.update(chunk); });
|
|
248
255
|
s.on("end", resolve);
|
|
249
256
|
s.on("error", reject);
|
|
@@ -399,7 +406,7 @@ function _shouldForceAttachment(contentType, ext, contentSafetyMap, allowSvgRend
|
|
|
399
406
|
return true;
|
|
400
407
|
}
|
|
401
408
|
if (bare.indexOf("text/") === 0) return false;
|
|
402
|
-
if (SAFE_RENDER_RASTER_MIMES
|
|
409
|
+
if (Object.prototype.hasOwnProperty.call(SAFE_RENDER_RASTER_MIMES, bare)) return false;
|
|
403
410
|
if (bare === "image/svg+xml") {
|
|
404
411
|
if (!allowSvgRender) return true;
|
|
405
412
|
if (!contentSafetyMap || typeof contentSafetyMap !== "object") return true;
|
|
@@ -884,10 +891,21 @@ function create(opts) {
|
|
|
884
891
|
// `_assertInsideRoot`, not the request-derived candidate.
|
|
885
892
|
var confined = _assertInsideRoot(root, absPath);
|
|
886
893
|
if (!confined) return { ok: false, reason: "read-failed" };
|
|
894
|
+
// Only the first 64 KiB is ever inspected, so read JUST that prefix from an
|
|
895
|
+
// O_NOFOLLOW fd: the previous fsp.readFile slurped the WHOLE file into memory
|
|
896
|
+
// just to sniff its header — a request-reachable OOM on a user-content mount
|
|
897
|
+
// — and followed a post-confinement symlink swap. A PREFIX read (not a
|
|
898
|
+
// maxBytes refusal) is required so a large but allowed file still serves.
|
|
887
899
|
var sample;
|
|
888
|
-
try {
|
|
889
|
-
|
|
890
|
-
|
|
900
|
+
try {
|
|
901
|
+
var sniffFd = atomicFile.openNoFollowSync(confined);
|
|
902
|
+
try {
|
|
903
|
+
var sniffBuf = Buffer.alloc(C.BYTES.kib(64));
|
|
904
|
+
var sniffN = nodeFs.readSync(sniffFd, sniffBuf, 0, sniffBuf.length, 0);
|
|
905
|
+
sample = sniffBuf.slice(0, sniffN);
|
|
906
|
+
} finally { nodeFs.closeSync(sniffFd); }
|
|
907
|
+
} catch (_e) { return { ok: false, reason: "read-failed" }; }
|
|
908
|
+
var detected = fileType.detect(sample) || {};
|
|
891
909
|
if (!detected.mime) return { ok: false, reason: "indeterminate" };
|
|
892
910
|
if (allowedFileTypes.indexOf(detected.mime) === -1) {
|
|
893
911
|
return { ok: false, reason: "not-allowed", detected: detected.mime };
|
|
@@ -1051,6 +1069,23 @@ function create(opts) {
|
|
|
1051
1069
|
// creation can ever ride this code path.
|
|
1052
1070
|
gateHandle = await fsp.open(gateConfined, gateOpenFlags, 0o600);
|
|
1053
1071
|
var gateStat = await gateHandle.stat();
|
|
1072
|
+
// Cap before Buffer.alloc(gateStat.size): the gate buffers the WHOLE
|
|
1073
|
+
// file to inspect it, so a multi-GiB file on a user-content mount is a
|
|
1074
|
+
// request-reachable OOM lever. A file too large for the gate to vet is
|
|
1075
|
+
// refused (the gate's own "refuse" disposition) rather than buffered.
|
|
1076
|
+
if (gateStat.size > C.BYTES.mib(16)) {
|
|
1077
|
+
stats.failures += 1;
|
|
1078
|
+
_emitObs("staticServe.content_safety_refused", 1, { route: urlPath });
|
|
1079
|
+
try { await gateHandle.close(); } catch (_ce) { /* close best-effort */ }
|
|
1080
|
+
if (auditFailures) {
|
|
1081
|
+
emitAudit("staticServe.serve.failure", Object.assign({
|
|
1082
|
+
outcome: "failure", reason: "content_safety_too_large",
|
|
1083
|
+
resource: urlPath, ext: ext, sizeBytes: gateStat.size,
|
|
1084
|
+
}, actorCtx));
|
|
1085
|
+
}
|
|
1086
|
+
return writeErr(res, HTTP.UNSUPPORTED_MEDIA_TYPE,
|
|
1087
|
+
"content_safety_refused", "Unsupported Media Type");
|
|
1088
|
+
}
|
|
1054
1089
|
gateBuf = Buffer.alloc(gateStat.size);
|
|
1055
1090
|
var gateRead = 0;
|
|
1056
1091
|
while (gateRead < gateStat.size) {
|
|
@@ -1135,8 +1170,11 @@ function create(opts) {
|
|
|
1135
1170
|
"precondition_failed", "Precondition Failed");
|
|
1136
1171
|
}
|
|
1137
1172
|
|
|
1138
|
-
// Conditional: If-Modified-Since (304)
|
|
1139
|
-
|
|
1173
|
+
// Conditional: If-Modified-Since (304) — RFC 7232 §6: evaluated ONLY when
|
|
1174
|
+
// If-None-Match is absent. Otherwise a changed-ETag resource rewritten
|
|
1175
|
+
// within the same wall-clock second (mtime compared at second granularity)
|
|
1176
|
+
// would be falsely reported 304 despite the content hash differing.
|
|
1177
|
+
var ifModSince = !ifNone && headersIn["if-modified-since"];
|
|
1140
1178
|
if (ifModSince) {
|
|
1141
1179
|
var ims = Date.parse(ifModSince);
|
|
1142
1180
|
if (isFinite(ims) && Math.floor(meta.mtimeMs / C.TIME.seconds(1)) <= Math.floor(ims / C.TIME.seconds(1))) {
|
|
@@ -1151,8 +1189,9 @@ function create(opts) {
|
|
|
1151
1189
|
}
|
|
1152
1190
|
}
|
|
1153
1191
|
|
|
1154
|
-
// Conditional: If-Unmodified-Since (412)
|
|
1155
|
-
|
|
1192
|
+
// Conditional: If-Unmodified-Since (412) — RFC 7232 §6: evaluated ONLY
|
|
1193
|
+
// when If-Match is absent.
|
|
1194
|
+
var ifUnmodSince = !ifMatch && headersIn["if-unmodified-since"];
|
|
1156
1195
|
if (ifUnmodSince) {
|
|
1157
1196
|
var ius = Date.parse(ifUnmodSince);
|
|
1158
1197
|
if (isFinite(ius) && Math.floor(meta.mtimeMs / C.TIME.seconds(1)) > Math.floor(ius / C.TIME.seconds(1))) {
|
|
@@ -1348,7 +1387,20 @@ function create(opts) {
|
|
|
1348
1387
|
}
|
|
1349
1388
|
|
|
1350
1389
|
var streamOpts = range ? { start: range.start, end: range.end } : {};
|
|
1351
|
-
|
|
1390
|
+
// Open streamTarget (the re-confined _assertInsideRoot output) O_NOFOLLOW and
|
|
1391
|
+
// stream from that fd, so a symlink swapped in at the final component after
|
|
1392
|
+
// confinement is refused (ELOOP) rather than followed (CWE-22 / CWE-367).
|
|
1393
|
+
// Headers are already committed here, so a sync refusal can't re-issue a 404
|
|
1394
|
+
// — abort the connection instead of serving the swapped target.
|
|
1395
|
+
var fileStream;
|
|
1396
|
+
try {
|
|
1397
|
+
fileStream = nodeFs.createReadStream(streamTarget,
|
|
1398
|
+
Object.assign({ fd: atomicFile.openNoFollowSync(streamTarget) }, streamOpts));
|
|
1399
|
+
} catch (_openErr) {
|
|
1400
|
+
releaseSlot();
|
|
1401
|
+
try { res.destroy(); } catch (_d) { /* already torn down */ }
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1352
1404
|
|
|
1353
1405
|
// Idle timeout — close the connection if the client stalls. Pattern is
|
|
1354
1406
|
// a deadline-style debounce (clearTimeout + setTimeout) tied directly
|
|
@@ -93,6 +93,7 @@ var nodeFs = require("node:fs");
|
|
|
93
93
|
var nodePath = require("node:path");
|
|
94
94
|
var lazyRequire = require("./lazy-require");
|
|
95
95
|
var validateOpts = require("./validate-opts");
|
|
96
|
+
var markupEscape = require("./markup-escape").markupEscape;
|
|
96
97
|
|
|
97
98
|
// Lazy because b.template can be loaded before b.sandbox (which pulls
|
|
98
99
|
// in node:worker_threads). Operators not opting into sandboxed helpers
|
|
@@ -116,9 +117,6 @@ var DEFAULT_STRING_TEMPLATE_BYTES = require("./constants").BYTES.kib(256);
|
|
|
116
117
|
// HTML escape (exported)
|
|
117
118
|
// ============================================================
|
|
118
119
|
|
|
119
|
-
var ESCAPE_MAP = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
120
|
-
var ESCAPE_RE = /[&<>"']/g;
|
|
121
|
-
|
|
122
120
|
/**
|
|
123
121
|
* @primitive b.template.escapeHtml
|
|
124
122
|
* @signature b.template.escapeHtml(value)
|
|
@@ -141,8 +139,12 @@ var ESCAPE_RE = /[&<>"']/g;
|
|
|
141
139
|
*/
|
|
142
140
|
function escapeHtml(value) {
|
|
143
141
|
if (value === null || value === undefined) return "";
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
// Delegate the actual escaping to the centralized markup escaper so the
|
|
143
|
+
// five-character HTML set (& < > " ') is defined in one place — a divergence
|
|
144
|
+
// between this and the shared escaper is an XSS / XML-injection surface. The
|
|
145
|
+
// apostrophe is escaped to its numeric form for safety in single-quoted
|
|
146
|
+
// attribute contexts (the historical behavior of this primitive).
|
|
147
|
+
return markupEscape(value, { apos: "'" });
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
// ============================================================
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
|
|
53
53
|
var C = require("./constants");
|
|
54
54
|
var lazyRequire = require("./lazy-require");
|
|
55
|
+
var boundedMap = require("./bounded-map");
|
|
55
56
|
var validateOpts = require("./validate-opts");
|
|
56
57
|
var { defineClass } = require("./framework-error");
|
|
57
58
|
|
|
@@ -354,18 +355,47 @@ function budget(opts) {
|
|
|
354
355
|
}
|
|
355
356
|
var auditOn = opts.audit !== false;
|
|
356
357
|
|
|
357
|
-
//
|
|
358
|
+
// TRUE sliding window (RFC-ish rolling counter, as advertised) — the prior
|
|
359
|
+
// first-call-pinned fixed window admitted ~2x the cap in a boundary burst.
|
|
360
|
+
// The window is split into BINS sub-bins; each observe lands in the current
|
|
361
|
+
// bin and the cap is enforced against the trailing-window SUM, so a burst
|
|
362
|
+
// straddling the reset can't double the rate. Mirrors network-byte-quota's
|
|
363
|
+
// _slideAndSum ring (here with two counters + a configurable bin width).
|
|
364
|
+
var BINS = 12;
|
|
365
|
+
var binMs = Math.max(1, Math.floor(windowMs / BINS));
|
|
366
|
+
|
|
367
|
+
// tenantId → { calls: number[BINS], rows: number[BINS], startBin }
|
|
358
368
|
var counters = new Map();
|
|
359
369
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
370
|
+
// Advance the ring so its BINS bins cover the trailing [nowBin-BINS+1 .. nowBin],
|
|
371
|
+
// zeroing bins that scrolled out of the window. Returns the tenant's ring.
|
|
372
|
+
function _slide(tenantId, now) {
|
|
373
|
+
var nowBin = Math.floor(now / binMs);
|
|
374
|
+
// A freshly-created ring is anchored at the current bin, so the advance
|
|
375
|
+
// below evaluates to 0 (no-op) on the create path — get-or-insert and the
|
|
376
|
+
// slide stay one code path.
|
|
377
|
+
var c = boundedMap.getOrInsert(counters, tenantId, function () {
|
|
378
|
+
return { calls: new Array(BINS).fill(0), rows: new Array(BINS).fill(0), startBin: nowBin - (BINS - 1) };
|
|
379
|
+
});
|
|
380
|
+
var advance = nowBin - (c.startBin + (BINS - 1));
|
|
381
|
+
if (advance > 0) {
|
|
382
|
+
if (advance >= BINS) {
|
|
383
|
+
c.calls.fill(0); c.rows.fill(0);
|
|
384
|
+
} else {
|
|
385
|
+
for (var i = 0; i < BINS - advance; i++) { c.calls[i] = c.calls[i + advance]; c.rows[i] = c.rows[i + advance]; }
|
|
386
|
+
for (var k = BINS - advance; k < BINS; k++) { c.calls[k] = 0; c.rows[k] = 0; }
|
|
387
|
+
}
|
|
388
|
+
c.startBin = nowBin - (BINS - 1);
|
|
365
389
|
}
|
|
366
390
|
return c;
|
|
367
391
|
}
|
|
368
392
|
|
|
393
|
+
function _sum(c) {
|
|
394
|
+
var calls = 0, rows = 0;
|
|
395
|
+
for (var i = 0; i < BINS; i++) { calls += c.calls[i]; rows += c.rows[i]; }
|
|
396
|
+
return { calls: calls, rowsRead: rows };
|
|
397
|
+
}
|
|
398
|
+
|
|
369
399
|
var _emitAudit = audit().namespaced(null, { audit: auditOn });
|
|
370
400
|
|
|
371
401
|
function _emitMetric(name, n) {
|
|
@@ -378,16 +408,19 @@ function budget(opts) {
|
|
|
378
408
|
"tenantQuota.budget.observe: tenantId", TenantQuotaError, "tenant-quota/bad-tenant");
|
|
379
409
|
info = info || {};
|
|
380
410
|
var rowsRead = (typeof info.rowsRead === "number" && info.rowsRead >= 0) ? info.rowsRead : 0;
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
c
|
|
411
|
+
// info.now lets a caller / test supply a deterministic clock (idiomatic —
|
|
412
|
+
// mirrors auth verifiers' opts.now); defaults to wall-clock.
|
|
413
|
+
var now = (typeof info.now === "number") ? info.now : Date.now();
|
|
414
|
+
var c = _slide(tenantId, now);
|
|
415
|
+
c.calls[BINS - 1] += 1;
|
|
416
|
+
c.rows[BINS - 1] += rowsRead;
|
|
417
|
+
var tot = _sum(c);
|
|
385
418
|
var maxCalls = Math.max(1, Math.floor(qpsCap * (windowMs / C.TIME.seconds(1))));
|
|
386
|
-
if (
|
|
419
|
+
if (tot.calls > maxCalls || tot.rowsRead > rowsCap) {
|
|
387
420
|
_emitAudit("tenant.budget.exceeded", "denied", {
|
|
388
421
|
tenantId: tenantId,
|
|
389
|
-
calls:
|
|
390
|
-
rowsRead:
|
|
422
|
+
calls: tot.calls,
|
|
423
|
+
rowsRead: tot.rowsRead,
|
|
391
424
|
qpsCap: qpsCap,
|
|
392
425
|
rowsCap: rowsCap,
|
|
393
426
|
windowMs: windowMs,
|
|
@@ -395,19 +428,19 @@ function budget(opts) {
|
|
|
395
428
|
_emitMetric("tenant.budget.exceeded", 1);
|
|
396
429
|
throw new TenantQuotaError("tenant-quota/budget-exceeded",
|
|
397
430
|
"tenantQuota.budget: tenant '" + tenantId + "' exceeded budget " +
|
|
398
|
-
"(calls=" +
|
|
431
|
+
"(calls=" + tot.calls + "/" + maxCalls + ", rowsRead=" + tot.rowsRead +
|
|
399
432
|
"/" + rowsCap + ", windowMs=" + windowMs + ")");
|
|
400
433
|
}
|
|
401
|
-
return { calls:
|
|
434
|
+
return { calls: tot.calls, rowsRead: tot.rowsRead, windowMs: windowMs };
|
|
402
435
|
}
|
|
403
436
|
|
|
404
437
|
function snapshot(tenantId) {
|
|
405
|
-
|
|
406
|
-
var c = counters.get(tenantId);
|
|
407
|
-
if (!c || (now - c.windowStart) >= windowMs) {
|
|
438
|
+
if (!counters.has(tenantId)) {
|
|
408
439
|
return { tenantId: tenantId, calls: 0, rowsRead: 0, windowMs: windowMs };
|
|
409
440
|
}
|
|
410
|
-
|
|
441
|
+
var c = _slide(tenantId, Date.now());
|
|
442
|
+
var tot = _sum(c);
|
|
443
|
+
return { tenantId: tenantId, calls: tot.calls, rowsRead: tot.rowsRead, windowMs: windowMs };
|
|
411
444
|
}
|
|
412
445
|
|
|
413
446
|
function reset(tenantId) {
|
|
@@ -56,6 +56,7 @@ var bCrypto = require("./crypto");
|
|
|
56
56
|
var safeBuffer = require("./safe-buffer");
|
|
57
57
|
var asn1 = require("./asn1-der");
|
|
58
58
|
var cms = require("./cms-codec");
|
|
59
|
+
var x509Chain = require("./x509-chain");
|
|
59
60
|
var validateOpts = require("./validate-opts");
|
|
60
61
|
var { defineClass } = require("./framework-error");
|
|
61
62
|
|
|
@@ -539,8 +540,10 @@ function _verifyChain(signerCertDer, tokenCerts, trustAnchorsPem, at) {
|
|
|
539
540
|
throw new TsaError("tsa/chain-loop", "tsa.verifyToken: certificate chain did not terminate");
|
|
540
541
|
}
|
|
541
542
|
function _issued(issuer, subject) {
|
|
542
|
-
|
|
543
|
-
|
|
543
|
+
// Enforces basicConstraints cA:TRUE on the issuer in addition to the
|
|
544
|
+
// checkIssued + signature linkage — a non-CA cert can never be a chain
|
|
545
|
+
// issuer (basicConstraints bypass, CVE-2002-0862 class).
|
|
546
|
+
return x509Chain.issuerValidlyIssued(issuer, subject);
|
|
544
547
|
}
|
|
545
548
|
function _assertValidAt(cert, atMs) {
|
|
546
549
|
if (atMs < cert.validFromDate.getTime() || atMs > cert.validToDate.getTime()) {
|
|
@@ -681,6 +681,11 @@ module.exports = {
|
|
|
681
681
|
init: init,
|
|
682
682
|
seal: seal,
|
|
683
683
|
unseal: unseal,
|
|
684
|
+
// The default sealed-storage Store: a { seal, unseal } pair backed by the
|
|
685
|
+
// in-process vault key. b.cert.create (and other sealed-disk consumers)
|
|
686
|
+
// resolve `opts.vault || getDefaultStore()`; documented in their @opts.
|
|
687
|
+
getDefaultStore: function () { return { seal: seal, unseal: unseal }; },
|
|
688
|
+
Store: { seal: seal, unseal: unseal },
|
|
684
689
|
getDerivedHashSalt: getDerivedHashSalt,
|
|
685
690
|
getDerivedHashMacKey: getDerivedHashMacKey,
|
|
686
691
|
_zeroizeAndReplace: _zeroizeAndReplace,
|