@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
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* crypto-interop-oracles — prove the framework's "external interop" and
|
|
4
|
+
* "FIPS/NIST" crypto claims against INDEPENDENT oracles, not the
|
|
5
|
+
* framework's own verifier.
|
|
6
|
+
*
|
|
7
|
+
* The advertised surface that this file holds to account:
|
|
8
|
+
*
|
|
9
|
+
* - b.auth.jws.sign — docstring: "exists strictly for interop with
|
|
10
|
+
* external ecosystems" (OAuth/OIDC OPs, FAPI, wallets). Every other
|
|
11
|
+
* test round-trips a token through b.auth.jwt.verifyExternal — the
|
|
12
|
+
* framework's OWN verifier. Here a from-scratch RFC 7515 verifier
|
|
13
|
+
* built on node:crypto (no framework code in the verify path) checks
|
|
14
|
+
* an ES256 and an EdDSA token, proving a third party who never
|
|
15
|
+
* touches blamejs can verify what blamejs signed.
|
|
16
|
+
*
|
|
17
|
+
* - b.pqcSoftware.{ml_kem_1024, ml_dsa_87, slh_dsa_shake_256f} — the
|
|
18
|
+
* module advertises "FIPS-203 / FIPS-204 / FIPS-205" and the
|
|
19
|
+
* "reference-implementation path for interop tests against Node
|
|
20
|
+
* WebCrypto or a hardware HSM". b.crypto.selfTest's PQC legs are
|
|
21
|
+
* pairwise-consistency only (generate a fresh keypair, round-trip it
|
|
22
|
+
* against itself) and b.pqcSoftware.runKnownAnswerTest's own
|
|
23
|
+
* docstring concedes it is "a self-consistency gate, NOT the FIPS 203
|
|
24
|
+
* Appendix A KAT vectors". This file closes that gap two ways:
|
|
25
|
+
*
|
|
26
|
+
* (a) A frozen cross-implementation KNOWN-ANSWER vector. ML-KEM-1024
|
|
27
|
+
* keygen + encapsulate are deterministic from a seed (d||z) and
|
|
28
|
+
* a message (m); the vendored pure-JS @noble/post-quantum bundle
|
|
29
|
+
* and Node's native OpenSSL-backed ML-KEM — two fully
|
|
30
|
+
* independent FIPS-203 implementations — agree on the resulting
|
|
31
|
+
* shared secret. That agreed value is embedded as the expected
|
|
32
|
+
* answer; the noble primitive must reproduce it byte-for-byte.
|
|
33
|
+
*
|
|
34
|
+
* (b) A live cross-implementation oracle on every run. The vendored
|
|
35
|
+
* pure-JS primitive is checked against Node's native OpenSSL
|
|
36
|
+
* implementation in BOTH directions for ML-KEM (encaps↔decaps),
|
|
37
|
+
* and the spec answer for the signature families comes FROM
|
|
38
|
+
* OpenSSL: OpenSSL signs, the framework's noble primitive
|
|
39
|
+
* verifies (ML-DSA-87 and SLH-DSA-SHAKE-256f), then the
|
|
40
|
+
* reverse. A pure-JS lattice/hash-sig implementation agreeing
|
|
41
|
+
* with a C/OpenSSL one is the substance of a KAT — neither
|
|
42
|
+
* shares code with the other.
|
|
43
|
+
*
|
|
44
|
+
* No bypass: real vendored bundle, real node:crypto, no rejectUnauthorized
|
|
45
|
+
* shortcuts, no require-cache mock of anything under test. The native
|
|
46
|
+
* ML-KEM / ML-DSA / SLH-DSA primitives are an independent implementation,
|
|
47
|
+
* not a stand-in for the thing under test (the vendored noble bundle).
|
|
48
|
+
*
|
|
49
|
+
* Native PQC is a Node-26 surface. Where it is unavailable the live
|
|
50
|
+
* cross-impl legs report a coverage finding and the frozen KAT (which
|
|
51
|
+
* needs no native crypto) still runs — so the FIPS conformance claim is
|
|
52
|
+
* always exercised against at least one off-framework anchor.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
var nodeCrypto = require("node:crypto");
|
|
56
|
+
var b = require("../..");
|
|
57
|
+
var check = require("../helpers/check").check;
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Independent RFC 7515 compact-JWS verifier — node:crypto only, ZERO
|
|
61
|
+
// framework code. This is the "different verifier" the framework's own
|
|
62
|
+
// jws.verify is not.
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
function b64uToBuf(s) {
|
|
66
|
+
var t = String(s).replace(/-/g, "+").replace(/_/g, "/");
|
|
67
|
+
while (t.length % 4) t += "=";
|
|
68
|
+
return Buffer.from(t, "base64");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Verify a compact JWS using only node:crypto. Mirrors RFC 7515 §5.2:
|
|
72
|
+
// recompute the signing input (ASCII of "<protected>.<payload>"), pick
|
|
73
|
+
// the verify parameters from the protected header's alg, and run
|
|
74
|
+
// crypto.verify against the operator-supplied public key.
|
|
75
|
+
function rfc7515Verify(token, publicKey) {
|
|
76
|
+
var parts = token.split(".");
|
|
77
|
+
if (parts.length !== 3) throw new Error("not a 3-part compact JWS");
|
|
78
|
+
var header = JSON.parse(b64uToBuf(parts[0]).toString("utf8"));
|
|
79
|
+
var signingInput = Buffer.from(parts[0] + "." + parts[1], "ascii");
|
|
80
|
+
var sig = b64uToBuf(parts[2]);
|
|
81
|
+
var alg = header.alg;
|
|
82
|
+
if (alg === "ES256") {
|
|
83
|
+
return {
|
|
84
|
+
header: header,
|
|
85
|
+
valid: nodeCrypto.verify("sha256", signingInput,
|
|
86
|
+
{ key: publicKey, dsaEncoding: "ieee-p1363" }, sig),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (alg === "ES384") {
|
|
90
|
+
return {
|
|
91
|
+
header: header,
|
|
92
|
+
valid: nodeCrypto.verify("sha384", signingInput,
|
|
93
|
+
{ key: publicKey, dsaEncoding: "ieee-p1363" }, sig),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (alg === "EdDSA") {
|
|
97
|
+
return { header: header, valid: nodeCrypto.verify(null, signingInput, publicKey, sig) };
|
|
98
|
+
}
|
|
99
|
+
if (alg === "RS256") {
|
|
100
|
+
return { header: header, valid: nodeCrypto.verify("sha256", signingInput, publicKey, sig) };
|
|
101
|
+
}
|
|
102
|
+
throw new Error("independent verifier does not implement alg " + alg);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Frozen cross-implementation ML-KEM-1024 KNOWN-ANSWER VECTOR.
|
|
107
|
+
//
|
|
108
|
+
// Derived deterministically (FIPS 203 is deterministic given the keygen
|
|
109
|
+
// seed d||z and the encapsulation message m) and confirmed identical by
|
|
110
|
+
// BOTH the vendored pure-JS @noble/post-quantum bundle AND Node's native
|
|
111
|
+
// OpenSSL ML-KEM-1024. The shared secret below is the value those two
|
|
112
|
+
// independent implementations agree on; the framework primitive must
|
|
113
|
+
// reproduce it. This anchor needs no native crypto, so it pins the FIPS
|
|
114
|
+
// conformance claim even on runtimes that lack native ML-KEM.
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
var MLKEM1024_KAT = {
|
|
118
|
+
// 64-byte keygen seed (d || z), FIPS 203 §7.1.
|
|
119
|
+
seedHex: "000102030405060708090a0b0c0d0e0f" +
|
|
120
|
+
"101112131415161718191a1b1c1d1e1f" +
|
|
121
|
+
"202122232425262728292a2b2c2d2e2f" +
|
|
122
|
+
"303132333435363738393a3b3c3d3e3f",
|
|
123
|
+
// 32-byte encapsulation message m, FIPS 203 §7.2.
|
|
124
|
+
msgHex: "0202020202020202020202020202020202020202020202020202020202020202",
|
|
125
|
+
// Expected 32-byte shared secret K, agreed by noble + OpenSSL.
|
|
126
|
+
sharedSecretHex: "7ca83e2bf9cdbdf7ebe24146efdd9a40a256e83c437d132d2048acf853fbbe46",
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Native-PQC availability probe (Node 26+). Used to gate the live
|
|
131
|
+
// cross-impl legs; the frozen KAT runs regardless.
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
// Whether this runtime can import an AKP (post-quantum) private key from a JWK
|
|
135
|
+
// for the given keygen alg — the exact operation each cross-implementation
|
|
136
|
+
// oracle leg performs. The AKP JWK *import* path is Node 26+ for ML-KEM and
|
|
137
|
+
// SLH-DSA; only ML-DSA JWK import is wired on the Node 24.14 floor. Probing the
|
|
138
|
+
// full generate -> export-to-JWK -> import-from-JWK round-trip (rather than just
|
|
139
|
+
// keygen, which exists for every alg on Node 24) lets a leg be SKIPPED — not
|
|
140
|
+
// FAILED — on a runtime that cannot perform the import the oracle relies on.
|
|
141
|
+
function nativeJwkImportWorks(keygenAlg) {
|
|
142
|
+
try {
|
|
143
|
+
var kp = nodeCrypto.generateKeyPairSync(keygenAlg);
|
|
144
|
+
var jwk = kp.privateKey.export({ format: "jwk" });
|
|
145
|
+
nodeCrypto.createPrivateKey({ key: jwk, format: "jwk" });
|
|
146
|
+
return true;
|
|
147
|
+
} catch (_e) { return false; }
|
|
148
|
+
}
|
|
149
|
+
function nativeMlKemAvailable() { return nativeJwkImportWorks("ml-kem-1024"); }
|
|
150
|
+
function nativeMlDsaAvailable() { return nativeJwkImportWorks("ml-dsa-87"); }
|
|
151
|
+
function nativeSlhDsaAvailable() { return nativeJwkImportWorks("slh-dsa-shake-256f"); }
|
|
152
|
+
|
|
153
|
+
function b64u(buf) { return Buffer.from(buf).toString("base64url"); }
|
|
154
|
+
|
|
155
|
+
var coverageFindings = [];
|
|
156
|
+
|
|
157
|
+
function run() {
|
|
158
|
+
var pq = b.pqcSoftware;
|
|
159
|
+
check("vendored PQC bundle is available", pq.isAvailable() === true);
|
|
160
|
+
|
|
161
|
+
// =====================================================================
|
|
162
|
+
// (1) b.auth.jws.sign verified by an INDEPENDENT RFC 7515 verifier.
|
|
163
|
+
// =====================================================================
|
|
164
|
+
|
|
165
|
+
// --- ES256 ---
|
|
166
|
+
var ecKeys = nodeCrypto.generateKeyPairSync("ec", { namedCurve: "prime256v1" });
|
|
167
|
+
var es256Token = b.auth.jws.sign(
|
|
168
|
+
{ iss: "blamejs-client", aud: "https://as.example.com", response_type: "code" },
|
|
169
|
+
{ privateKey: ecKeys.privateKey, typ: "oauth-authz-req+jwt", kid: "c1" });
|
|
170
|
+
var es256r = rfc7515Verify(es256Token, ecKeys.publicKey);
|
|
171
|
+
check("jws.sign ES256: independent RFC 7515 verifier accepts", es256r.valid === true);
|
|
172
|
+
check("jws.sign ES256: header alg derived from key", es256r.header.alg === "ES256");
|
|
173
|
+
check("jws.sign ES256: typ + kid present in protected header",
|
|
174
|
+
es256r.header.typ === "oauth-authz-req+jwt" && es256r.header.kid === "c1");
|
|
175
|
+
|
|
176
|
+
// A tampered payload must fail the independent verifier — proves the
|
|
177
|
+
// verify path actually checks the signature, not just structure.
|
|
178
|
+
var es256Parts = es256Token.split(".");
|
|
179
|
+
var forgedPayload = b64u(Buffer.from(JSON.stringify(
|
|
180
|
+
{ iss: "attacker", aud: "https://as.example.com", response_type: "code" }), "utf8"));
|
|
181
|
+
var es256Forged = es256Parts[0] + "." + forgedPayload + "." + es256Parts[2];
|
|
182
|
+
var es256ForgedR = rfc7515Verify(es256Forged, ecKeys.publicKey);
|
|
183
|
+
check("jws.sign ES256: tampered payload rejected by independent verifier",
|
|
184
|
+
es256ForgedR.valid === false);
|
|
185
|
+
|
|
186
|
+
// Wrong key must fail — proves the signature binds to the signer's key.
|
|
187
|
+
var otherEc = nodeCrypto.generateKeyPairSync("ec", { namedCurve: "prime256v1" });
|
|
188
|
+
check("jws.sign ES256: wrong public key rejected by independent verifier",
|
|
189
|
+
rfc7515Verify(es256Token, otherEc.publicKey).valid === false);
|
|
190
|
+
|
|
191
|
+
// --- EdDSA ---
|
|
192
|
+
var edKeys = nodeCrypto.generateKeyPairSync("ed25519");
|
|
193
|
+
var edToken = b.auth.jws.sign({ sub: "user-42", scope: "openid" }, { privateKey: edKeys.privateKey });
|
|
194
|
+
var edR = rfc7515Verify(edToken, edKeys.publicKey);
|
|
195
|
+
check("jws.sign EdDSA: independent RFC 7515 verifier accepts", edR.valid === true);
|
|
196
|
+
check("jws.sign EdDSA: header alg derived from key", edR.header.alg === "EdDSA");
|
|
197
|
+
check("jws.sign EdDSA: wrong key rejected by independent verifier",
|
|
198
|
+
rfc7515Verify(edToken, nodeCrypto.generateKeyPairSync("ed25519").publicKey).valid === false);
|
|
199
|
+
|
|
200
|
+
// --- RS256 ---
|
|
201
|
+
var rsaKeys = nodeCrypto.generateKeyPairSync("rsa", { modulusLength: 2048 });
|
|
202
|
+
var rsToken = b.auth.jws.sign({ iss: "rp", aud: "op" }, { privateKey: rsaKeys.privateKey });
|
|
203
|
+
var rsR = rfc7515Verify(rsToken, rsaKeys.publicKey);
|
|
204
|
+
check("jws.sign RS256: independent RFC 7515 verifier accepts", rsR.valid === true);
|
|
205
|
+
check("jws.sign RS256: header alg derived from RSA key", rsR.header.alg === "RS256");
|
|
206
|
+
|
|
207
|
+
// =====================================================================
|
|
208
|
+
// (2a) ML-KEM-1024 FROZEN cross-implementation KNOWN-ANSWER vector.
|
|
209
|
+
// The framework primitive must produce the exact spec shared secret
|
|
210
|
+
// that two independent FIPS-203 implementations agree on.
|
|
211
|
+
// =====================================================================
|
|
212
|
+
|
|
213
|
+
var katSeed = Buffer.from(MLKEM1024_KAT.seedHex, "hex");
|
|
214
|
+
var katMsg = Buffer.from(MLKEM1024_KAT.msgHex, "hex");
|
|
215
|
+
var katExpected = Buffer.from(MLKEM1024_KAT.sharedSecretHex, "hex");
|
|
216
|
+
|
|
217
|
+
check("ML-KEM-1024 KAT: seed is 64 bytes (d||z)", katSeed.length === 64);
|
|
218
|
+
check("ML-KEM-1024 KAT: message is 32 bytes (m)", katMsg.length === 32);
|
|
219
|
+
|
|
220
|
+
var katKp = pq.ml_kem_1024.keygen(katSeed);
|
|
221
|
+
check("ML-KEM-1024 KAT: deterministic keygen pk size (FIPS 203 |ek|=1568)",
|
|
222
|
+
katKp.publicKey.length === 1568);
|
|
223
|
+
check("ML-KEM-1024 KAT: deterministic keygen sk size (FIPS 203 |dk|=3168)",
|
|
224
|
+
katKp.secretKey.length === 3168);
|
|
225
|
+
|
|
226
|
+
var katEnc = pq.ml_kem_1024.encapsulate(katKp.publicKey, katMsg);
|
|
227
|
+
check("ML-KEM-1024 KAT: ciphertext size (FIPS 203 |c|=1568)",
|
|
228
|
+
katEnc.cipherText.length === 1568);
|
|
229
|
+
check("ML-KEM-1024 KAT: encapsulated shared secret matches frozen spec answer",
|
|
230
|
+
Buffer.from(katEnc.sharedSecret).equals(katExpected));
|
|
231
|
+
|
|
232
|
+
var katSs = pq.ml_kem_1024.decapsulate(katEnc.cipherText, katKp.secretKey);
|
|
233
|
+
check("ML-KEM-1024 KAT: decapsulated shared secret matches frozen spec answer",
|
|
234
|
+
Buffer.from(katSs).equals(katExpected));
|
|
235
|
+
|
|
236
|
+
// Re-run to assert determinism — a non-deterministic keygen/encaps
|
|
237
|
+
// would make the frozen vector meaningless.
|
|
238
|
+
var katKp2 = pq.ml_kem_1024.keygen(katSeed);
|
|
239
|
+
var katEnc2 = pq.ml_kem_1024.encapsulate(katKp2.publicKey, katMsg);
|
|
240
|
+
check("ML-KEM-1024 KAT: keygen is deterministic from the seed",
|
|
241
|
+
Buffer.from(katKp.publicKey).equals(Buffer.from(katKp2.publicKey)));
|
|
242
|
+
check("ML-KEM-1024 KAT: encapsulate is deterministic from (pk, m)",
|
|
243
|
+
Buffer.from(katEnc.cipherText).equals(Buffer.from(katEnc2.cipherText)));
|
|
244
|
+
|
|
245
|
+
// =====================================================================
|
|
246
|
+
// (2b) Live cross-implementation oracle: vendored pure-JS noble bundle
|
|
247
|
+
// vs Node native OpenSSL. Independent in both directions.
|
|
248
|
+
// =====================================================================
|
|
249
|
+
|
|
250
|
+
if (nativeMlKemAvailable()) {
|
|
251
|
+
// Cross-check the frozen KAT's public key against OpenSSL too:
|
|
252
|
+
// import noble's (seed, pk) and have OpenSSL decapsulate noble's
|
|
253
|
+
// ciphertext — the independent impl must derive the same secret.
|
|
254
|
+
var natPriv = nodeCrypto.createPrivateKey({
|
|
255
|
+
key: { kty: "AKP", alg: "ML-KEM-1024", priv: b64u(katSeed), pub: b64u(katKp.publicKey) },
|
|
256
|
+
format: "jwk",
|
|
257
|
+
});
|
|
258
|
+
var natDecaps = nodeCrypto.decapsulate(natPriv, Buffer.from(katEnc.cipherText));
|
|
259
|
+
check("ML-KEM-1024 live: OpenSSL accepts noble's deterministic key + ciphertext",
|
|
260
|
+
Buffer.from(natDecaps).equals(katExpected));
|
|
261
|
+
|
|
262
|
+
// Fresh random keypair, noble encapsulates -> OpenSSL decapsulates.
|
|
263
|
+
var freshSeed = nodeCrypto.randomBytes(64);
|
|
264
|
+
var freshKp = pq.ml_kem_1024.keygen(freshSeed);
|
|
265
|
+
var freshEnc = pq.ml_kem_1024.encapsulate(freshKp.publicKey);
|
|
266
|
+
var freshPriv = nodeCrypto.createPrivateKey({
|
|
267
|
+
key: { kty: "AKP", alg: "ML-KEM-1024", priv: b64u(freshSeed), pub: b64u(freshKp.publicKey) },
|
|
268
|
+
format: "jwk",
|
|
269
|
+
});
|
|
270
|
+
var ossDecaps = nodeCrypto.decapsulate(freshPriv, Buffer.from(freshEnc.cipherText));
|
|
271
|
+
check("ML-KEM-1024 live: noble encaps -> OpenSSL decaps agree",
|
|
272
|
+
Buffer.from(freshEnc.sharedSecret).equals(Buffer.from(ossDecaps)));
|
|
273
|
+
|
|
274
|
+
// Reverse: OpenSSL encapsulates -> noble decapsulates.
|
|
275
|
+
var ossEnc = nodeCrypto.encapsulate(nodeCrypto.createPublicKey(freshPriv));
|
|
276
|
+
var nobleDecaps = pq.ml_kem_1024.decapsulate(ossEnc.ciphertext, freshKp.secretKey);
|
|
277
|
+
check("ML-KEM-1024 live: OpenSSL encaps -> noble decaps agree",
|
|
278
|
+
Buffer.from(ossEnc.sharedKey).equals(Buffer.from(nobleDecaps)));
|
|
279
|
+
|
|
280
|
+
// A different keypair must NOT recover the secret — proves the KEM
|
|
281
|
+
// binds the secret to the key, not to the ciphertext shape.
|
|
282
|
+
var wrongSeed = nodeCrypto.randomBytes(64);
|
|
283
|
+
var wrongKp = pq.ml_kem_1024.keygen(wrongSeed);
|
|
284
|
+
var wrongDecaps = pq.ml_kem_1024.decapsulate(freshEnc.cipherText, wrongKp.secretKey);
|
|
285
|
+
check("ML-KEM-1024 live: wrong secret key does not recover the shared secret",
|
|
286
|
+
!Buffer.from(wrongDecaps).equals(Buffer.from(freshEnc.sharedSecret)));
|
|
287
|
+
} else {
|
|
288
|
+
coverageFindings.push("ML-KEM-1024 live cross-impl (Node native OpenSSL) " +
|
|
289
|
+
"unavailable on this runtime — frozen cross-impl KAT still ran.");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// =====================================================================
|
|
293
|
+
// (3) ML-DSA-87 — spec answer FROM OpenSSL: OpenSSL signs, the
|
|
294
|
+
// framework's noble primitive verifies. Then the reverse.
|
|
295
|
+
// =====================================================================
|
|
296
|
+
|
|
297
|
+
if (nativeMlDsaAvailable()) {
|
|
298
|
+
var dsaSeed = nodeCrypto.randomBytes(32);
|
|
299
|
+
var dsaKp = pq.ml_dsa_87.keygen(dsaSeed);
|
|
300
|
+
check("ML-DSA-87: keygen pk size (FIPS 204 |pk|=2592)", dsaKp.publicKey.length === 2592);
|
|
301
|
+
|
|
302
|
+
var dsaMsg = Buffer.from("cross-impl ML-DSA-87 known-answer message", "utf8");
|
|
303
|
+
// Import noble's (seed, pk) into OpenSSL; OpenSSL is the signer.
|
|
304
|
+
var dsaNatPriv = nodeCrypto.createPrivateKey({
|
|
305
|
+
key: { kty: "AKP", alg: "ML-DSA-87", priv: b64u(dsaSeed), pub: b64u(dsaKp.publicKey) },
|
|
306
|
+
format: "jwk",
|
|
307
|
+
});
|
|
308
|
+
var ossSig = nodeCrypto.sign(null, dsaMsg, dsaNatPriv);
|
|
309
|
+
check("ML-DSA-87: OpenSSL produced a non-empty signature", ossSig.length > 0);
|
|
310
|
+
// The framework's pure-JS verifier accepts an OpenSSL-produced sig.
|
|
311
|
+
check("ML-DSA-87: noble verifies an OpenSSL-signed message (spec answer = accept)",
|
|
312
|
+
pq.ml_dsa_87.verify(Buffer.from(ossSig), dsaMsg, dsaKp.publicKey) === true);
|
|
313
|
+
// Tamper the OpenSSL signature -> noble must reject.
|
|
314
|
+
var ossSigTamp = Buffer.from(ossSig); ossSigTamp[0] ^= 0xff;
|
|
315
|
+
check("ML-DSA-87: noble rejects a tampered OpenSSL signature",
|
|
316
|
+
pq.ml_dsa_87.verify(ossSigTamp, dsaMsg, dsaKp.publicKey) === false);
|
|
317
|
+
// Wrong message -> noble must reject.
|
|
318
|
+
check("ML-DSA-87: noble rejects an OpenSSL sig over a different message",
|
|
319
|
+
pq.ml_dsa_87.verify(Buffer.from(ossSig),
|
|
320
|
+
Buffer.from("different message", "utf8"), dsaKp.publicKey) === false);
|
|
321
|
+
|
|
322
|
+
// Reverse: noble signs -> OpenSSL verifies (spec answer = accept).
|
|
323
|
+
var nobleSig = pq.ml_dsa_87.sign(dsaMsg, dsaKp.secretKey);
|
|
324
|
+
var dsaNatPub = nodeCrypto.createPublicKey(dsaNatPriv);
|
|
325
|
+
check("ML-DSA-87: OpenSSL verifies a noble-signed message",
|
|
326
|
+
nodeCrypto.verify(null, dsaMsg, dsaNatPub, Buffer.from(nobleSig)) === true);
|
|
327
|
+
} else {
|
|
328
|
+
coverageFindings.push("ML-DSA-87 cross-impl (Node native OpenSSL) unavailable " +
|
|
329
|
+
"on this runtime — no off-framework signature oracle exercised for ML-DSA-87.");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// =====================================================================
|
|
333
|
+
// (4) SLH-DSA-SHAKE-256f — spec answer FROM OpenSSL, same shape.
|
|
334
|
+
// =====================================================================
|
|
335
|
+
|
|
336
|
+
if (nativeSlhDsaAvailable()) {
|
|
337
|
+
var slh = pq.slh_dsa_shake_256f;
|
|
338
|
+
var slhKp = slh.keygen();
|
|
339
|
+
check("SLH-DSA-SHAKE-256f: keygen pk size (FIPS 205 |pk|=64)", slhKp.publicKey.length === 64);
|
|
340
|
+
|
|
341
|
+
var slhMsg = Buffer.from("cross-impl SLH-DSA-SHAKE-256f known-answer message", "utf8");
|
|
342
|
+
// OpenSSL is the signer. Native SLH-DSA's JWK private field is the
|
|
343
|
+
// full secret key, which matches noble's secretKey byte layout.
|
|
344
|
+
var slhNatPriv = nodeCrypto.createPrivateKey({
|
|
345
|
+
key: { kty: "AKP", alg: "SLH-DSA-SHAKE-256f", priv: b64u(slhKp.secretKey), pub: b64u(slhKp.publicKey) },
|
|
346
|
+
format: "jwk",
|
|
347
|
+
});
|
|
348
|
+
var slhOssSig = nodeCrypto.sign(null, slhMsg, slhNatPriv);
|
|
349
|
+
check("SLH-DSA-SHAKE-256f: OpenSSL produced a non-empty signature", slhOssSig.length > 0);
|
|
350
|
+
check("SLH-DSA-SHAKE-256f: noble verifies an OpenSSL-signed message (spec answer = accept)",
|
|
351
|
+
slh.verify(Buffer.from(slhOssSig), slhMsg, slhKp.publicKey) === true);
|
|
352
|
+
var slhTamp = Buffer.from(slhOssSig); slhTamp[0] ^= 0xff;
|
|
353
|
+
check("SLH-DSA-SHAKE-256f: noble rejects a tampered OpenSSL signature",
|
|
354
|
+
slh.verify(slhTamp, slhMsg, slhKp.publicKey) === false);
|
|
355
|
+
|
|
356
|
+
// Reverse: noble signs -> OpenSSL verifies.
|
|
357
|
+
var slhNobleSig = slh.sign(slhMsg, slhKp.secretKey);
|
|
358
|
+
var slhNatPub = nodeCrypto.createPublicKey(slhNatPriv);
|
|
359
|
+
check("SLH-DSA-SHAKE-256f: OpenSSL verifies a noble-signed message",
|
|
360
|
+
nodeCrypto.verify(null, slhMsg, slhNatPub, Buffer.from(slhNobleSig)) === true);
|
|
361
|
+
} else {
|
|
362
|
+
coverageFindings.push("SLH-DSA-SHAKE-256f cross-impl (Node native OpenSSL) " +
|
|
363
|
+
"unavailable on this runtime — no off-framework signature oracle exercised for SLH-DSA.");
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// =====================================================================
|
|
367
|
+
// Coverage findings — where no independent oracle was achievable.
|
|
368
|
+
// COSE_Sign1 (b.cose.sign) and PGP (b.mail.crypto.pgp) are NOT proven
|
|
369
|
+
// here against an external verifier; an independent CBOR Sig_structure
|
|
370
|
+
// reconstruction (COSE) and a GnuPG cross-verify (PGP) are the next
|
|
371
|
+
// oracles to build. b.crypto.selfTest's PQC legs remain
|
|
372
|
+
// pairwise-only — this file is the independent KAT coverage they lack.
|
|
373
|
+
// =====================================================================
|
|
374
|
+
coverageFindings.push("COSE_Sign1 (b.cose.sign) NOT verified against an independent " +
|
|
375
|
+
"oracle here — requires a from-scratch CBOR Sig_structure verifier.");
|
|
376
|
+
coverageFindings.push("PGP (b.mail.crypto.pgp) NOT cross-verified against GnuPG here — " +
|
|
377
|
+
"requires gpg in PATH (not assumed in layer-0).");
|
|
378
|
+
coverageFindings.push("b.crypto.selfTest's ML-KEM/ML-DSA/SLH-DSA legs remain " +
|
|
379
|
+
"pairwise-consistency only; this file supplies the independent-oracle / frozen-KAT coverage.");
|
|
380
|
+
|
|
381
|
+
if (coverageFindings.length) {
|
|
382
|
+
console.log("Coverage findings:");
|
|
383
|
+
coverageFindings.forEach(function (f) { console.log(" - " + f); });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
console.log("OK — crypto-interop-oracles tests");
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
module.exports = { run: run };
|
|
390
|
+
if (require.main === module) {
|
|
391
|
+
try { run(); process.exit(0); } catch (e) { console.error(e); process.exit(1); }
|
|
392
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* b.middleware.csrfProtect — cookie-header parsing prototype-pollution
|
|
4
|
+
* defense (CWE-915 / CWE-1321) + double-submit success path.
|
|
5
|
+
*
|
|
6
|
+
* The Cookie request header is attacker-controlled. The internal cookie
|
|
7
|
+
* parser builds its map from [name, value] pairs through
|
|
8
|
+
* Object.fromEntries onto a null-prototype object — never a computed-
|
|
9
|
+
* write (`out[name] = value`) sink. These tests drive the middleware
|
|
10
|
+
* end-to-end (no internal mocks) to verify:
|
|
11
|
+
* - a Cookie header carrying `__proto__` / `constructor` / `prototype`
|
|
12
|
+
* names does NOT pollute Object.prototype;
|
|
13
|
+
* - a legitimate CSRF cookie alongside those hostile names still
|
|
14
|
+
* resolves and the double-submit check passes (header token matches);
|
|
15
|
+
* - first-occurrence-wins is preserved for duplicate cookie names.
|
|
16
|
+
*
|
|
17
|
+
* Run standalone: `node test/layer-0-primitives/csrf-protect.test.js`
|
|
18
|
+
* Or via smoke: `node test/smoke.js`
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
var helpers = require("../helpers");
|
|
22
|
+
var b = helpers.b;
|
|
23
|
+
var check = helpers.check;
|
|
24
|
+
var _mockReq = helpers._mockReq;
|
|
25
|
+
var _mockRes = helpers._mockRes;
|
|
26
|
+
|
|
27
|
+
// Drive one request through the csrf middleware; resolve to an outcome
|
|
28
|
+
// object describing whether next() was called or the request was denied.
|
|
29
|
+
function _runCsrf(mwOpts, req) {
|
|
30
|
+
var res = _mockRes();
|
|
31
|
+
return new Promise(function (resolve) {
|
|
32
|
+
var calledNext = false;
|
|
33
|
+
var mw = b.middleware.csrfProtect(mwOpts);
|
|
34
|
+
// denyResponse writes to res + ends it; next() is the success signal.
|
|
35
|
+
// mockRes captures the status via writeHead → res._captured().status.
|
|
36
|
+
var origEnd = res.end;
|
|
37
|
+
res.end = function () {
|
|
38
|
+
var r = origEnd.apply(res, arguments);
|
|
39
|
+
var cap = res._captured();
|
|
40
|
+
resolve({ outcome: "denied", status: cap.status, body: cap.body, req: req, res: res, calledNext: calledNext });
|
|
41
|
+
return r;
|
|
42
|
+
};
|
|
43
|
+
mw(req, res, function () {
|
|
44
|
+
calledNext = true;
|
|
45
|
+
resolve({ outcome: "next", req: req, res: res, calledNext: true });
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function testSuccessPathDoubleSubmit() {
|
|
51
|
+
// Valid 64-hex cookie + matching X-CSRF-Token header on a POST → next().
|
|
52
|
+
var token = b.forms.generateCsrfToken();
|
|
53
|
+
var req = _mockReq({
|
|
54
|
+
method: "POST",
|
|
55
|
+
url: "/submit",
|
|
56
|
+
headers: {
|
|
57
|
+
host: "example.com",
|
|
58
|
+
cookie: "csrf=" + token,
|
|
59
|
+
"x-csrf-token": token,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
var r = await _runCsrf({ cookie: true }, req);
|
|
63
|
+
check("csrf: valid double-submit passes (next called)", r.outcome === "next");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function testMismatchDenied() {
|
|
67
|
+
var token = b.forms.generateCsrfToken();
|
|
68
|
+
var req = _mockReq({
|
|
69
|
+
method: "POST",
|
|
70
|
+
url: "/submit",
|
|
71
|
+
headers: {
|
|
72
|
+
host: "example.com",
|
|
73
|
+
cookie: "csrf=" + token,
|
|
74
|
+
"x-csrf-token": b.forms.generateCsrfToken(), // different token
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
var r = await _runCsrf({ cookie: true }, req);
|
|
78
|
+
check("csrf: token mismatch denied (403)", r.outcome === "denied" && r.status === 403);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function testPoisonedCookieNamesDoNotPollute() {
|
|
82
|
+
// A Cookie header carrying __proto__ / constructor / prototype names
|
|
83
|
+
// alongside the real csrf cookie must not pollute Object.prototype, and
|
|
84
|
+
// the legitimate cookie must still resolve so the double-submit passes.
|
|
85
|
+
var token = b.forms.generateCsrfToken();
|
|
86
|
+
var req = _mockReq({
|
|
87
|
+
method: "POST",
|
|
88
|
+
url: "/submit",
|
|
89
|
+
headers: {
|
|
90
|
+
host: "example.com",
|
|
91
|
+
cookie: "__proto__=polluted; constructor=evil; prototype=evil2; csrf=" + token + "; other=ok",
|
|
92
|
+
"x-csrf-token": token,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
var r = await _runCsrf({ cookie: true }, req);
|
|
96
|
+
check("csrf: hostile cookie names did not pollute Object.prototype",
|
|
97
|
+
({}).polluted === undefined &&
|
|
98
|
+
Object.prototype.polluted === undefined &&
|
|
99
|
+
({}).evil === undefined &&
|
|
100
|
+
({}).evil2 === undefined);
|
|
101
|
+
check("csrf: legitimate cookie still resolved (double-submit passed)",
|
|
102
|
+
r.outcome === "next");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function testFirstOccurrenceWinsForDuplicateCookie() {
|
|
106
|
+
// RFC 6265 §5.2 — duplicate cookie names resolve to the FIRST occurrence
|
|
107
|
+
// (most-specific path). A later forged `csrf=` must not override the
|
|
108
|
+
// first; the double-submit must validate against the first value.
|
|
109
|
+
var first = b.forms.generateCsrfToken();
|
|
110
|
+
var second = b.forms.generateCsrfToken();
|
|
111
|
+
var req = _mockReq({
|
|
112
|
+
method: "POST",
|
|
113
|
+
url: "/submit",
|
|
114
|
+
headers: {
|
|
115
|
+
host: "example.com",
|
|
116
|
+
cookie: "csrf=" + first + "; csrf=" + second,
|
|
117
|
+
"x-csrf-token": first, // matches FIRST occurrence
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
var r = await _runCsrf({ cookie: true }, req);
|
|
121
|
+
check("csrf: duplicate cookie resolves to first occurrence (next on first-token submit)",
|
|
122
|
+
r.outcome === "next");
|
|
123
|
+
|
|
124
|
+
// Submitting the SECOND value must be rejected — proves first-wins, not
|
|
125
|
+
// last-wins.
|
|
126
|
+
var req2 = _mockReq({
|
|
127
|
+
method: "POST",
|
|
128
|
+
url: "/submit",
|
|
129
|
+
headers: {
|
|
130
|
+
host: "example.com",
|
|
131
|
+
cookie: "csrf=" + first + "; csrf=" + second,
|
|
132
|
+
"x-csrf-token": second,
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
var r2 = await _runCsrf({ cookie: true }, req2);
|
|
136
|
+
check("csrf: submitting the second (shadowed) cookie value is denied",
|
|
137
|
+
r2.outcome === "denied" && r2.status === 403);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function run() {
|
|
141
|
+
await testSuccessPathDoubleSubmit();
|
|
142
|
+
await testMismatchDenied();
|
|
143
|
+
await testPoisonedCookieNamesDoNotPollute();
|
|
144
|
+
await testFirstOccurrenceWinsForDuplicateCookie();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = { run: run };
|
|
148
|
+
|
|
149
|
+
if (require.main === module) {
|
|
150
|
+
run().then(
|
|
151
|
+
function () { console.log("OK — " + helpers.getChecks() + " checks passed"); },
|
|
152
|
+
// Re-throw rather than logging e.message: the failure message can
|
|
153
|
+
// echo request-derived cookie names/values fed into the middleware,
|
|
154
|
+
// and writing that to the log unescaped would be log injection
|
|
155
|
+
// (CWE-117). The non-zero exit + thrown stack still surface the
|
|
156
|
+
// failure to the runner.
|
|
157
|
+
function (e) { process.exitCode = 1; throw e; }
|
|
158
|
+
);
|
|
159
|
+
}
|