@blamejs/blamejs-shop 0.4.31 → 0.4.32
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/asset-manifest.json +1 -1
- package/lib/vendor/MANIFEST.json +392 -278
- package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
- package/lib/vendor/blamejs/.gitignore +6 -0
- package/lib/vendor/blamejs/CHANGELOG.md +26 -0
- package/lib/vendor/blamejs/MIGRATING.md +43 -0
- package/lib/vendor/blamejs/README.md +8 -6
- package/lib/vendor/blamejs/SECURITY.md +19 -3
- package/lib/vendor/blamejs/api-snapshot.json +2190 -664
- package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
- package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
- package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
- package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
- package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
- package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
- package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
- package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
- package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
- package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
- package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
- package/lib/vendor/blamejs/index.js +4 -0
- package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
- package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
- package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
- package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
- package/lib/vendor/blamejs/lib/api-key.js +158 -77
- package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
- package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
- package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
- package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
- package/lib/vendor/blamejs/lib/audit.js +259 -123
- package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
- package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
- package/lib/vendor/blamejs/lib/backup/index.js +45 -10
- package/lib/vendor/blamejs/lib/break-glass.js +355 -147
- package/lib/vendor/blamejs/lib/cache.js +174 -105
- package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
- package/lib/vendor/blamejs/lib/cli.js +19 -14
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
- package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
- package/lib/vendor/blamejs/lib/cluster.js +119 -71
- package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
- package/lib/vendor/blamejs/lib/compliance.js +206 -4
- package/lib/vendor/blamejs/lib/consent.js +82 -29
- package/lib/vendor/blamejs/lib/constants.js +27 -11
- package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
- package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
- package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
- package/lib/vendor/blamejs/lib/db-query.js +882 -260
- package/lib/vendor/blamejs/lib/db-schema.js +228 -44
- package/lib/vendor/blamejs/lib/db.js +249 -99
- package/lib/vendor/blamejs/lib/dsr.js +385 -55
- package/lib/vendor/blamejs/lib/error-page.js +14 -1
- package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
- package/lib/vendor/blamejs/lib/external-db.js +549 -34
- package/lib/vendor/blamejs/lib/file-upload.js +52 -7
- package/lib/vendor/blamejs/lib/framework-error.js +20 -1
- package/lib/vendor/blamejs/lib/framework-files.js +73 -0
- package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
- package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
- package/lib/vendor/blamejs/lib/guard-all.js +1 -0
- package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
- package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
- package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
- package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
- package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
- package/lib/vendor/blamejs/lib/guard-email.js +47 -69
- package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
- package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
- package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
- package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
- package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
- package/lib/vendor/blamejs/lib/guard-html.js +53 -108
- package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
- package/lib/vendor/blamejs/lib/guard-image.js +46 -103
- package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
- package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
- package/lib/vendor/blamejs/lib/guard-json.js +38 -108
- package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
- package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
- package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
- package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
- package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
- package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
- package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
- package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
- package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
- package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
- package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
- package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
- package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
- package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
- package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
- package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
- package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
- package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
- package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
- package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
- package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
- package/lib/vendor/blamejs/lib/guard-template.js +35 -172
- package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
- package/lib/vendor/blamejs/lib/guard-time.js +32 -154
- package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
- package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
- package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
- package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
- package/lib/vendor/blamejs/lib/http-client.js +37 -9
- package/lib/vendor/blamejs/lib/inbox.js +120 -107
- package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
- package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
- package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
- package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
- package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
- package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
- package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
- package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
- package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
- package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
- package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
- package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
- package/lib/vendor/blamejs/lib/mail-store.js +293 -154
- package/lib/vendor/blamejs/lib/mail.js +8 -4
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
- package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
- package/lib/vendor/blamejs/lib/migrations.js +108 -66
- package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
- package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
- package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
- package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
- package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
- package/lib/vendor/blamejs/lib/observability.js +124 -0
- package/lib/vendor/blamejs/lib/otel-export.js +12 -3
- package/lib/vendor/blamejs/lib/outbox.js +184 -83
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
- package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
- package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
- package/lib/vendor/blamejs/lib/queue-local.js +225 -140
- package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
- package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
- package/lib/vendor/blamejs/lib/queue.js +7 -0
- package/lib/vendor/blamejs/lib/redact.js +68 -11
- package/lib/vendor/blamejs/lib/redis-client.js +160 -31
- package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
- package/lib/vendor/blamejs/lib/retention.js +101 -40
- package/lib/vendor/blamejs/lib/router.js +212 -5
- package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
- package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
- package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
- package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
- package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
- package/lib/vendor/blamejs/lib/safe-url.js +170 -3
- package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
- package/lib/vendor/blamejs/lib/scheduler.js +35 -12
- package/lib/vendor/blamejs/lib/seeders.js +122 -74
- package/lib/vendor/blamejs/lib/session-stores.js +42 -14
- package/lib/vendor/blamejs/lib/session.js +175 -77
- package/lib/vendor/blamejs/lib/sql.js +3842 -0
- package/lib/vendor/blamejs/lib/sse.js +26 -0
- package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
- package/lib/vendor/blamejs/lib/static.js +177 -34
- package/lib/vendor/blamejs/lib/subject.js +96 -49
- package/lib/vendor/blamejs/lib/vault/index.js +3 -2
- package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
- package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
- package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
- package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
- package/lib/vendor/blamejs/lib/websocket.js +35 -5
- package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
- package/lib/vendor/blamejs/package.json +2 -2
- package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
- package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
- package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
- package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
- package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
- package/lib/vendor/blamejs/scripts/check-services.js +21 -0
- package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
- package/lib/vendor/blamejs/scripts/release.js +398 -38
- package/lib/vendor/blamejs/test/00-primitives.js +117 -0
- package/lib/vendor/blamejs/test/10-state.js +140 -14
- package/lib/vendor/blamejs/test/20-db.js +65 -2
- package/lib/vendor/blamejs/test/helpers/db.js +9 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
- package/lib/vendor/blamejs/test/helpers/services.js +21 -0
- package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
- package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
- package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
- package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
- package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
- package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
- package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
- package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
- package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
- package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
- package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
- package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
- package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
- package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
- package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
- package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
- package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
- package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
- package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
- package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
- package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
- package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
- package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
- package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
- package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
- package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
- package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
- package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
- package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
- package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
- package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
- package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
- package/lib/vendor/blamejs/test/smoke.js +79 -21
- package/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
- package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
- package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
- package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
- package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
- package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
- package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
- package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
- package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
- package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
- package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
- package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
- package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
- package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
- package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
- package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
- package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
- package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
- package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
- package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
- package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
- package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
|
@@ -1944,15 +1944,19 @@ module.exports = {
|
|
|
1944
1944
|
// default, ed25519-sha256 opt-in). Wire it into the smtp transport
|
|
1945
1945
|
// via opts.dkimSigner. See lib/mail-dkim.js for the full surface.
|
|
1946
1946
|
dkim: dkim,
|
|
1947
|
-
// Inbound mail authentication
|
|
1948
|
-
//
|
|
1949
|
-
//
|
|
1950
|
-
//
|
|
1947
|
+
// Inbound mail authentication verification: SPF (RFC 7208), DKIM
|
|
1948
|
+
// verify (RFC 6376, on .dkim above alongside outbound signing),
|
|
1949
|
+
// DMARC (RFC 7489), ARC (RFC 8617). `.inbound.verify` is the
|
|
1950
|
+
// one-call receiver pipeline — SPF + DKIM + From-header extraction +
|
|
1951
|
+
// DMARC policy + the RFC 8601 Authentication-Results header —
|
|
1952
|
+
// composed by b.mail.server.mx at DATA time via its guardEnvelope
|
|
1953
|
+
// opt and callable directly by operator-built listeners.
|
|
1951
1954
|
spf: mailAuth.spf,
|
|
1952
1955
|
dmarc: mailAuth.dmarc,
|
|
1953
1956
|
arc: mailAuth.arc,
|
|
1954
1957
|
iprev: mailAuth.iprev,
|
|
1955
1958
|
authResults: mailAuth.authResults,
|
|
1959
|
+
inbound: mailAuth.inbound,
|
|
1956
1960
|
bimi: mailBimi,
|
|
1957
1961
|
// Test-only export: lets unit tests inspect the wire format without
|
|
1958
1962
|
// standing up a TLS-capable SMTP fixture. Operators don't call this.
|
|
@@ -166,6 +166,29 @@ var BodyParserError = defineClass("BodyParserError", { withStatusCode: true });
|
|
|
166
166
|
// in play — consistent prototype-pollution defense across the framework.
|
|
167
167
|
var POISONED_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
168
168
|
|
|
169
|
+
// Materialize a header/parameter map from request-derived [key, value]
|
|
170
|
+
// pairs WITHOUT a computed member write (`target[key] = value`). A
|
|
171
|
+
// request-keyed computed write is the CWE-915 unsafe-reflection /
|
|
172
|
+
// CWE-1321 prototype-pollution sink: an attacker who controls the key
|
|
173
|
+
// (Content-Type parameter name, multipart part-header name,
|
|
174
|
+
// Content-Disposition parameter name) can target `__proto__` /
|
|
175
|
+
// `constructor` / `prototype` and corrupt the prototype chain. Poisoned
|
|
176
|
+
// keys are dropped, the remaining pairs are funneled through
|
|
177
|
+
// `Object.fromEntries`, and the result carries no prototype chain
|
|
178
|
+
// (`Object.create(null)`) so even a key that slipped a future POISONED_KEYS
|
|
179
|
+
// gap cannot reach Object.prototype. The returned map has plain-object
|
|
180
|
+
// shape (string keys → values) so existing named-property reads
|
|
181
|
+
// (`.boundary`, `.charset`, `["content-disposition"]`, `.name`,
|
|
182
|
+
// `.filename`) are unchanged.
|
|
183
|
+
function _mapFromPairs(pairs) {
|
|
184
|
+
var safe = [];
|
|
185
|
+
for (var i = 0; i < pairs.length; i++) {
|
|
186
|
+
if (POISONED_KEYS.has(pairs[i][0])) continue;
|
|
187
|
+
safe.push(pairs[i]);
|
|
188
|
+
}
|
|
189
|
+
return Object.assign(Object.create(null), Object.fromEntries(safe));
|
|
190
|
+
}
|
|
191
|
+
|
|
169
192
|
// ---- defaults ----
|
|
170
193
|
|
|
171
194
|
var DEFAULTS = Object.freeze({
|
|
@@ -221,7 +244,11 @@ function _contentType(req) {
|
|
|
221
244
|
if (typeof ct !== "string") return { type: "", params: {} };
|
|
222
245
|
var idx = ct.indexOf(";");
|
|
223
246
|
var type = (idx === -1 ? ct : ct.slice(0, idx)).trim().toLowerCase();
|
|
224
|
-
|
|
247
|
+
// Collect [name, value] pairs, then materialize via _mapFromPairs so a
|
|
248
|
+
// request-controlled parameter name (e.g. `boundary` / `charset` / an
|
|
249
|
+
// attacker-supplied `__proto__`) is never used as a computed-write key
|
|
250
|
+
// (CWE-915 / CWE-1321). Poisoned names are dropped at materialization.
|
|
251
|
+
var paramPairs = [];
|
|
225
252
|
if (idx !== -1) {
|
|
226
253
|
var rest = ct.slice(idx + 1);
|
|
227
254
|
// RFC 9110 §8.3 + §5.6.6 — parameter values may be quoted-string
|
|
@@ -238,10 +265,10 @@ function _contentType(req) {
|
|
|
238
265
|
var v = p.slice(eq + 1).trim();
|
|
239
266
|
var _unq = structuredFields.unquoteSfString(v);
|
|
240
267
|
if (_unq !== null) v = _unq;
|
|
241
|
-
|
|
268
|
+
paramPairs.push([k, v]);
|
|
242
269
|
}
|
|
243
270
|
}
|
|
244
|
-
return { type: type, params:
|
|
271
|
+
return { type: type, params: _mapFromPairs(paramPairs) };
|
|
245
272
|
}
|
|
246
273
|
|
|
247
274
|
function _typeMatches(actual, allowed) {
|
|
@@ -583,7 +610,13 @@ function _parseMultipartHeaders(rawHeaders) {
|
|
|
583
610
|
// §5.5 — header field values MUST NOT contain CR, LF, or NUL bytes.
|
|
584
611
|
// We refuse the part outright (caller surfaces the throw as 400 + drop).
|
|
585
612
|
var lines = rawHeaders.split("\r\n");
|
|
586
|
-
|
|
613
|
+
// Collect [name, value] pairs; materialize via _mapFromPairs so the
|
|
614
|
+
// request-controlled header name is never a computed-write key
|
|
615
|
+
// (CWE-915 / CWE-1321 — a part header literally named `__proto__` would
|
|
616
|
+
// otherwise pollute the prototype chain). Later headers of the same
|
|
617
|
+
// name keep last-wins (the prior `out[k] = v` overwrite semantics:
|
|
618
|
+
// Object.fromEntries takes the last pair for a duplicate key).
|
|
619
|
+
var headerPairs = [];
|
|
587
620
|
for (var i = 0; i < lines.length; i++) {
|
|
588
621
|
var line = lines[i];
|
|
589
622
|
if (!line) continue;
|
|
@@ -609,9 +642,9 @@ function _parseMultipartHeaders(rawHeaders) {
|
|
|
609
642
|
);
|
|
610
643
|
}
|
|
611
644
|
}
|
|
612
|
-
|
|
645
|
+
headerPairs.push([k, v]);
|
|
613
646
|
}
|
|
614
|
-
return
|
|
647
|
+
return _mapFromPairs(headerPairs);
|
|
615
648
|
}
|
|
616
649
|
|
|
617
650
|
// Percent-decode an RFC 5987 ext-value's value segment under iso-8859-1.
|
|
@@ -672,14 +705,20 @@ function _parseHeaderParams(headerValue, filenameCharsets) {
|
|
|
672
705
|
// is present, it takes precedence over the legacy `filename=`
|
|
673
706
|
// companion (RFC 6266 §4.3). We surface the decoded value at
|
|
674
707
|
// `filename` so downstream consumers don't need parser-aware code.
|
|
675
|
-
|
|
676
|
-
if (!headerValue) return out;
|
|
708
|
+
if (!headerValue) return _mapFromPairs([["_value", ""]]);
|
|
677
709
|
// RFC 6266 §4.1 + RFC 9110 §5.6.6 — parameter values may be
|
|
678
710
|
// quoted-string (e.g. `filename="weird;name.txt"`). Bare
|
|
679
711
|
// `.split(";")` would slice through the quoted semicolon and
|
|
680
712
|
// corrupt the filename. Quote-aware shared splitter.
|
|
681
713
|
var parts = structuredFields.splitTopLevel(headerValue, ";");
|
|
682
|
-
|
|
714
|
+
// Collect [name, value] pairs, then materialize via _mapFromPairs so a
|
|
715
|
+
// request-controlled Content-Disposition parameter name (or its
|
|
716
|
+
// ext-value `name*` bare form) is never a computed-write key
|
|
717
|
+
// (CWE-915 / CWE-1321). `_value` carries the disposition type;
|
|
718
|
+
// `filename` (when an ext-value decoded) takes precedence over the
|
|
719
|
+
// legacy `filename=` companion (RFC 6266 §4.3), preserved by appending
|
|
720
|
+
// it last so Object.fromEntries' last-wins resolves it.
|
|
721
|
+
var paramPairs = [["_value", parts[0].trim().toLowerCase()]];
|
|
683
722
|
var extName = null;
|
|
684
723
|
for (var i = 1; i < parts.length; i++) {
|
|
685
724
|
var p = parts[i].trim();
|
|
@@ -694,14 +733,14 @@ function _parseHeaderParams(headerValue, filenameCharsets) {
|
|
|
694
733
|
if (decoded !== null) {
|
|
695
734
|
var bareKey = k.slice(0, -1);
|
|
696
735
|
if (bareKey === "filename") extName = decoded;
|
|
697
|
-
|
|
736
|
+
paramPairs.push([bareKey, decoded]);
|
|
698
737
|
}
|
|
699
738
|
continue;
|
|
700
739
|
}
|
|
701
|
-
|
|
740
|
+
paramPairs.push([k, v]);
|
|
702
741
|
}
|
|
703
|
-
if (extName !== null)
|
|
704
|
-
return
|
|
742
|
+
if (extName !== null) paramPairs.push(["filename", extName]);
|
|
743
|
+
return _mapFromPairs(paramPairs);
|
|
705
744
|
}
|
|
706
745
|
|
|
707
746
|
async function _parseMultipart(req, opts, ctParams) {
|
|
@@ -1173,20 +1212,27 @@ async function _parseMultipart(req, opts, ctParams) {
|
|
|
1173
1212
|
var fbuf = Buffer.concat(currentBuf);
|
|
1174
1213
|
var text = fbuf.toString("utf8");
|
|
1175
1214
|
// Repeated field name → array, matching urlencoded parser.
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1215
|
+
// `currentField` is request-controlled, so the accumulation
|
|
1216
|
+
// never uses it as a computed-write key (`fields[key] = v`),
|
|
1217
|
+
// which is the CWE-915 / CWE-1321 sink: it is merged through
|
|
1218
|
+
// Object.fromEntries + Object.assign instead. The upstream
|
|
1219
|
+
// POISONED_KEYS gate (the multipart-poisoned-field check above)
|
|
1220
|
+
// already rejects __proto__ / constructor / prototype field
|
|
1221
|
+
// names with a 400 before reaching here; the entries-merge is
|
|
1222
|
+
// the structural backstop.
|
|
1223
|
+
var fieldName = currentField;
|
|
1224
|
+
var prior = Object.prototype.hasOwnProperty.call(fields, fieldName)
|
|
1225
|
+
? fields[fieldName] : undefined;
|
|
1226
|
+
var nextValue;
|
|
1227
|
+
if (prior === undefined) {
|
|
1228
|
+
nextValue = text;
|
|
1229
|
+
} else if (Array.isArray(prior)) {
|
|
1230
|
+
prior.push(text);
|
|
1231
|
+
nextValue = prior;
|
|
1185
1232
|
} else {
|
|
1186
|
-
|
|
1187
|
-
// gate at lib/middleware/body-parser.js:867.
|
|
1188
|
-
fields[currentField] = text;
|
|
1233
|
+
nextValue = [prior, text];
|
|
1189
1234
|
}
|
|
1235
|
+
Object.assign(fields, Object.fromEntries([[fieldName, nextValue]]));
|
|
1190
1236
|
}
|
|
1191
1237
|
currentHeaders = null;
|
|
1192
1238
|
currentField = null;
|
|
@@ -91,25 +91,36 @@ function _parseCookieHeader(header) {
|
|
|
91
91
|
// just splits the name=value pairs. Keys that appear multiple times
|
|
92
92
|
// resolve to the FIRST occurrence (browsers send pairs left-to-right
|
|
93
93
|
// by registration order; the first is the most-specific path).
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
// Collect [name, value] pairs, then materialize the cookie map via
|
|
95
|
+
// Object.fromEntries onto a null-prototype object. The cookie name is
|
|
96
|
+
// attacker-controlled (Cookie request header), so it is never used as a
|
|
97
|
+
// computed-write key (`out[name] = value` / `seen[name] = true`) — that
|
|
98
|
+
// is the CWE-915 unsafe-reflection / CWE-1321 prototype-pollution sink.
|
|
99
|
+
// First-occurrence-wins de-duplication tracks names in a Set (add/has
|
|
100
|
+
// are method calls, not tainted-key property writes); POISONED names
|
|
101
|
+
// (`__proto__` / `constructor` / `prototype`) are dropped; and the
|
|
102
|
+
// null-prototype accumulator means even a slipped name cannot reach
|
|
103
|
+
// Object.prototype.
|
|
104
|
+
if (typeof header !== "string" || header.length === 0) return Object.create(null);
|
|
99
105
|
var parts = header.split(/;\s*/);
|
|
106
|
+
var seen = new Set();
|
|
107
|
+
var pairs = [];
|
|
100
108
|
for (var i = 0; i < parts.length; i++) {
|
|
101
109
|
var p = parts[i];
|
|
102
110
|
var eq = p.indexOf("=");
|
|
103
111
|
if (eq === -1) continue;
|
|
104
112
|
var k = p.slice(0, eq).trim();
|
|
105
|
-
if (k.length === 0
|
|
113
|
+
if (k.length === 0) continue;
|
|
114
|
+
if (k === "__proto__" || k === "constructor" || k === "prototype") continue;
|
|
115
|
+
if (seen.has(k)) continue; // first-occurrence wins
|
|
116
|
+
seen.add(k);
|
|
106
117
|
var v = p.slice(eq + 1).trim();
|
|
107
118
|
if (v.length >= 2 && v.charCodeAt(0) === 0x22 && v.charCodeAt(v.length - 1) === 0x22) {
|
|
108
119
|
v = v.slice(1, -1);
|
|
109
120
|
}
|
|
110
|
-
|
|
121
|
+
pairs.push([k, v]);
|
|
111
122
|
}
|
|
112
|
-
return
|
|
123
|
+
return Object.assign(Object.create(null), Object.fromEntries(pairs));
|
|
113
124
|
}
|
|
114
125
|
|
|
115
126
|
// `_isHttps` defers to `requestHelpers.requestProtocol` so the
|
|
@@ -239,6 +239,15 @@ function create(opts) {
|
|
|
239
239
|
var auditOn = opts.audit !== false;
|
|
240
240
|
var algorithms = opts.algorithms;
|
|
241
241
|
var iatWindowSec = opts.iatWindowSec;
|
|
242
|
+
// replayStore is the jti-replay defense (RFC 9449 §11.1) — REQUIRED. Reading
|
|
243
|
+
// it optionally and gating the check behind `if (replayStore)` would silently
|
|
244
|
+
// mount a proof-of-possession gate that performs no replay check, letting a
|
|
245
|
+
// captured proof replay indefinitely. Fail closed at config time: a missing
|
|
246
|
+
// store and a store lacking checkAndInsert both throw here, not at the first
|
|
247
|
+
// request. (The low-level b.auth.dpop.verify primitive keeps replayStore
|
|
248
|
+
// optional for advanced callers that track jti themselves.)
|
|
249
|
+
validateOpts.requireMethods(opts.replayStore, ["checkAndInsert"],
|
|
250
|
+
"middleware.dpop: opts.replayStore", AuthError, "auth-dpop/replay-store-required");
|
|
242
251
|
var replayStore = opts.replayStore;
|
|
243
252
|
var requireNonce = opts.requireNonce === true;
|
|
244
253
|
|
|
@@ -328,7 +337,7 @@ function create(opts) {
|
|
|
328
337
|
if (iatWindowSec !== undefined) verifyOpts.iatWindowSec = iatWindowSec;
|
|
329
338
|
if (accessToken) verifyOpts.accessToken = accessToken;
|
|
330
339
|
if (nonce) verifyOpts.nonce = nonce;
|
|
331
|
-
|
|
340
|
+
verifyOpts.replayStore = replayStore; // required at create() — always present
|
|
332
341
|
|
|
333
342
|
var result;
|
|
334
343
|
try { result = await dpop().verify(proofHeader, verifyOpts); }
|
|
@@ -125,11 +125,13 @@ function _writeReject(req, res, message, reason, onDeny, problemMode) {
|
|
|
125
125
|
* destination list, including `webidentity` (FedCM credentialed
|
|
126
126
|
* requests). `deniedDest` refuses chosen destinations outright on the
|
|
127
127
|
* gated methods — a FedCM `webidentity` Sec-Fetch-Dest hitting a route
|
|
128
|
-
* that is not an identity endpoint is refused.
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
128
|
+
* that is not an identity endpoint is refused. The Storage Access API
|
|
129
|
+
* escalation (a cross-site request carrying `Sec-Fetch-Storage-Access:
|
|
130
|
+
* active` / `inactive`) is REFUSED BY DEFAULT (v0.15.0) on routes that do
|
|
131
|
+
* not participate in the Storage Access flow; operators running an
|
|
132
|
+
* embedded-iframe SaaS that legitimately uses the API opt back in with
|
|
133
|
+
* `allowStorageAccess: true`. `deniedDest` stays opt-in (unset = no
|
|
134
|
+
* destination is denied outright).
|
|
133
135
|
*
|
|
134
136
|
* @opts
|
|
135
137
|
* {
|
|
@@ -138,7 +140,7 @@ function _writeReject(req, res, message, reason, onDeny, problemMode) {
|
|
|
138
140
|
* allowMissing: boolean, // default true
|
|
139
141
|
* allowedDest: string[], // cross-site allowlist of Sec-Fetch-Dest values
|
|
140
142
|
* deniedDest: string[], // Sec-Fetch-Dest values refused on gated methods regardless of site (e.g. ["webidentity"])
|
|
141
|
-
* allowStorageAccess: boolean, // default
|
|
143
|
+
* allowStorageAccess: boolean, // default false — refuses Sec-Fetch-Storage-Access: active|inactive; pass true to opt back in for Storage-Access-flow routes
|
|
142
144
|
* strictDest: boolean, // default false — true throws at config time on an allowedDest/deniedDest value outside the known Sec-Fetch-Dest vocabulary
|
|
143
145
|
* allowedNavigate: boolean, // default true
|
|
144
146
|
* methods: string[], // default POST/PUT/DELETE/PATCH
|
|
@@ -178,7 +180,15 @@ function create(opts) {
|
|
|
178
180
|
var allowCrossSite = opts.allowCrossSite === true;
|
|
179
181
|
var allowMissing = opts.allowMissing !== false;
|
|
180
182
|
var allowedDest = Array.isArray(opts.allowedDest) ? opts.allowedDest.slice() : null;
|
|
181
|
-
|
|
183
|
+
// Storage Access escalation default-deny (v0.15.0): a cross-site
|
|
184
|
+
// credentialed request carrying Sec-Fetch-Storage-Access: active|inactive
|
|
185
|
+
// is REFUSED by default on the gated methods, because that header signals
|
|
186
|
+
// the embedded context can reach unpartitioned cross-site cookies — a
|
|
187
|
+
// capability a route that does not participate in the Storage Access flow
|
|
188
|
+
// should not silently honor. Operators running an embedded-iframe SaaS
|
|
189
|
+
// that legitimately uses the Storage Access API opt back in with
|
|
190
|
+
// allowStorageAccess: true.
|
|
191
|
+
var allowStorageAccess = opts.allowStorageAccess === true;
|
|
182
192
|
// deniedDest → a null-prototype membership map; an operator-supplied
|
|
183
193
|
// destination string is never assigned onto a plain object, so no
|
|
184
194
|
// reserved name (__proto__ / constructor / prototype) can pollute it.
|
|
@@ -47,6 +47,7 @@ var validateOpts = require("../validate-opts");
|
|
|
47
47
|
var safeBuffer = require("../safe-buffer");
|
|
48
48
|
var safeJson = require("../safe-json");
|
|
49
49
|
var safeSql = require("../safe-sql");
|
|
50
|
+
var sql = require("../sql");
|
|
50
51
|
var bCrypto = require("../crypto");
|
|
51
52
|
var cryptoField = require("../crypto-field");
|
|
52
53
|
var vault = require("../vault");
|
|
@@ -250,17 +251,23 @@ function dbStore(opts) {
|
|
|
250
251
|
"dbStore: opts.db must be a sqlite-shaped database with a `prepare(sql)` method", true);
|
|
251
252
|
}
|
|
252
253
|
var tableNameRaw = opts.tableName !== undefined ? opts.tableName : "blamejs_idempotency_keys";
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
// Validate the operator-supplied table name up front so a bad
|
|
255
|
+
// identifier fails at construction with the stable
|
|
256
|
+
// idempotency/bad-table-name code (b.sql would otherwise raise its own
|
|
257
|
+
// SqlBuilderError deeper in the first build). b.sql then quotes the
|
|
258
|
+
// name by construction in every statement it emits for this store
|
|
259
|
+
// (quoteName:true — this is a direct sqlite handle, not a
|
|
260
|
+
// clusterStorage rewrite target, so the name is quoted, not left bare).
|
|
261
|
+
try { safeSql.validateIdentifier(tableNameRaw, { allowReserved: true }); }
|
|
258
262
|
catch (sqlErr) {
|
|
259
263
|
throw new IdempotencyError("idempotency/bad-table-name",
|
|
260
264
|
"dbStore: opts.tableName is not a valid SQL identifier: " +
|
|
261
265
|
(sqlErr && sqlErr.message ? sqlErr.message : String(sqlErr)), true);
|
|
262
266
|
}
|
|
263
|
-
|
|
267
|
+
// b.sql opts for every statement this store builds against the local
|
|
268
|
+
// sqlite handle: sqlite dialect (native `?` placeholders, double-quoted
|
|
269
|
+
// identifiers) + quoteName so the operator table name is emitted quoted.
|
|
270
|
+
var sqlOpts = { dialect: "sqlite", quoteName: true };
|
|
264
271
|
var doInit = opts.init !== false;
|
|
265
272
|
var hashKeys = opts.hashKeys !== false;
|
|
266
273
|
var sealReq = opts.seal !== false;
|
|
@@ -309,63 +316,79 @@ function dbStore(opts) {
|
|
|
309
316
|
});
|
|
310
317
|
}
|
|
311
318
|
|
|
312
|
-
// Derive a per-vault HMAC secret for fingerprint sealing.
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
//
|
|
319
|
+
// Derive a per-vault HMAC secret for fingerprint sealing. Seed off the
|
|
320
|
+
// SEALED per-deployment MAC key (vault.getDerivedHashMacKey, sealed at
|
|
321
|
+
// rest under the vault root) — NOT getDerivedHashSalt, which sits in
|
|
322
|
+
// PLAINTEXT on disk. With the salt-derived seed an attacker who read
|
|
323
|
+
// the disk could recompute the HMAC key and forge / correlate request
|
|
324
|
+
// fingerprints; the sealed MAC key closes that (the vault root is the
|
|
325
|
+
// trust root, so the secret is unrecoverable without it). Lazy: only
|
|
326
|
+
// derived when fpSealOn is enabled AND the vault is ready, so test
|
|
327
|
+
// fixtures that haven't initialized the vault still construct a
|
|
328
|
+
// dbStore (the fingerprint then falls back to bare sha3-256 with a
|
|
329
|
+
// single audit warning).
|
|
318
330
|
var fpHmacSecret = null;
|
|
319
331
|
if (fpSealOn) {
|
|
320
332
|
try {
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
333
|
+
// The MAC key is per-deployment + sealed, so the same dbStore
|
|
334
|
+
// instance across hosts converges on the same HMAC key while disk
|
|
335
|
+
// access alone cannot recover it. The table name domain-separates
|
|
336
|
+
// the fingerprint secret from other consumers of the MAC key.
|
|
337
|
+
var fpDeriveInput = Buffer.concat([
|
|
338
|
+
vault.getDerivedHashMacKey(),
|
|
339
|
+
Buffer.from("idempotency.fingerprint:" + tableNameRaw, "utf8"),
|
|
340
|
+
]);
|
|
341
|
+
fpHmacSecret = bCrypto.kdf(fpDeriveInput, C.BYTES.bytes(32));
|
|
327
342
|
} catch (_fpErr) {
|
|
328
343
|
_emitAudit("idempotency.fingerprint_seal_skipped_no_vault",
|
|
329
344
|
{ tableName: tableNameRaw,
|
|
330
|
-
reason: "vault.
|
|
345
|
+
reason: "vault.getDerivedHashMacKey() unavailable; fingerprint falls back to plain sha3-256" },
|
|
331
346
|
"warning");
|
|
332
347
|
fpHmacSecret = null;
|
|
333
348
|
}
|
|
334
349
|
}
|
|
335
350
|
|
|
336
351
|
if (doInit) {
|
|
337
|
-
db.prepare(
|
|
338
|
-
"k
|
|
339
|
-
"fingerprint
|
|
340
|
-
"status_code
|
|
341
|
-
"headers
|
|
342
|
-
"body
|
|
343
|
-
"expires_at
|
|
344
|
-
|
|
345
|
-
|
|
352
|
+
db.prepare(sql.createTable(tableNameRaw, [
|
|
353
|
+
{ name: "k", type: "text", primaryKey: true },
|
|
354
|
+
{ name: "fingerprint", type: "text", notNull: true },
|
|
355
|
+
{ name: "status_code", type: "int", notNull: true },
|
|
356
|
+
{ name: "headers", type: "text", notNull: true },
|
|
357
|
+
{ name: "body", type: "text", notNull: true },
|
|
358
|
+
{ name: "expires_at", type: "int", notNull: true },
|
|
359
|
+
], sqlOpts).sql).run();
|
|
360
|
+
db.prepare(sql.createIndex(tableNameRaw + "_expires_idx", tableNameRaw,
|
|
361
|
+
["expires_at"], sqlOpts).sql).run();
|
|
346
362
|
}
|
|
347
363
|
|
|
348
|
-
// Prepared statements.
|
|
349
|
-
//
|
|
350
|
-
//
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
"
|
|
360
|
-
"
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
"
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
"
|
|
368
|
-
|
|
364
|
+
// Prepared statements, composed once through b.sql and reused per call.
|
|
365
|
+
// b.sql binds concrete values into a params array; for a reusable
|
|
366
|
+
// prepared statement we keep only the emitted SQL text (its `?`
|
|
367
|
+
// placeholders) and bind fresh values at run time, so a build-time
|
|
368
|
+
// sentinel value is just a placeholder slot. status_code + expires_at
|
|
369
|
+
// stay non-sealed so audit/forensic SELECTs don't have to unseal-
|
|
370
|
+
// everything. The `k` column is selected even when not strictly needed
|
|
371
|
+
// for read because cryptoField.unsealRow uses it as the rowId in AAD
|
|
372
|
+
// when the table is AAD-bound.
|
|
373
|
+
var _slot = 0; // sentinel bind value; the prepared statement rebinds at call time
|
|
374
|
+
var stmtGet = db.prepare(sql.select(tableNameRaw, sqlOpts)
|
|
375
|
+
.columns(["k", "fingerprint", "status_code", "headers", "body", "expires_at"])
|
|
376
|
+
.where("k", _slot)
|
|
377
|
+
.toSql().sql);
|
|
378
|
+
var stmtUpsert = db.prepare(sql.upsert(tableNameRaw, sqlOpts)
|
|
379
|
+
.columns(["k", "fingerprint", "status_code", "headers", "body", "expires_at"])
|
|
380
|
+
.values({ k: _slot, fingerprint: _slot, status_code: _slot,
|
|
381
|
+
headers: _slot, body: _slot, expires_at: _slot })
|
|
382
|
+
.onConflict(["k"])
|
|
383
|
+
.doUpdateFromExcluded(["fingerprint", "status_code", "headers", "body", "expires_at"])
|
|
384
|
+
.toSql().sql);
|
|
385
|
+
var stmtDeleteStale = db.prepare(sql.delete(tableNameRaw, sqlOpts)
|
|
386
|
+
.where("k", _slot)
|
|
387
|
+
.where("expires_at", "<=", _slot)
|
|
388
|
+
.toSql().sql);
|
|
389
|
+
var stmtDelete = db.prepare(sql.delete(tableNameRaw, sqlOpts)
|
|
390
|
+
.where("k", _slot)
|
|
391
|
+
.toSql().sql);
|
|
369
392
|
|
|
370
393
|
function _k(rawKey) {
|
|
371
394
|
if (!hashKeys) return rawKey;
|
|
@@ -476,8 +499,9 @@ function dbStore(opts) {
|
|
|
476
499
|
}
|
|
477
500
|
var migrated = 0;
|
|
478
501
|
var skipped = 0;
|
|
479
|
-
var rows = db.prepare(
|
|
480
|
-
|
|
502
|
+
var rows = db.prepare(sql.select(tableNameRaw, sqlOpts)
|
|
503
|
+
.columns(["k", "fingerprint", "status_code", "headers", "body", "expires_at"])
|
|
504
|
+
.toSql().sql).all();
|
|
481
505
|
for (var i = 0; i < rows.length; i += 1) {
|
|
482
506
|
var r = rows[i];
|
|
483
507
|
// If headers/body already start with vault.aad: this row is
|