@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
|
@@ -46,6 +46,7 @@ var C = require("./constants");
|
|
|
46
46
|
var lazyRequire = require("./lazy-require");
|
|
47
47
|
var validateOpts = require("./validate-opts");
|
|
48
48
|
var safeSql = require("./safe-sql");
|
|
49
|
+
var sql = require("./sql");
|
|
49
50
|
var { defineClass } = require("./framework-error");
|
|
50
51
|
|
|
51
52
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
@@ -55,6 +56,25 @@ var legalHold = lazyRequire(function () { return require("./legal-hold"); });
|
|
|
55
56
|
var RetentionError = defineClass("RetentionError", { alwaysPermanent: true });
|
|
56
57
|
var _err = RetentionError.factory;
|
|
57
58
|
|
|
59
|
+
// Resolve the b.sql dialect for the operator-supplied handle. The framework's
|
|
60
|
+
// local b.db handle is always node:sqlite (db.js pins { dialect: "sqlite",
|
|
61
|
+
// quoteName: true }) and exposes no .dialect, so this defaults to "sqlite" —
|
|
62
|
+
// every sweep statement runs against that handle via .prepare(). An operator
|
|
63
|
+
// handle that DOES advertise a dialect (string or () -> string) has it
|
|
64
|
+
// threaded through so the emitted identifier quoting + idioms match the
|
|
65
|
+
// backend the handle dispatches to. quoteName stays on for every retention
|
|
66
|
+
// statement: the rule's table / ageField / softDeleteField identifiers are
|
|
67
|
+
// validated then quoted by construction (no clusterStorage prefix rewrite on
|
|
68
|
+
// this operator-app-schema path).
|
|
69
|
+
function _handleDialect(db) {
|
|
70
|
+
if (db && typeof db.dialect === "function") {
|
|
71
|
+
try { var d = db.dialect(); return typeof d === "string" ? d : "sqlite"; }
|
|
72
|
+
catch (_e) { return "sqlite"; }
|
|
73
|
+
}
|
|
74
|
+
if (db && typeof db.dialect === "string") return db.dialect;
|
|
75
|
+
return "sqlite";
|
|
76
|
+
}
|
|
77
|
+
|
|
58
78
|
// Identifier-level SQLi defense: every operator-supplied table name,
|
|
59
79
|
// column name, and cascade FK must pass safeSql.validateIdentifier
|
|
60
80
|
// before reaching SQL string concatenation. Without this gate a
|
|
@@ -196,6 +216,11 @@ function create(opts) {
|
|
|
196
216
|
throw _err("BAD_OPT", "create: opts.db is required (a b.db handle with .prepare(sql))");
|
|
197
217
|
}
|
|
198
218
|
var db = opts.db;
|
|
219
|
+
// b.sql opts for every retention statement built against this handle. The
|
|
220
|
+
// dialect tracks the handle (sqlite for the framework's local b.db); the
|
|
221
|
+
// validated operator identifiers are quoted by construction (quoteName)
|
|
222
|
+
// with no clusterStorage prefix rewrite on this path.
|
|
223
|
+
var SQL_OPTS = { dialect: _handleDialect(db), quoteName: true };
|
|
199
224
|
var auditOn = opts.audit !== false && opts.audit != null;
|
|
200
225
|
var auditInstance = (opts.audit && opts.audit !== true) ? opts.audit : null;
|
|
201
226
|
var rules = {};
|
|
@@ -235,21 +260,28 @@ function create(opts) {
|
|
|
235
260
|
|
|
236
261
|
function _hardDelete(table, rowId, dryRun) {
|
|
237
262
|
if (dryRun) return { wouldDelete: 1 };
|
|
238
|
-
|
|
239
|
-
|
|
263
|
+
// Operator app table — quoteName so the validated identifier emits as a
|
|
264
|
+
// quoted local name; the row id binds as a placeholder.
|
|
265
|
+
var built = sql.delete(table, SQL_OPTS)
|
|
266
|
+
.where("_id", rowId)
|
|
267
|
+
.toSql();
|
|
268
|
+
var del = db.prepare(built.sql);
|
|
269
|
+
del.run.apply(del, built.params);
|
|
240
270
|
return { deleted: 1 };
|
|
241
271
|
}
|
|
242
272
|
|
|
243
273
|
function _softDelete(table, rowId, softField, dryRun) {
|
|
244
274
|
if (dryRun) return { wouldSoftDelete: 1 };
|
|
245
|
-
var
|
|
246
|
-
|
|
247
|
-
|
|
275
|
+
var built = sql.update(table, SQL_OPTS)
|
|
276
|
+
.set(softField, Date.now())
|
|
277
|
+
.where("_id", rowId)
|
|
278
|
+
.toSql();
|
|
279
|
+
var upd = db.prepare(built.sql);
|
|
280
|
+
upd.run.apply(upd, built.params);
|
|
248
281
|
return { softDeleted: 1 };
|
|
249
282
|
}
|
|
250
283
|
|
|
251
284
|
function _erase(table, row, dryRun) {
|
|
252
|
-
var erased = cryptoField.eraseRow(table, row);
|
|
253
285
|
var sealedFields = cryptoField.getSealedFields(table) || [];
|
|
254
286
|
var hashFields = [];
|
|
255
287
|
var schema = cryptoField.getSchema(table);
|
|
@@ -261,21 +293,38 @@ function create(opts) {
|
|
|
261
293
|
return _hardDelete(table, row._id, dryRun);
|
|
262
294
|
}
|
|
263
295
|
if (dryRun) return { wouldErase: 1, sealedFieldCount: sealedFields.length };
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
296
|
+
// eraseRow produces the in-memory tombstone AND drives the posture-gated
|
|
297
|
+
// side effects: under a regime whose POSTURE_DEFAULTS sets
|
|
298
|
+
// requireVacuumAfterErase it schedules db.vacuumAfterErase({ mode: "full" })
|
|
299
|
+
// and emits cryptofield.erase.row. Both belong only to the COMMITTING path
|
|
300
|
+
// — running them above the dry-run gate made a preview VACUUM the whole
|
|
301
|
+
// database file per candidate row (#120). Its return value is unused (the
|
|
302
|
+
// UPDATE below NULLs the columns directly); we keep the call for the
|
|
303
|
+
// tombstone bucketing + posture vacuum on the real path.
|
|
304
|
+
var erased = cryptoField.eraseRow(table, row);
|
|
305
|
+
// NULL every sealed column + its derived-hash sibling. b.sql binds each
|
|
306
|
+
// null as a placeholder (the set map preserves the column ordering).
|
|
307
|
+
var eraseSet = {};
|
|
308
|
+
for (var si = 0; si < sealedFields.length; si++) eraseSet[sealedFields[si]] = null;
|
|
309
|
+
for (var hi = 0; hi < hashFields.length; hi++) eraseSet[hashFields[hi]] = null;
|
|
310
|
+
var eraseBuilt = sql.update(table, SQL_OPTS)
|
|
311
|
+
.set(eraseSet)
|
|
312
|
+
.where("_id", row._id)
|
|
313
|
+
.toSql();
|
|
314
|
+
var upd2 = db.prepare(eraseBuilt.sql);
|
|
315
|
+
upd2.run.apply(upd2, eraseBuilt.params);
|
|
316
|
+
// Per-row-key tables (declarePerRowKey): NULLing the sealed columns
|
|
317
|
+
// is not enough — WAL / replica residuals keep the old K_row cells.
|
|
318
|
+
// Destroy the row's wrapped secret so K_row is unrecoverable and the
|
|
319
|
+
// residual ciphertext reads as absent (crypto-shred, GDPR Art. 17).
|
|
320
|
+
// rowId is row._id, the same identity materialize / eraseHard use.
|
|
321
|
+
var perRowKeysDestroyed = 0;
|
|
322
|
+
if (cryptoField.hasPerRowKey(table)) {
|
|
323
|
+
var dr = cryptoField.destroyPerRowKey(table, row._id, db);
|
|
324
|
+
perRowKeysDestroyed = (dr && dr.destroyed) || 0;
|
|
273
325
|
}
|
|
274
|
-
values.push(row._id);
|
|
275
|
-
var upd2 = db.prepare("UPDATE \"" + table + "\" SET " + setClauses.join(", ") + " WHERE _id = ?");
|
|
276
|
-
upd2.run.apply(upd2, values);
|
|
277
326
|
void erased;
|
|
278
|
-
return { erased: 1, sealedFieldCount: sealedFields.length };
|
|
327
|
+
return { erased: 1, sealedFieldCount: sealedFields.length, perRowKeysDestroyed: perRowKeysDestroyed };
|
|
279
328
|
}
|
|
280
329
|
|
|
281
330
|
function _cascade(rule, rowId, dryRun) {
|
|
@@ -284,15 +333,20 @@ function create(opts) {
|
|
|
284
333
|
for (var i = 0; i < rule.cascade.length; i++) {
|
|
285
334
|
var c = rule.cascade[i];
|
|
286
335
|
if (dryRun) {
|
|
287
|
-
var
|
|
288
|
-
"
|
|
289
|
-
|
|
336
|
+
var selBuilt = sql.select(c.table, SQL_OPTS)
|
|
337
|
+
.count("*", "n")
|
|
338
|
+
.where(c.foreignKey, rowId)
|
|
339
|
+
.toSql();
|
|
340
|
+
var sel = db.prepare(selBuilt.sql);
|
|
341
|
+
var n = sel.get.apply(sel, selBuilt.params);
|
|
290
342
|
cascadeSummary.push({ table: c.table, foreignKey: c.foreignKey,
|
|
291
343
|
wouldDelete: (n && typeof n.n === "number") ? n.n : 0 });
|
|
292
344
|
} else {
|
|
293
|
-
var
|
|
294
|
-
|
|
295
|
-
|
|
345
|
+
var delBuilt = sql.delete(c.table, SQL_OPTS)
|
|
346
|
+
.where(c.foreignKey, rowId)
|
|
347
|
+
.toSql();
|
|
348
|
+
var del = db.prepare(delBuilt.sql);
|
|
349
|
+
var result = del.run.apply(del, delBuilt.params);
|
|
296
350
|
cascadeSummary.push({ table: c.table, foreignKey: c.foreignKey,
|
|
297
351
|
deleted: result.changes || 0 });
|
|
298
352
|
}
|
|
@@ -382,24 +436,31 @@ function create(opts) {
|
|
|
382
436
|
while (moreRows) {
|
|
383
437
|
var rows;
|
|
384
438
|
// The candidate WHERE-clause: age + not-already-erased + not-on-legal-hold +
|
|
385
|
-
// (when soft-delete is configured) not-already-soft-deleted.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
439
|
+
// (when soft-delete is configured) not-already-soft-deleted. Built
|
|
440
|
+
// through b.sql so the operator-supplied table / ageField / softDeleteField
|
|
441
|
+
// identifiers are quoted by construction and every value binds as a
|
|
442
|
+
// placeholder (the '' empty-string compare included — no embedded literal).
|
|
443
|
+
function _candidateBase() {
|
|
444
|
+
var qb = sql.select(rule.table, SQL_OPTS)
|
|
445
|
+
.where(rule.ageField, "<=", cutoff);
|
|
446
|
+
if (rule.softDeleteField) qb.whereNull(rule.softDeleteField);
|
|
447
|
+
return qb;
|
|
390
448
|
}
|
|
391
|
-
var sql = "SELECT * FROM \"" + rule.table + "\" " +
|
|
392
|
-
"WHERE " + whereParts.join(" AND ") + " " +
|
|
393
|
-
"AND (__erasedAt IS NULL OR __erasedAt = '') " +
|
|
394
|
-
"LIMIT ?";
|
|
395
449
|
var selStmt;
|
|
396
|
-
try {
|
|
397
|
-
|
|
450
|
+
try {
|
|
451
|
+
var built = _candidateBase()
|
|
452
|
+
.whereGroup(function (g) {
|
|
453
|
+
g.whereNull("__erasedAt").orWhereOp("__erasedAt", "=", "");
|
|
454
|
+
})
|
|
455
|
+
.limit(rule.batchSize)
|
|
456
|
+
.toSql();
|
|
457
|
+
selStmt = db.prepare(built.sql);
|
|
458
|
+
rows = selStmt.all.apply(selStmt, built.params);
|
|
459
|
+
} catch (_eA) {
|
|
398
460
|
// Fallback: tables without __erasedAt
|
|
399
|
-
var
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
rows = selPlain.all.apply(selPlain, whereArgs.concat([rule.batchSize]));
|
|
461
|
+
var plainBuilt = _candidateBase().limit(rule.batchSize).toSql();
|
|
462
|
+
var selPlain = db.prepare(plainBuilt.sql);
|
|
463
|
+
rows = selPlain.all.apply(selPlain, plainBuilt.params);
|
|
403
464
|
}
|
|
404
465
|
if (!rows || rows.length === 0) { moreRows = false; break; }
|
|
405
466
|
summary.scanned += rows.length;
|
|
@@ -42,6 +42,7 @@ var lazyRequire = require("./lazy-require");
|
|
|
42
42
|
var safeAsync = require("./safe-async");
|
|
43
43
|
var safeEnv = require("./parsers/safe-env");
|
|
44
44
|
var safeUrl = require("./safe-url");
|
|
45
|
+
var validateOpts = require("./validate-opts");
|
|
45
46
|
var websocket = require("./websocket");
|
|
46
47
|
var { boot } = require("./log");
|
|
47
48
|
var { RouterError } = require("./framework-error");
|
|
@@ -301,6 +302,13 @@ class Router {
|
|
|
301
302
|
constructor(opts) {
|
|
302
303
|
opts = opts || {};
|
|
303
304
|
this.routes = [];
|
|
305
|
+
// Registration-ordered middleware table. Each entry is
|
|
306
|
+
// `{ prefix, prefixSegments, fn }`: `prefix === null` is a global
|
|
307
|
+
// middleware (runs on every request); a non-null `prefix` is a
|
|
308
|
+
// path-scoped middleware that runs only when the request path
|
|
309
|
+
// matches the prefix on segment boundaries. Path-scoped and global
|
|
310
|
+
// entries interleave in registration order so a gate registered
|
|
311
|
+
// before a route still runs before it.
|
|
304
312
|
this.middleware = [];
|
|
305
313
|
// WebSocket routes are kept separate from HTTP routes — they're
|
|
306
314
|
// matched on the upgrade / Extended CONNECT nodePath, not on a method
|
|
@@ -453,8 +461,23 @@ class Router {
|
|
|
453
461
|
return conns.length;
|
|
454
462
|
}
|
|
455
463
|
|
|
456
|
-
use(
|
|
457
|
-
|
|
464
|
+
// use(mw) — global middleware (runs on every request)
|
|
465
|
+
// use(mw1, mw2, ...) — several global middlewares, in order
|
|
466
|
+
// use(prefix, mw1, mw2, ...) — path-scoped: mw runs only when the
|
|
467
|
+
// request path is at or beneath `prefix`
|
|
468
|
+
// on segment boundaries ("/admin" covers
|
|
469
|
+
// "/admin" + "/admin/x", not "/administrator")
|
|
470
|
+
// use([prefixA, prefixB], mw) — scoped to any of several prefixes
|
|
471
|
+
//
|
|
472
|
+
// Bad input throws at config time (a non-string / non-array prefix, a
|
|
473
|
+
// prefix that doesn't begin with "/", a non-function middleware) so an
|
|
474
|
+
// operator wiring typo surfaces at boot instead of silently dropping a
|
|
475
|
+
// security gate or 500-ing every request.
|
|
476
|
+
use() {
|
|
477
|
+
var entries = _normalizeUseArgs(Array.prototype.slice.call(arguments));
|
|
478
|
+
for (var i = 0; i < entries.length; i++) {
|
|
479
|
+
this.middleware.push(entries[i]);
|
|
480
|
+
}
|
|
458
481
|
}
|
|
459
482
|
|
|
460
483
|
// Internal: split a route registration's args into { spec, handlers }.
|
|
@@ -687,8 +710,24 @@ class Router {
|
|
|
687
710
|
}
|
|
688
711
|
req.query = Object.fromEntries(queryEntries);
|
|
689
712
|
|
|
690
|
-
// Run middleware
|
|
691
|
-
|
|
713
|
+
// Run middleware in registration order. Global entries
|
|
714
|
+
// (prefixSegmentsList === null) run on every request; path-scoped
|
|
715
|
+
// entries run only when req.pathname is at or beneath one of the
|
|
716
|
+
// mount's prefixes (segment-boundary match). A skipped scoped
|
|
717
|
+
// middleware does NOT short-circuit the chain — the next entry
|
|
718
|
+
// still runs.
|
|
719
|
+
for (var entry of this.middleware) {
|
|
720
|
+
if (entry.prefixSegmentsList !== null) {
|
|
721
|
+
var matched = false;
|
|
722
|
+
for (var pli = 0; pli < entry.prefixSegmentsList.length; pli++) {
|
|
723
|
+
if (_pathMatchesPrefix(entry.prefixSegmentsList[pli], req.pathname)) {
|
|
724
|
+
matched = true;
|
|
725
|
+
break;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
if (!matched) continue;
|
|
729
|
+
}
|
|
730
|
+
var mw = entry.fn;
|
|
692
731
|
var next = false;
|
|
693
732
|
try {
|
|
694
733
|
await mw(req, res, () => (next = true));
|
|
@@ -1206,6 +1245,152 @@ class Router {
|
|
|
1206
1245
|
}
|
|
1207
1246
|
}
|
|
1208
1247
|
|
|
1248
|
+
// ---- Path-scoped `use()` helpers ----
|
|
1249
|
+
//
|
|
1250
|
+
// These back `Router.use(prefix, mw)`. They live after the class
|
|
1251
|
+
// (hoisted function declarations are visible to the methods regardless
|
|
1252
|
+
// of source order) so the class methods sit contiguous with the
|
|
1253
|
+
// route-matching helpers above.
|
|
1254
|
+
|
|
1255
|
+
// Compile a `use(prefix, mw)` path prefix into the segment list the
|
|
1256
|
+
// matcher walks. A prefix is the literal-segment portion of a path
|
|
1257
|
+
// ("/admin", "/.well-known/jmap") — parameter segments (":id") are not
|
|
1258
|
+
// meaningful for a mounting prefix, so they're treated as literals.
|
|
1259
|
+
//
|
|
1260
|
+
// Normalization mirrors route-pattern handling: split on "/" and drop a
|
|
1261
|
+
// single trailing-slash artifact so "/admin" and "/admin/" mount the
|
|
1262
|
+
// same. The leading empty segment from the leading "/" is preserved so
|
|
1263
|
+
// the prefix anchors at the path root (a prefix that does not begin with
|
|
1264
|
+
// "/" is refused at the use() entry point).
|
|
1265
|
+
function _compilePrefix(prefix) {
|
|
1266
|
+
var segments = prefix.split("/");
|
|
1267
|
+
// A trailing "/" produces a final empty segment ("/admin/" → ["", "admin", ""]).
|
|
1268
|
+
// Drop it so the trailing slash doesn't force an extra path segment.
|
|
1269
|
+
if (segments.length > 1 && segments[segments.length - 1] === "") {
|
|
1270
|
+
segments.pop();
|
|
1271
|
+
}
|
|
1272
|
+
return segments;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
// True when `pathname` is at or beneath the mounting prefix, matching on
|
|
1276
|
+
// segment boundaries. "/admin" matches "/admin" and "/admin/x" but NOT
|
|
1277
|
+
// "/administrator" (Express-style segment semantics) — a substring
|
|
1278
|
+
// prefix that lands mid-segment is a no-match so a security gate scoped
|
|
1279
|
+
// to "/admin" never leaks onto a sibling path that merely shares a
|
|
1280
|
+
// textual prefix.
|
|
1281
|
+
function _pathMatchesPrefix(prefixSegments, pathname) {
|
|
1282
|
+
var pathSegments = pathname.split("/");
|
|
1283
|
+
if (pathSegments.length < prefixSegments.length) return false;
|
|
1284
|
+
// Compare segment-for-segment. This is routing metadata (public URL
|
|
1285
|
+
// path), not secret material, so an ordinary equality walk is correct
|
|
1286
|
+
// — no constant-time comparison is warranted.
|
|
1287
|
+
return prefixSegments.every(function (seg, i) {
|
|
1288
|
+
return pathSegments[i] === seg;
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// Classify the first `use()` argument:
|
|
1293
|
+
// function → global mount (prefixes stays null)
|
|
1294
|
+
// string / string[] → path-scoped mount (one or more prefixes)
|
|
1295
|
+
// anything else → operator wiring typo, refused at config time
|
|
1296
|
+
// Returns the prefix array (or null for a global mount). Does not touch
|
|
1297
|
+
// the middleware functions — the caller validates those.
|
|
1298
|
+
function _usePrefixesFromFirstArg(first) {
|
|
1299
|
+
if (typeof first === "function") return null;
|
|
1300
|
+
if (typeof first !== "string" && !Array.isArray(first)) {
|
|
1301
|
+
throw new RouterError("router/use-bad-first-arg",
|
|
1302
|
+
"router.use: first argument must be a middleware function, a path " +
|
|
1303
|
+
"prefix string, or an array of prefix strings (got " +
|
|
1304
|
+
(first === null ? "null" : typeof first) + ")");
|
|
1305
|
+
}
|
|
1306
|
+
var prefixes = Array.isArray(first) ? first : [first];
|
|
1307
|
+
if (prefixes.length === 0) {
|
|
1308
|
+
throw new RouterError("router/use-empty-prefix-array",
|
|
1309
|
+
"router.use: path-prefix array must contain at least one prefix string");
|
|
1310
|
+
}
|
|
1311
|
+
// Array-of-non-empty-strings shape (the index-pointing throw on a
|
|
1312
|
+
// non-string / empty entry) is the shared validate-opts contract.
|
|
1313
|
+
validateOpts.optionalNonEmptyStringArray(
|
|
1314
|
+
prefixes, "router.use: path prefix", RouterError, "router/use-prefix-not-string");
|
|
1315
|
+
// Prefix-specific grammar: anchor at "/" + bounded length.
|
|
1316
|
+
for (var i = 0; i < prefixes.length; i++) {
|
|
1317
|
+
var grammarErr = _prefixGrammarError(prefixes[i]);
|
|
1318
|
+
if (grammarErr) throw grammarErr;
|
|
1319
|
+
}
|
|
1320
|
+
return prefixes;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// Return a RouterError describing why `prefix` is not a valid mounting
|
|
1324
|
+
// prefix, or null when it is valid. Split out so the per-prefix grammar
|
|
1325
|
+
// check is one branch, not an inline throw-block in the loop.
|
|
1326
|
+
function _prefixGrammarError(prefix) {
|
|
1327
|
+
if (prefix.charAt(0) !== "/") {
|
|
1328
|
+
return new RouterError("router/use-prefix-not-absolute",
|
|
1329
|
+
"router.use: path prefix '" + prefix + "' must begin with '/'");
|
|
1330
|
+
}
|
|
1331
|
+
if (prefix.length > MAX_ROUTE_PATTERN_LEN) {
|
|
1332
|
+
return new RouterError("router/use-prefix-too-long",
|
|
1333
|
+
"router.use: path prefix exceeds " + MAX_ROUTE_PATTERN_LEN +
|
|
1334
|
+
" chars (got " + prefix.length + ")");
|
|
1335
|
+
}
|
|
1336
|
+
return null;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// Index of the first non-function entry in `fns`, or -1 when all are
|
|
1340
|
+
// functions. Kept separate so the middleware-shape check is a scan, not
|
|
1341
|
+
// an inline throw inside the normalize flow.
|
|
1342
|
+
function _firstNonFunctionIndex(fns) {
|
|
1343
|
+
for (var i = 0; i < fns.length; i++) {
|
|
1344
|
+
if (typeof fns[i] !== "function") return i;
|
|
1345
|
+
}
|
|
1346
|
+
return -1;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// Validate + normalize the `use()` arguments into middleware-table
|
|
1350
|
+
// entries. Config-time entry-point tier: a non-string / non-array-of-
|
|
1351
|
+
// strings prefix or a non-function middleware is an operator wiring
|
|
1352
|
+
// typo and throws so it surfaces at boot, not as a silent dropped gate
|
|
1353
|
+
// or a request-time 500. Returns one entry per middleware function:
|
|
1354
|
+
// { prefix: null, prefixSegmentsList: null, fn } — global
|
|
1355
|
+
// { prefix: "/admin", prefixSegmentsList: [[...], ...], fn } — scoped
|
|
1356
|
+
// A scoped entry matches when ANY of its prefixes match the request
|
|
1357
|
+
// path on segment boundaries; the fn runs at most once per request even
|
|
1358
|
+
// when two of its prefixes both match (nested prefixes), so a gate never
|
|
1359
|
+
// double-executes.
|
|
1360
|
+
function _normalizeUseArgs(args) {
|
|
1361
|
+
if (args.length === 0) {
|
|
1362
|
+
throw new RouterError("router/use-no-args",
|
|
1363
|
+
"router.use: requires at least one middleware function");
|
|
1364
|
+
}
|
|
1365
|
+
var prefixes = _usePrefixesFromFirstArg(args[0]);
|
|
1366
|
+
// Global mount uses every arg as a middleware; a scoped mount drops the
|
|
1367
|
+
// leading prefix arg and uses the rest.
|
|
1368
|
+
var fns = (prefixes === null) ? args : args.slice(1);
|
|
1369
|
+
if (fns.length === 0) {
|
|
1370
|
+
throw new RouterError("router/use-no-middleware",
|
|
1371
|
+
"router.use: path-scoped mount requires at least one middleware " +
|
|
1372
|
+
"function after the prefix");
|
|
1373
|
+
}
|
|
1374
|
+
var nonFn = _firstNonFunctionIndex(fns);
|
|
1375
|
+
if (nonFn !== -1) {
|
|
1376
|
+
throw new RouterError("router/use-middleware-not-function",
|
|
1377
|
+
"router.use: middleware at position " + nonFn +
|
|
1378
|
+
" must be a function (got " +
|
|
1379
|
+
(fns[nonFn] === null ? "null" : typeof fns[nonFn]) + ")");
|
|
1380
|
+
}
|
|
1381
|
+
// Pre-compile each prefix to its segment list once at registration so
|
|
1382
|
+
// dispatch only walks segments, never re-splits the prefix per request.
|
|
1383
|
+
var segmentsList = (prefixes === null) ? null : prefixes.map(_compilePrefix);
|
|
1384
|
+
var label = (prefixes === null) ? null
|
|
1385
|
+
: (prefixes.length === 1 ? prefixes[0] : prefixes.slice());
|
|
1386
|
+
// One entry per fn, preserving the order each middleware was passed —
|
|
1387
|
+
// a path-scoped mount with two middlewares interleaves them in
|
|
1388
|
+
// registration order just like two separate use() calls would.
|
|
1389
|
+
return fns.map(function (fn) {
|
|
1390
|
+
return { prefix: label, prefixSegmentsList: segmentsList, fn: fn };
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1209
1394
|
/**
|
|
1210
1395
|
* @primitive b.router.serveStatic
|
|
1211
1396
|
* @signature b.router.serveStatic(dir)
|
|
@@ -1266,7 +1451,7 @@ function serveStatic(dir) {
|
|
|
1266
1451
|
*
|
|
1267
1452
|
* Builds a `Router` instance with the framework's security-on-by-
|
|
1268
1453
|
* default posture. Returned object exposes `get / post / put / patch
|
|
1269
|
-
* / delete` for route registration, `use(
|
|
1454
|
+
* / delete` for route registration, `use(...)` for middleware,
|
|
1270
1455
|
* `ws(path, handler, opts?)` for WebSocket routes, `onNotFound(fn)`
|
|
1271
1456
|
* and `onError(fn)` for fallthrough hooks, `inspectRoutes()` and
|
|
1272
1457
|
* `openapi()` for introspection, `closeWebSockets({ timeoutMs })`
|
|
@@ -1274,6 +1459,21 @@ function serveStatic(dir) {
|
|
|
1274
1459
|
* which boots an HTTP/2-capable TLS server (ALPN h2 + http/1.1) when
|
|
1275
1460
|
* `tlsOptions` is provided, an HTTP/1.1 server otherwise.
|
|
1276
1461
|
*
|
|
1462
|
+
* `use` has two forms. `use(mw)` (and `use(mw1, mw2, ...)`) mounts
|
|
1463
|
+
* global middleware that runs on every request. `use(prefix, mw1,
|
|
1464
|
+
* mw2, ...)` mounts path-scoped middleware that runs only when the
|
|
1465
|
+
* request path is at or beneath `prefix`, matched on segment
|
|
1466
|
+
* boundaries — `"/admin"` covers `"/admin"` and `"/admin/x"` but not
|
|
1467
|
+
* `"/administrator"`. The prefix may be an array of strings to scope a
|
|
1468
|
+
* gate to several path roots at once. Global and scoped middleware
|
|
1469
|
+
* interleave in registration order, so a gate registered before a
|
|
1470
|
+
* route still runs before it. A non-string / non-array prefix, a
|
|
1471
|
+
* prefix not beginning with `"/"`, or a non-function middleware throws
|
|
1472
|
+
* at registration time rather than dropping the gate or 500-ing every
|
|
1473
|
+
* request — scope a security middleware (`csrf`, `bearerAuth`,
|
|
1474
|
+
* `requireAal`, `requireMtls`) to a path with confidence it runs
|
|
1475
|
+
* exactly where mounted.
|
|
1476
|
+
*
|
|
1277
1477
|
* @opts
|
|
1278
1478
|
* tls0Rtt: "refuse" | "replay-cache", // RFC 8446 §8 anti-replay; default "refuse"
|
|
1279
1479
|
* allowedRedirectOrigins: string[], // exact-match HTTPS origins for cross-origin res.redirect()
|
|
@@ -1286,6 +1486,13 @@ function serveStatic(dir) {
|
|
|
1286
1486
|
* router.get("/users/:id", function (req, res) {
|
|
1287
1487
|
* res.json({ id: req.params.id });
|
|
1288
1488
|
* });
|
|
1489
|
+
*
|
|
1490
|
+
* // Global middleware — runs on every request.
|
|
1491
|
+
* router.use(b.middleware.securityHeaders());
|
|
1492
|
+
*
|
|
1493
|
+
* // Path-scoped middleware — the step-up gate runs only under /admin.
|
|
1494
|
+
* router.use("/admin", b.middleware.requireAal({ minimum: "AAL2" }));
|
|
1495
|
+
*
|
|
1289
1496
|
* router.listen(3000);
|
|
1290
1497
|
*/
|
|
1291
1498
|
function create(opts) {
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
|
|
58
58
|
var C = require("./constants");
|
|
59
59
|
var { defineClass } = require("./framework-error");
|
|
60
|
+
var gateContract = require("./gate-contract");
|
|
60
61
|
|
|
61
62
|
var SafeDnsError = defineClass("SafeDnsError", { alwaysPermanent: true });
|
|
62
63
|
|
|
@@ -153,11 +154,15 @@ var PROFILES = Object.freeze({
|
|
|
153
154
|
},
|
|
154
155
|
});
|
|
155
156
|
|
|
156
|
-
var COMPLIANCE_POSTURES =
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
|
|
158
|
+
|
|
159
|
+
var _resolveProfile = gateContract.makeProfileResolver({
|
|
160
|
+
profiles: PROFILES,
|
|
161
|
+
postures: COMPLIANCE_POSTURES,
|
|
162
|
+
defaults: DEFAULT_PROFILE,
|
|
163
|
+
errorClass: SafeDnsError,
|
|
164
|
+
codePrefix: "safe-dns",
|
|
165
|
+
byObject: true,
|
|
161
166
|
});
|
|
162
167
|
|
|
163
168
|
/**
|
|
@@ -349,22 +354,6 @@ function checkCnameChainDepth(depth, opts) {
|
|
|
349
354
|
}
|
|
350
355
|
}
|
|
351
356
|
|
|
352
|
-
/**
|
|
353
|
-
* @primitive b.safeDns.compliancePosture
|
|
354
|
-
* @signature b.safeDns.compliancePosture(posture)
|
|
355
|
-
* @since 0.9.31
|
|
356
|
-
* @status stable
|
|
357
|
-
*
|
|
358
|
-
* Return the effective profile name for a compliance posture, or
|
|
359
|
-
* `null` for unknown posture names (operator typo surfaces here).
|
|
360
|
-
*
|
|
361
|
-
* @example
|
|
362
|
-
* b.safeDns.compliancePosture("hipaa"); // → "strict"
|
|
363
|
-
*/
|
|
364
|
-
function compliancePosture(posture) {
|
|
365
|
-
return COMPLIANCE_POSTURES[posture] || null;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
357
|
function _readName(state, pointerDepth) {
|
|
369
358
|
if (pointerDepth > state.caps.maxPointerDepth) {
|
|
370
359
|
throw new SafeDnsError("safe-dns/oversize-pointer-depth",
|
|
@@ -639,27 +628,22 @@ function _decodeOpt(rr, caps) {
|
|
|
639
628
|
};
|
|
640
629
|
}
|
|
641
630
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
RTYPE_NAMES: RTYPE_NAMES,
|
|
662
|
-
SafeDnsError: SafeDnsError,
|
|
663
|
-
NAME: "dns",
|
|
664
|
-
KIND: "dns-response",
|
|
665
|
-
};
|
|
631
|
+
// compliancePosture is assembled by gateContract.defineParser below; its
|
|
632
|
+
// wiki section renders from the single-sourced @abiTemplate (defineParser)
|
|
633
|
+
// block in gate-contract.js, instantiated for this guard by the page
|
|
634
|
+
// generator.
|
|
635
|
+
module.exports = gateContract.defineParser({
|
|
636
|
+
name: "dns",
|
|
637
|
+
entry: parseResponse,
|
|
638
|
+
entryName: "parseResponse",
|
|
639
|
+
errorClass: SafeDnsError,
|
|
640
|
+
profiles: PROFILES,
|
|
641
|
+
postures: COMPLIANCE_POSTURES,
|
|
642
|
+
extra: {
|
|
643
|
+
boundEdns0: boundEdns0,
|
|
644
|
+
checkCnameChainDepth: checkCnameChainDepth,
|
|
645
|
+
RTYPE_NAMES: RTYPE_NAMES,
|
|
646
|
+
NAME: "dns",
|
|
647
|
+
KIND: "dns-response",
|
|
648
|
+
},
|
|
649
|
+
});
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
|
|
82
82
|
var C = require("./constants");
|
|
83
83
|
var { defineClass } = require("./framework-error");
|
|
84
|
+
var gateContract = require("./gate-contract");
|
|
84
85
|
|
|
85
86
|
var SafeIcalError = defineClass("SafeIcalError", { alwaysPermanent: true });
|
|
86
87
|
|
|
@@ -116,12 +117,7 @@ var PROFILES = Object.freeze({
|
|
|
116
117
|
}),
|
|
117
118
|
});
|
|
118
119
|
|
|
119
|
-
var COMPLIANCE_POSTURES =
|
|
120
|
-
hipaa: "strict",
|
|
121
|
-
"pci-dss": "strict",
|
|
122
|
-
gdpr: "strict",
|
|
123
|
-
soc2: "strict",
|
|
124
|
-
});
|
|
120
|
+
var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
|
|
125
121
|
|
|
126
122
|
// Property-name allowlist per RFC 5545 §8.7 (Property Registry) +
|
|
127
123
|
// RFC 5546 §4.3 (iTIP additions) + RFC 7986 §5 (new calendar
|
|
@@ -273,24 +269,6 @@ function parse(text, opts) {
|
|
|
273
269
|
: { vcalendar: vcalendars[0], vcalendars: vcalendars };
|
|
274
270
|
}
|
|
275
271
|
|
|
276
|
-
/**
|
|
277
|
-
* @primitive b.safeIcal.compliancePosture
|
|
278
|
-
* @signature b.safeIcal.compliancePosture(name)
|
|
279
|
-
* @since 0.9.81
|
|
280
|
-
* @status stable
|
|
281
|
-
* @related b.safeIcal.parse
|
|
282
|
-
*
|
|
283
|
-
* Map a compliance-posture name to its profile. Returns the profile
|
|
284
|
-
* string for a known posture, `null` for unknown names.
|
|
285
|
-
*
|
|
286
|
-
* @example
|
|
287
|
-
* b.safeIcal.compliancePosture("hipaa"); // → "strict"
|
|
288
|
-
* b.safeIcal.compliancePosture("loose"); // → null
|
|
289
|
-
*/
|
|
290
|
-
function compliancePosture(name) {
|
|
291
|
-
return COMPLIANCE_POSTURES[name] || null;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
272
|
// ---- Profile / opt resolution ----
|
|
295
273
|
|
|
296
274
|
function _resolveCaps(opts) {
|
|
@@ -623,12 +601,19 @@ function _preview(s) {
|
|
|
623
601
|
return s.length > 64 ? s.slice(0, 64) + "..." : s; // log-preview length cap
|
|
624
602
|
}
|
|
625
603
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
604
|
+
// compliancePosture is assembled by gateContract.defineParser below; its
|
|
605
|
+
// wiki section renders from the single-sourced @abiTemplate (defineParser)
|
|
606
|
+
// block in gate-contract.js, instantiated for this guard by the page
|
|
607
|
+
// generator.
|
|
608
|
+
module.exports = gateContract.defineParser({
|
|
609
|
+
name: "ical",
|
|
610
|
+
entry: parse,
|
|
611
|
+
entryName: "parse",
|
|
612
|
+
errorClass: SafeIcalError,
|
|
613
|
+
profiles: PROFILES,
|
|
614
|
+
postures: COMPLIANCE_POSTURES,
|
|
615
|
+
extra: {
|
|
616
|
+
KNOWN_PROPERTIES: KNOWN_PROPERTIES,
|
|
617
|
+
KNOWN_COMPONENTS: KNOWN_COMPONENTS,
|
|
618
|
+
},
|
|
619
|
+
});
|