@blamejs/blamejs-shop 0.4.69 → 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 +2 -0
- package/lib/admin.js +8 -6
- package/lib/asset-manifest.json +1 -1
- 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
|
@@ -1093,6 +1093,15 @@ function _verifyOcspSignature(parsed, issuerPem) {
|
|
|
1093
1093
|
// `ocsp.requireStapled` or any other source) plus the issuer cert PEM
|
|
1094
1094
|
// and returns a structured outcome:
|
|
1095
1095
|
// { ok, status, certStatus, thisUpdate, nextUpdate, signatureValid, errors }
|
|
1096
|
+
// Normalize a certificate serial for comparison: lowercase, drop separators
|
|
1097
|
+
// (X509Certificate.serialNumber is uppercase, no colons here but defensive) and
|
|
1098
|
+
// the optional DER leading sign-zero, so a serial from node:crypto and one
|
|
1099
|
+
// parsed from the OCSP certID DER compare equal. Both sides go through this.
|
|
1100
|
+
function _normOcspSerial(s) {
|
|
1101
|
+
var h = String(s || "").toLowerCase().replace(/[^0-9a-f]/g, "");
|
|
1102
|
+
return h.replace(/^0+/, "") || "0";
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1096
1105
|
function evaluateOcspResponse(ocspDer, opts) {
|
|
1097
1106
|
opts = opts || {};
|
|
1098
1107
|
var issuerPem = opts.issuerPem;
|
|
@@ -1120,12 +1129,21 @@ function evaluateOcspResponse(ocspDer, opts) {
|
|
|
1120
1129
|
return { ok: false, status: parsed.status, signatureValid: false,
|
|
1121
1130
|
errors: ["OCSP signature did not verify against the issuer key"] };
|
|
1122
1131
|
}
|
|
1123
|
-
//
|
|
1124
|
-
|
|
1132
|
+
// Bind the response to the serial of the certificate UNDER VALIDATION. The
|
|
1133
|
+
// old code defaulted an absent serialHex to responses[0]'s own serial and
|
|
1134
|
+
// then matched it — so a CA-signed "good" response covering a DIFFERENT cert
|
|
1135
|
+
// of the same issuer (replayed/mis-routed batch reply) was accepted. Require
|
|
1136
|
+
// a bound serial and fail closed without one; compare normalized (lowercase,
|
|
1137
|
+
// strip separators + DER leading sign-zero on both sides).
|
|
1138
|
+
if (!opts.serialHex) {
|
|
1139
|
+
return { ok: false, status: parsed.status, signatureValid: true,
|
|
1140
|
+
errors: ["OCSP evaluation requires opts.serialHex (the serial of the certificate being validated) to bind the response"] };
|
|
1141
|
+
}
|
|
1142
|
+
var wantSerial = _normOcspSerial(opts.serialHex);
|
|
1125
1143
|
var match = null;
|
|
1126
1144
|
for (var i = 0; i < parsed.basic.responses.length; i += 1) {
|
|
1127
1145
|
var r = parsed.basic.responses[i];
|
|
1128
|
-
if (
|
|
1146
|
+
if (_normOcspSerial(r.certIdSerialHex) === wantSerial) { match = r; break; }
|
|
1129
1147
|
}
|
|
1130
1148
|
if (!match) {
|
|
1131
1149
|
return { ok: false, status: parsed.status, signatureValid: true,
|
|
@@ -1418,7 +1436,9 @@ async function fetchOcspResponse(opts) {
|
|
|
1418
1436
|
}
|
|
1419
1437
|
var evald = evaluateOcspResponse(res.body, {
|
|
1420
1438
|
issuerPem: opts.issuerPem,
|
|
1421
|
-
|
|
1439
|
+
// Bind to the leaf being checked (its serial), not whatever the response
|
|
1440
|
+
// happens to carry — defaults to leafX.serialNumber when not overridden.
|
|
1441
|
+
serialHex: opts.serialHex || leafX.serialNumber,
|
|
1422
1442
|
expectedNonce: opts.nonce === false ? null : built.nonce,
|
|
1423
1443
|
});
|
|
1424
1444
|
if (!evald.ok) {
|
|
@@ -1458,7 +1478,9 @@ var ocsp = Object.freeze({
|
|
|
1458
1478
|
}
|
|
1459
1479
|
var evald = evaluateOcspResponse(rv.ocspBytes, {
|
|
1460
1480
|
issuerPem: opts.issuerPem,
|
|
1461
|
-
|
|
1481
|
+
// Bind to the connected peer's certificate serial (not the response's own
|
|
1482
|
+
// entry) — without it evaluateOcspResponse fails closed.
|
|
1483
|
+
serialHex: opts.serialHex || (rv.peerCert && rv.peerCert.serialNumber) || null,
|
|
1462
1484
|
});
|
|
1463
1485
|
if (!evald.ok) {
|
|
1464
1486
|
throw new TlsTrustError("tls/ocsp-not-good",
|
|
@@ -61,8 +61,8 @@ var ERROR = { NOERROR: 0, BADSIG: 16, BADKEY: 17, BADTIME: 18, BADTRUNC: 22 };
|
|
|
61
61
|
|
|
62
62
|
function _normAlg(name, allowLegacy) {
|
|
63
63
|
var key = String(name || "hmac-sha256").toLowerCase().replace(/\.$/, "");
|
|
64
|
-
if (ALGORITHMS
|
|
65
|
-
if (LEGACY_ALGORITHMS
|
|
64
|
+
if (Object.prototype.hasOwnProperty.call(ALGORITHMS, key)) return { name: key, hash: ALGORITHMS[key] };
|
|
65
|
+
if (Object.prototype.hasOwnProperty.call(LEGACY_ALGORITHMS, key)) {
|
|
66
66
|
if (!allowLegacy) throw new TsigError("tsig/legacy-algorithm", "tsig: algorithm '" + key + "' is broken; pass allowLegacy:true to permit it for legacy interop");
|
|
67
67
|
return { name: key, hash: LEGACY_ALGORITHMS[key] };
|
|
68
68
|
}
|
|
@@ -54,7 +54,7 @@ function create(opts) {
|
|
|
54
54
|
validateOpts.requireNonEmptyString(opts.entityId,
|
|
55
55
|
"nis2.report.create: opts.entityId is required (NIS2 registration ID)",
|
|
56
56
|
Nis2ReportError, "nis2-report/bad-entity-id");
|
|
57
|
-
if (!VALID_ENTITY_TYPES
|
|
57
|
+
if (!Object.prototype.hasOwnProperty.call(VALID_ENTITY_TYPES, opts.entityType)) {
|
|
58
58
|
throw new Nis2ReportError("nis2-report/bad-entity-type",
|
|
59
59
|
"nis2.report.create: opts.entityType must be 'essential' or 'important' (NIS2 Article 3 classification)");
|
|
60
60
|
}
|
|
@@ -199,7 +199,7 @@ var CATALOGS = {
|
|
|
199
199
|
* // → ["b.permissions", "b.middleware.requireAuth", ...]
|
|
200
200
|
*/
|
|
201
201
|
function controls(catalog) {
|
|
202
|
-
if (typeof catalog !== "string" || !CATALOGS
|
|
202
|
+
if (typeof catalog !== "string" || !Object.prototype.hasOwnProperty.call(CATALOGS, catalog)) {
|
|
203
203
|
throw new NistCrosswalkError("nist-crosswalk/unknown-catalog",
|
|
204
204
|
"controls: unknown catalog '" + catalog + "'. Known: " +
|
|
205
205
|
Object.keys(CATALOGS).join(", "));
|
|
@@ -45,6 +45,8 @@
|
|
|
45
45
|
* Boot-time clock-drift verification against an external NTP / NTS-KE reference.
|
|
46
46
|
*/
|
|
47
47
|
var dgram = require("node:dgram");
|
|
48
|
+
var nodeCrypto = require("node:crypto");
|
|
49
|
+
var bCrypto = require("./crypto");
|
|
48
50
|
var C = require("./constants");
|
|
49
51
|
var lazyRequire = require("./lazy-require");
|
|
50
52
|
var safeAsync = require("./safe-async");
|
|
@@ -200,6 +202,14 @@ function querySingle(server, opts) {
|
|
|
200
202
|
// LI=0 (no warning), VN=4, Mode=3 (client). Other bytes zero.
|
|
201
203
|
var req = Buffer.alloc(NTP_PACKET_BYTES);
|
|
202
204
|
req[0] = 0x23;
|
|
205
|
+
// RFC 5905 §8 client-cookie: put a random 64-bit nonce in the request's
|
|
206
|
+
// Transmit Timestamp (bytes 40-47). A conformant server copies it verbatim
|
|
207
|
+
// into the reply's Originate Timestamp (bytes 24-31). Verifying that echo
|
|
208
|
+
// rejects an off-path spoofed reply — without it ANY 48-byte UDP datagram
|
|
209
|
+
// reaching our ephemeral port becomes the authoritative time, letting a
|
|
210
|
+
// spoofer force a fatal-drift refuse-to-boot under BLAMEJS_NTP_STRICT.
|
|
211
|
+
var originCookie = nodeCrypto.randomBytes(8);
|
|
212
|
+
originCookie.copy(req, 40);
|
|
203
213
|
var sendTimeMs = Date.now();
|
|
204
214
|
|
|
205
215
|
socket.on("error", function (e) {
|
|
@@ -213,6 +223,24 @@ function querySingle(server, opts) {
|
|
|
213
223
|
if (!Buffer.isBuffer(msg) || msg.length < NTP_PACKET_BYTES) {
|
|
214
224
|
return done({ code: "ntp/bad-reply", message: "reply too short (" + (msg && msg.length) + " bytes)" });
|
|
215
225
|
}
|
|
226
|
+
// Origin-cookie echo (RFC 5905 §8): the reply's Originate Timestamp
|
|
227
|
+
// (bytes 24-31) MUST equal the nonce we sent. An off-path spoofer can't
|
|
228
|
+
// know it, so this is the primary reply-authenticity check.
|
|
229
|
+
if (!bCrypto.timingSafeEqual(msg.subarray(24, 32), originCookie)) {
|
|
230
|
+
return done({ code: "ntp/origin-mismatch",
|
|
231
|
+
message: server + ": reply Originate Timestamp does not echo the request nonce (spoofed/stale reply)" });
|
|
232
|
+
}
|
|
233
|
+
// Reject a non-server mode, an unsynchronized/kiss-o'-death stratum
|
|
234
|
+
// (0 or >= 16), or LI=3 (alarm — clock not synchronized): such a peer
|
|
235
|
+
// cannot supply a trustworthy time and must not drive drift.
|
|
236
|
+
var mode = msg[0] & 0x07;
|
|
237
|
+
var li = (msg[0] >> 6) & 0x03;
|
|
238
|
+
var stratum = msg[1];
|
|
239
|
+
if (mode !== 4 || li === 3 || stratum === 0 || stratum >= 16) {
|
|
240
|
+
return done({ code: "ntp/unsynchronized",
|
|
241
|
+
message: server + ": reply mode=" + mode + " stratum=" + stratum + " LI=" + li +
|
|
242
|
+
" is not a synchronized server response" });
|
|
243
|
+
}
|
|
216
244
|
// Bytes 40-47 = Transmit Timestamp (NTP epoch seconds.fraction)
|
|
217
245
|
var ntpSeconds = msg.readUInt32BE(40); // NTP packet offset
|
|
218
246
|
var ntpFraction = msg.readUInt32BE(44); // NTP packet offset
|
|
@@ -66,6 +66,14 @@ function isNonNegativeFiniteInt(value) {
|
|
|
66
66
|
Number.isInteger(value) && value >= 0;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
// Any-sign finite integer (no sign bound) — for callers that only require
|
|
70
|
+
// integrality (e.g. a CloudEvents 32-bit signed-integer extension, a DNS
|
|
71
|
+
// algorithm/digest-type code) and reject only non-numbers / floats / Infinity /
|
|
72
|
+
// NaN. Distinct from isNonNegativeFiniteInt (which also forbids negatives).
|
|
73
|
+
function isFiniteInt(value) {
|
|
74
|
+
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value);
|
|
75
|
+
}
|
|
76
|
+
|
|
69
77
|
// requirePositiveFiniteIntIfPresent / requireNonNegativeFiniteIntIfPresent —
|
|
70
78
|
// optional-shape gates that throw via the caller's framework-error class
|
|
71
79
|
// when the value is present but invalid. Replaces the per-file
|
|
@@ -150,6 +158,7 @@ module.exports = {
|
|
|
150
158
|
shape: shape,
|
|
151
159
|
isPositiveFiniteInt: isPositiveFiniteInt,
|
|
152
160
|
isNonNegativeFiniteInt: isNonNegativeFiniteInt,
|
|
161
|
+
isFiniteInt: isFiniteInt,
|
|
153
162
|
requirePositiveFiniteInt: requirePositiveFiniteInt,
|
|
154
163
|
requirePositiveFiniteIntIfPresent: requirePositiveFiniteIntIfPresent,
|
|
155
164
|
requireNonNegativeFiniteIntIfPresent: requireNonNegativeFiniteIntIfPresent,
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
*/
|
|
38
38
|
var nodeCrypto = require("node:crypto");
|
|
39
39
|
var { URL } = require("node:url");
|
|
40
|
-
var { Readable } = require("node:stream");
|
|
41
40
|
var safeXml = require("../parsers/safe-xml");
|
|
42
41
|
var sharedRequest = require("./http-request");
|
|
43
42
|
var sigv4 = require("./sigv4");
|
|
@@ -299,7 +298,7 @@ function create(config) {
|
|
|
299
298
|
return getResponse(key, opts).then(function (r) { return r.body; });
|
|
300
299
|
}
|
|
301
300
|
|
|
302
|
-
function getStream(key, opts) { return
|
|
301
|
+
function getStream(key, opts) { return sharedRequest.promiseToStream(get(key, opts)); }
|
|
303
302
|
|
|
304
303
|
function getResponse(key, opts) {
|
|
305
304
|
opts = opts || {};
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
* Auth: same service-account JSON / RSA-SHA256-signed JWT exchanged
|
|
24
24
|
* for an OAuth2 access token as `lib/object-store/gcs.js`.
|
|
25
25
|
*/
|
|
26
|
-
var nodeFs = require("node:fs");
|
|
27
26
|
var gcs = require("./gcs");
|
|
28
27
|
var authHeader = require("../auth-header");
|
|
29
28
|
var httpClient = require("../http-client");
|
|
30
29
|
var safeJson = require("../safe-json");
|
|
31
30
|
var safeUrl = require("../safe-url");
|
|
32
31
|
var C = require("../constants");
|
|
32
|
+
var atomicFile = require("../atomic-file");
|
|
33
33
|
var requestHelpers = require("../request-helpers");
|
|
34
34
|
var { ObjectStoreError } = require("../framework-error");
|
|
35
35
|
|
|
@@ -139,7 +139,9 @@ function create(config) {
|
|
|
139
139
|
var serviceAccount = config.serviceAccount;
|
|
140
140
|
if (!serviceAccount && config.serviceAccountFile) {
|
|
141
141
|
try {
|
|
142
|
-
|
|
142
|
+
// Cap + fd-bound read of the GCS service-account JSON (private_key). NO
|
|
143
|
+
// refuseSymlink: commonly a k8s projected-secret mount (symlink).
|
|
144
|
+
serviceAccount = safeJson.parse(atomicFile.fdSafeReadSync(config.serviceAccountFile, { maxBytes: C.BYTES.kib(64), encoding: "utf8" }));
|
|
143
145
|
} catch (e) {
|
|
144
146
|
throw _err("BAD_OPT", "gcs bucketOps: failed to read serviceAccountFile '" +
|
|
145
147
|
config.serviceAccountFile + "': " + ((e && e.message) || String(e)), true);
|
|
@@ -22,12 +22,11 @@
|
|
|
22
22
|
* https://cloud.google.com/storage/docs/json_api/v1
|
|
23
23
|
* https://developers.google.com/identity/protocols/oauth2/service-account
|
|
24
24
|
*/
|
|
25
|
-
var nodeFs = require("node:fs");
|
|
26
25
|
var nodeCrypto = require("node:crypto");
|
|
27
|
-
var { Readable } = require("node:stream");
|
|
28
26
|
var bCrypto = require("../crypto");
|
|
29
27
|
var safeJson = require("../safe-json");
|
|
30
28
|
var C = require("../constants");
|
|
29
|
+
var atomicFile = require("../atomic-file");
|
|
31
30
|
var requestHelpers = require("../request-helpers");
|
|
32
31
|
var { ObjectStoreError } = require("../framework-error");
|
|
33
32
|
var safeUrl = require("../safe-url");
|
|
@@ -115,7 +114,10 @@ function create(config) {
|
|
|
115
114
|
var serviceAccount = config.serviceAccount;
|
|
116
115
|
if (!serviceAccount && config.serviceAccountFile) {
|
|
117
116
|
try {
|
|
118
|
-
|
|
117
|
+
// Cap + fd-bound read of the GCS service-account JSON (contains the
|
|
118
|
+
// private_key). NO refuseSymlink: the SA file is commonly a k8s
|
|
119
|
+
// projected-secret mount (symlink). 64 KiB bounds the uncapped read.
|
|
120
|
+
serviceAccount = safeJson.parse(atomicFile.fdSafeReadSync(config.serviceAccountFile, { maxBytes: C.BYTES.kib(64), encoding: "utf8" }), { schema: SERVICE_ACCOUNT_SCHEMA });
|
|
119
121
|
} catch (e) {
|
|
120
122
|
throw new Error("gcs: failed to read serviceAccountFile '" + config.serviceAccountFile + "': " + e.message);
|
|
121
123
|
}
|
|
@@ -224,7 +226,7 @@ function create(config) {
|
|
|
224
226
|
}
|
|
225
227
|
|
|
226
228
|
function getStream(key, opts) {
|
|
227
|
-
return
|
|
229
|
+
return sharedRequest.promiseToStream(get(key, opts));
|
|
228
230
|
}
|
|
229
231
|
|
|
230
232
|
async function getResponse(key, opts) {
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
* Errors are surfaced as object-store errors with statusCode set so the
|
|
17
17
|
* retry layer can classify retryable vs permanent.
|
|
18
18
|
*/
|
|
19
|
-
var { Readable } = require("node:stream");
|
|
20
19
|
var { ObjectStoreError } = require("../framework-error");
|
|
21
20
|
var safeUrl = require("../safe-url");
|
|
22
21
|
var sharedRequest = require("./http-request");
|
|
@@ -96,7 +95,7 @@ function create(config) {
|
|
|
96
95
|
// https that doesn't buffer; return a Readable wrapping the buffered
|
|
97
96
|
// body. Backends that support chunked transfer (e.g. SigV4) implement
|
|
98
97
|
// a real streaming getStream in their own adapter.
|
|
99
|
-
return
|
|
98
|
+
return sharedRequest.promiseToStream(get(key));
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
function head(key) {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* different class pass `errorClass: SomeError` in opts.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
var { Readable } = require("node:stream");
|
|
19
20
|
var httpClient = require("../http-client");
|
|
20
21
|
var C = require("../constants");
|
|
21
22
|
var numericBounds = require("../numeric-bounds");
|
|
@@ -109,7 +110,22 @@ function resolvePresignUploadMinBytes(opts) {
|
|
|
109
110
|
// parameter; the rest is identical.
|
|
110
111
|
function applyConditionalGetHeaders(target, opts, rangeHeaderName) {
|
|
111
112
|
if (opts.range) {
|
|
112
|
-
|
|
113
|
+
// The documented + shipped contract is an array [start, end] (see
|
|
114
|
+
// b.archive.adapters.objectStore and b.backup). Reading .start/.end off an
|
|
115
|
+
// array yields undefined → "bytes=undefined-undefined", which every store
|
|
116
|
+
// IGNORES — silently returning the FULL object instead of the byte range
|
|
117
|
+
// (over-fetch + wrong data for a partial read). Accept the array form (and
|
|
118
|
+
// {start,end} for compatibility) and validate, so a malformed range fails
|
|
119
|
+
// loudly rather than emitting a garbage header.
|
|
120
|
+
var r = opts.range;
|
|
121
|
+
var start = Array.isArray(r) ? r[0] : r.start;
|
|
122
|
+
var end = Array.isArray(r) ? r[1] : r.end;
|
|
123
|
+
if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end < start) {
|
|
124
|
+
throw _err("INVALID_RANGE",
|
|
125
|
+
"range must be [start, end] (or { start, end }) with 0 <= start <= end, got " +
|
|
126
|
+
JSON.stringify(r), true);
|
|
127
|
+
}
|
|
128
|
+
target[rangeHeaderName] = "bytes=" + start + "-" + end;
|
|
113
129
|
}
|
|
114
130
|
if (opts.ifNoneMatch) target["If-None-Match"] = opts.ifNoneMatch;
|
|
115
131
|
if (opts.ifMatch) target["If-Match"] = opts.ifMatch;
|
|
@@ -153,8 +169,21 @@ function notModifiedGetResult() {
|
|
|
153
169
|
};
|
|
154
170
|
}
|
|
155
171
|
|
|
172
|
+
// Wrap a Promise<Buffer|string> as a Readable WITHOUT awaiting it first, so a
|
|
173
|
+
// backend's getStream() stays synchronous (the dispatcher hands the returned
|
|
174
|
+
// Readable straight to the consumer). A bare `Readable.from(promise)` throws
|
|
175
|
+
// ERR_INVALID_ARG_TYPE — Readable.from needs an (async-)iterable, not a Promise
|
|
176
|
+
// — which broke getStream on every remote backend. The async generator defers
|
|
177
|
+
// the await to the first read; a rejection surfaces as the stream's 'error'
|
|
178
|
+
// event, matching the dispatcher's "the Readable surfaces its own errors"
|
|
179
|
+
// contract.
|
|
180
|
+
function promiseToStream(promise) {
|
|
181
|
+
return Readable.from((async function* () { yield await promise; })());
|
|
182
|
+
}
|
|
183
|
+
|
|
156
184
|
module.exports = request;
|
|
157
185
|
module.exports.applyConditionalGetHeaders = applyConditionalGetHeaders;
|
|
186
|
+
module.exports.promiseToStream = promiseToStream;
|
|
158
187
|
module.exports.mapGetResponse = mapGetResponse;
|
|
159
188
|
module.exports.mapHeadResponse = mapHeadResponse;
|
|
160
189
|
module.exports.notModifiedGetResult = notModifiedGetResult;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
var nodeFs = require("node:fs");
|
|
15
15
|
var nodePath = require("node:path");
|
|
16
16
|
var atomicFile = require("../atomic-file");
|
|
17
|
+
var C = require("../constants");
|
|
17
18
|
var cluster = require("../cluster");
|
|
18
19
|
var { ObjectStoreError } = require("../framework-error");
|
|
19
20
|
|
|
@@ -54,16 +55,14 @@ function create(config) {
|
|
|
54
55
|
return Promise.resolve({ size: body.length });
|
|
55
56
|
}
|
|
56
57
|
if (body && typeof body.pipe === "function") {
|
|
57
|
-
// Streaming put —
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
body.on("error", reject);
|
|
66
|
-
});
|
|
58
|
+
// Streaming put — stage into a no-follow exclusive temp + atomic rename
|
|
59
|
+
// (a bare createWriteStream(full) follows a symlink planted at `full` and
|
|
60
|
+
// leaves a half-written object there if the source aborts). maxBytes is
|
|
61
|
+
// raised to the object-store ceiling; default 64 MiB is too small here.
|
|
62
|
+
return atomicFile.writeStream(full, body, {
|
|
63
|
+
fileMode: 0o600,
|
|
64
|
+
maxBytes: C.BYTES.gib(64),
|
|
65
|
+
}).then(function (r) { return { size: r.bytesWritten }; });
|
|
67
66
|
}
|
|
68
67
|
if (typeof body === "string") {
|
|
69
68
|
var buf = Buffer.from(body, "utf8");
|
|
@@ -75,18 +74,39 @@ function create(config) {
|
|
|
75
74
|
|
|
76
75
|
function get(key) {
|
|
77
76
|
var full = _resolveSafe(rootDir, key);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
// One capped fd-bound read (no existsSync check-then-read TOCTOU): get()
|
|
78
|
+
// buffers the whole object, so an uncapped read of a multi-GiB object is an
|
|
79
|
+
// OOM lever — cap it (large reads should use getStream). refuseSymlink stays
|
|
80
|
+
// OFF: operators may legitimately symlink into the store, and _resolveSafe
|
|
81
|
+
// already confines the key to rootDir.
|
|
82
|
+
try {
|
|
83
|
+
return Promise.resolve(atomicFile.fdSafeReadSync(full, {
|
|
84
|
+
maxBytes: C.BYTES.mib(64),
|
|
85
|
+
errorFor: function (kind, detail) {
|
|
86
|
+
if (kind === "enoent") return _err("NOT_FOUND", "key not found: " + key, true);
|
|
87
|
+
if (kind === "too-large") {
|
|
88
|
+
return _err("OBJECT_TOO_LARGE", "object " + key + " exceeds the buffered-get read cap (" +
|
|
89
|
+
detail.size + " > " + detail.max + " bytes) — use getStream()", true);
|
|
90
|
+
}
|
|
91
|
+
return _err("READ_FAILED", "failed to read " + key, true);
|
|
92
|
+
},
|
|
93
|
+
}));
|
|
94
|
+
} catch (e) { return Promise.reject(e); }
|
|
82
95
|
}
|
|
83
96
|
|
|
84
97
|
function getStream(key) {
|
|
85
98
|
var full = _resolveSafe(rootDir, key);
|
|
86
|
-
|
|
87
|
-
|
|
99
|
+
// Open once and stream from that fd, mapping ENOENT to NOT_FOUND, so the
|
|
100
|
+
// existsSync→createReadStream check-then-read window is collapsed. Plain
|
|
101
|
+
// O_RDONLY (follows symlinks): operators may symlink into the store, and the
|
|
102
|
+
// key is already confined by _resolveSafe.
|
|
103
|
+
var fd;
|
|
104
|
+
try { fd = nodeFs.openSync(full, "r"); }
|
|
105
|
+
catch (e) {
|
|
106
|
+
if (e && e.code === "ENOENT") throw _err("NOT_FOUND", "key not found: " + key, true);
|
|
107
|
+
throw e;
|
|
88
108
|
}
|
|
89
|
-
return nodeFs.createReadStream(full);
|
|
109
|
+
return nodeFs.createReadStream(full, { fd: fd });
|
|
90
110
|
}
|
|
91
111
|
|
|
92
112
|
function head(key) {
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
*/
|
|
26
26
|
var nodeCrypto = require("node:crypto");
|
|
27
27
|
var { URL } = require("node:url");
|
|
28
|
-
var { Readable } = require("node:stream");
|
|
29
28
|
var safeXml = require("../parsers/safe-xml");
|
|
30
29
|
var sharedRequest = require("./http-request");
|
|
31
30
|
var C = require("../constants");
|
|
@@ -633,7 +632,7 @@ function create(config) {
|
|
|
633
632
|
}
|
|
634
633
|
|
|
635
634
|
function getStream(key, opts) {
|
|
636
|
-
return
|
|
635
|
+
return sharedRequest.promiseToStream(get(key, opts));
|
|
637
636
|
}
|
|
638
637
|
|
|
639
638
|
// getResponse(key, opts?) — full-fidelity GET. Returns
|
|
@@ -133,12 +133,27 @@ function _valueToOtlp(v) {
|
|
|
133
133
|
return { stringValue: String(v) };
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
// Run a single wire STRING (span name / status message) through the telemetry
|
|
137
|
+
// redactor. These reach the collector exactly like attribute values, so a
|
|
138
|
+
// connection string / token / PII in an error message (the tracer's canonical
|
|
139
|
+
// `setStatus("error", e.message)`) must be scrubbed too (CWE-532). Routes
|
|
140
|
+
// through redactAttrs (the same chokepoint attributes use); fails toward an
|
|
141
|
+
// empty string on a redactor throw, matching redactAttrs' drop-on-error.
|
|
142
|
+
function _redactWireString(key, value) {
|
|
143
|
+
if (typeof value !== "string" || value.length === 0) return value || "";
|
|
144
|
+
try {
|
|
145
|
+
var holder = {};
|
|
146
|
+
holder[key] = value;
|
|
147
|
+
return observability().redactAttrs(holder)[key];
|
|
148
|
+
} catch (_e) { return ""; }
|
|
149
|
+
}
|
|
150
|
+
|
|
136
151
|
function _spanToOtlp(span) {
|
|
137
152
|
return {
|
|
138
153
|
traceId: span.traceId,
|
|
139
154
|
spanId: span.spanId,
|
|
140
155
|
parentSpanId: span.parentSpanId || "",
|
|
141
|
-
name: span.name,
|
|
156
|
+
name: _redactWireString("otel.span.name", span.name),
|
|
142
157
|
kind: KIND_TO_OTLP[span.kind] || KIND_TO_OTLP.internal,
|
|
143
158
|
startTimeUnixNano: span.startTimeUnixNano,
|
|
144
159
|
endTimeUnixNano: span.endTimeUnixNano || span.startTimeUnixNano,
|
|
@@ -155,7 +170,7 @@ function _spanToOtlp(span) {
|
|
|
155
170
|
droppedEventsCount: span.droppedEventsCount || 0,
|
|
156
171
|
status: {
|
|
157
172
|
code: STATUS_CODE_TO_OTLP[span.status && span.status.code] || 0,
|
|
158
|
-
message: (span.status && span.status.message) || "",
|
|
173
|
+
message: _redactWireString("exception.message", (span.status && span.status.message) || ""),
|
|
159
174
|
},
|
|
160
175
|
};
|
|
161
176
|
}
|
|
@@ -336,7 +351,7 @@ function _attrsToProto(attrs) {
|
|
|
336
351
|
function _spanToProto(span) {
|
|
337
352
|
// Status code: 0=Unset, 1=Ok, 2=Error. Status field 1 is reserved.
|
|
338
353
|
var statusBody = Buffer.concat([
|
|
339
|
-
pb.string(2, (span.status && span.status.message) || ""),
|
|
354
|
+
pb.string(2, _redactWireString("exception.message", (span.status && span.status.message) || "")),
|
|
340
355
|
pb.uint32(3, STATUS_CODE_TO_OTLP[span.status && span.status.code] || 0),
|
|
341
356
|
]);
|
|
342
357
|
var eventsRepeated = pb.repeatedMessage(11, span.events || [], function (e) {
|
|
@@ -352,7 +367,7 @@ function _spanToProto(span) {
|
|
|
352
367
|
pb.bytes(2, _hexToBytes(span.spanId)),
|
|
353
368
|
pb.string(3, ""), // trace_state (not yet propagated by the framework)
|
|
354
369
|
pb.bytes(4, _hexToBytes(span.parentSpanId || "")),
|
|
355
|
-
pb.string(5, span.name || ""),
|
|
370
|
+
pb.string(5, _redactWireString("otel.span.name", span.name || "")),
|
|
356
371
|
pb.uint32(6, KIND_TEXT_TO_ENUM[span.kind] != null ? KIND_TEXT_TO_ENUM[span.kind] : KIND_TEXT_TO_ENUM.internal),
|
|
357
372
|
pb.fixed64(7, span.startTimeUnixNano || 0),
|
|
358
373
|
pb.fixed64(8, span.endTimeUnixNano || span.startTimeUnixNano || 0), // proto field number 8, not bytes
|
|
@@ -648,6 +663,7 @@ module.exports = {
|
|
|
648
663
|
OtlpExporterError: OtlpExporterError,
|
|
649
664
|
// Exported for tests
|
|
650
665
|
_spanToOtlp: _spanToOtlp,
|
|
666
|
+
_spanToProto: _spanToProto,
|
|
651
667
|
_bundleSpans: _bundleSpans,
|
|
652
668
|
_attrToOtlp: _attrToOtlp,
|
|
653
669
|
_BASE64URL_RE_REF: safeBuffer.BASE64URL_RE, // not used; reserved for OTLP/protobuf shape upgrade
|
|
@@ -375,11 +375,18 @@ function create(opts) {
|
|
|
375
375
|
{ name: "last_error", type: "TEXT" },
|
|
376
376
|
{ name: "status", type: "VARCHAR(16)", notNull: true, default: "pending" },
|
|
377
377
|
], { dialect: dialect }), dialect);
|
|
378
|
-
//
|
|
379
|
-
//
|
|
380
|
-
//
|
|
378
|
+
// Index for the publisher's claim path (scans status='pending' ORDER BY
|
|
379
|
+
// next_attempt_at). sqlite/postgres support a partial index (WHERE on
|
|
380
|
+
// CREATE INDEX) on next_attempt_at; MySQL does NOT — a WHERE there is a
|
|
381
|
+
// syntax error that made declareSchema() throw on MySQL — so fall back to a
|
|
382
|
+
// composite (status, next_attempt_at) index, which serves the same
|
|
383
|
+
// equality+range scan. The 'pending' literal is a builder-emitted static
|
|
384
|
+
// predicate, opted in via allowLiterals.
|
|
385
|
+
var idxCols = dialect === "mysql" ? ["status", "next_attempt_at"] : ["next_attempt_at"];
|
|
386
|
+
var idxOpts = { dialect: dialect };
|
|
387
|
+
if (dialect !== "mysql") idxOpts.where = "status = 'pending'";
|
|
381
388
|
var idx = sql.toExternalSql(sql.createIndex(opts.table + "_pending_idx", opts.table,
|
|
382
|
-
|
|
389
|
+
idxCols, idxOpts), dialect);
|
|
383
390
|
await target.query(ddl.sql, ddl.params);
|
|
384
391
|
await target.query(idx.sql, idx.params);
|
|
385
392
|
// Back-compat: an outbox table created before the claimed_at column
|
|
@@ -174,7 +174,7 @@ function parse(input, opts) {
|
|
|
174
174
|
}
|
|
175
175
|
out += String.fromCodePoint(code);
|
|
176
176
|
i = end + 1;
|
|
177
|
-
} else if (BUILT_IN_ENTITIES
|
|
177
|
+
} else if (Object.prototype.hasOwnProperty.call(BUILT_IN_ENTITIES, name)) {
|
|
178
178
|
out += BUILT_IN_ENTITIES[name];
|
|
179
179
|
i = end + 1;
|
|
180
180
|
} else {
|
|
@@ -771,9 +771,27 @@ function parse(input, opts) {
|
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
function _stripEolComment(text) {
|
|
774
|
-
// Strip ` #...` comments (must be preceded by
|
|
775
|
-
|
|
776
|
-
|
|
774
|
+
// Strip ` #...` comments (a YAML end-of-line comment must be preceded by
|
|
775
|
+
// whitespace) via a single linear scan. The previous /^(.*?)(\s+#.*)?$/
|
|
776
|
+
// backtracks polynomially on a long inline-whitespace run with no '#'
|
|
777
|
+
// (each position re-tries `\s+#`) — a ReDoS lever on attacker-supplied
|
|
778
|
+
// YAML. This finds the first whitespace-preceded '#' and cuts the
|
|
779
|
+
// preceding whitespace run, identical output without the catastrophic
|
|
780
|
+
// backtracking.
|
|
781
|
+
for (var i = 1; i < text.length; i++) {
|
|
782
|
+
if (text.charCodeAt(i) !== 0x23 /* # */) continue;
|
|
783
|
+
var prev = text.charCodeAt(i - 1);
|
|
784
|
+
// inline whitespace: space / tab / vtab / formfeed / CR
|
|
785
|
+
if (prev !== 0x20 && prev !== 0x09 && prev !== 0x0b && prev !== 0x0c && prev !== 0x0d) continue;
|
|
786
|
+
var end = i;
|
|
787
|
+
while (end > 0) {
|
|
788
|
+
var c = text.charCodeAt(end - 1);
|
|
789
|
+
if (c === 0x20 || c === 0x09 || c === 0x0b || c === 0x0c || c === 0x0d) end--;
|
|
790
|
+
else break;
|
|
791
|
+
}
|
|
792
|
+
return safeBuffer.stripTrailingHspace(text.slice(0, end));
|
|
793
|
+
}
|
|
794
|
+
return safeBuffer.stripTrailingHspace(text);
|
|
777
795
|
}
|
|
778
796
|
|
|
779
797
|
// ---- Block scalars (| literal, > folded) ----
|
|
@@ -406,7 +406,13 @@ function create(config) {
|
|
|
406
406
|
.where("_id", jobId)
|
|
407
407
|
.where("status", "inflight")
|
|
408
408
|
.toSql();
|
|
409
|
-
await store.execute(doneBuilt.sql, doneBuilt.params);
|
|
409
|
+
var doneRes = await store.execute(doneBuilt.sql, doneBuilt.params);
|
|
410
|
+
// Only run the post-completion side effects if THIS call actually flipped
|
|
411
|
+
// the row inflight→done. If the status guard matched 0 rows the job was
|
|
412
|
+
// already completed or re-leased to another worker (its lease expired and
|
|
413
|
+
// sweepExpired re-queued it) — a stale completer must NOT re-enqueue the
|
|
414
|
+
// cron repeat (duplicate firing) or release flow children twice.
|
|
415
|
+
if ((doneRes.rowCount || 0) === 0) return false;
|
|
410
416
|
|
|
411
417
|
// Repeat-in-queue: cron-recurring job re-enqueues itself for the
|
|
412
418
|
// next firing time. Failures (which take the fail() path) don't
|
|
@@ -513,9 +519,10 @@ function create(config) {
|
|
|
513
519
|
[nowMs + retryDelayMs])
|
|
514
520
|
.setRaw("finishedAt", "CASE WHEN " + attemptsLt + " THEN NULL ELSE ? END", [nowMs])
|
|
515
521
|
.where("_id", jobId)
|
|
522
|
+
.where("status", "inflight") // lease-ownership guard — a stale fail() must not clobber a job re-leased to another worker after this one's lease expired (mirrors complete()/extendLease)
|
|
516
523
|
.toSql();
|
|
517
|
-
await store.execute(failBuilt.sql, failBuilt.params);
|
|
518
|
-
return
|
|
524
|
+
var failRes = await store.execute(failBuilt.sql, failBuilt.params);
|
|
525
|
+
return (failRes.rowCount || 0) > 0;
|
|
519
526
|
}
|
|
520
527
|
|
|
521
528
|
async function sweepExpired() {
|
|
@@ -278,12 +278,16 @@ function redact(value, opts) {
|
|
|
278
278
|
function _redact(value, depth, maxDepth, marker, parentKey) {
|
|
279
279
|
if (depth > maxDepth) return marker;
|
|
280
280
|
if (value === null || value === undefined) return value;
|
|
281
|
+
// A sensitive parent key collapses the ENTIRE value — scalar OR composite —
|
|
282
|
+
// to the marker. Checking before the type branches is what stops a secret
|
|
283
|
+
// under e.g. `authorization: ["Bearer …"]` / `password: {…}` from slipping
|
|
284
|
+
// through the array/object branches (which recurse with parentKey=null), the
|
|
285
|
+
// way a scalar already does (CWE-532 telemetry egress).
|
|
286
|
+
if (parentKey && _isSensitiveFieldName(parentKey)) return marker;
|
|
281
287
|
if (typeof value === "string") {
|
|
282
|
-
if (parentKey && _isSensitiveFieldName(parentKey)) return marker;
|
|
283
288
|
return _redactValue(value);
|
|
284
289
|
}
|
|
285
290
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
286
|
-
if (parentKey && _isSensitiveFieldName(parentKey)) return marker;
|
|
287
291
|
return value;
|
|
288
292
|
}
|
|
289
293
|
if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
|
|
@@ -513,7 +517,7 @@ function classifyDefaults(opts) {
|
|
|
513
517
|
"redact.classifyDefaults: patterns[" + p + "] must be a string, got " +
|
|
514
518
|
typeof patterns[p]);
|
|
515
519
|
}
|
|
516
|
-
if (!CLASSIFIER_PATTERNS
|
|
520
|
+
if (!Object.prototype.hasOwnProperty.call(CLASSIFIER_PATTERNS, patterns[p]) &&
|
|
517
521
|
!(opts.extra && opts.extra[patterns[p]])) {
|
|
518
522
|
throw new DlpError("redact-dlp/unknown-pattern",
|
|
519
523
|
"redact.classifyDefaults: unknown pattern '" + patterns[p] +
|