@blamejs/blamejs-shop 0.5.12 → 0.5.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/lib/asset-manifest.json +1 -1
- package/lib/sales-tax-filings.js +143 -0
- package/lib/vendor/MANIFEST.json +632 -416
- package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
- package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
- package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
- package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
- package/lib/vendor/blamejs/.gitignore +2 -0
- package/lib/vendor/blamejs/CHANGELOG.md +122 -0
- package/lib/vendor/blamejs/NOTICE +26 -1
- package/lib/vendor/blamejs/SECURITY.md +1 -1
- package/lib/vendor/blamejs/api-snapshot.json +207 -5
- package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
- package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
- package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
- package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
- package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
- package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
- package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
- package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
- package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
- package/lib/vendor/blamejs/index.js +6 -0
- package/lib/vendor/blamejs/lib/a2a.js +4 -4
- package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
- package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
- package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
- package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
- package/lib/vendor/blamejs/lib/archive-read.js +8 -0
- package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
- package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
- package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
- package/lib/vendor/blamejs/lib/audit.js +71 -8
- package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
- package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
- package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
- package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
- package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
- package/lib/vendor/blamejs/lib/backup/index.js +16 -5
- package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
- package/lib/vendor/blamejs/lib/base32.js +21 -0
- package/lib/vendor/blamejs/lib/break-glass.js +19 -10
- package/lib/vendor/blamejs/lib/bundler.js +5 -1
- package/lib/vendor/blamejs/lib/cache-status.js +3 -7
- package/lib/vendor/blamejs/lib/calendar.js +21 -1
- package/lib/vendor/blamejs/lib/cbor.js +12 -1
- package/lib/vendor/blamejs/lib/cert.js +29 -11
- package/lib/vendor/blamejs/lib/cli.js +94 -24
- package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
- package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
- package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
- package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
- package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
- package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
- package/lib/vendor/blamejs/lib/content-digest.js +2 -1
- package/lib/vendor/blamejs/lib/cookies.js +13 -3
- package/lib/vendor/blamejs/lib/cose.js +31 -16
- package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
- package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
- package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
- package/lib/vendor/blamejs/lib/crypto.js +314 -19
- package/lib/vendor/blamejs/lib/csp.js +11 -3
- package/lib/vendor/blamejs/lib/daemon.js +270 -24
- package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
- package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
- package/lib/vendor/blamejs/lib/db-query.js +34 -7
- package/lib/vendor/blamejs/lib/db.js +18 -6
- package/lib/vendor/blamejs/lib/dbsc.js +17 -0
- package/lib/vendor/blamejs/lib/dev.js +21 -2
- package/lib/vendor/blamejs/lib/dsr.js +157 -102
- package/lib/vendor/blamejs/lib/external-db.js +41 -2
- package/lib/vendor/blamejs/lib/file-upload.js +25 -7
- package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
- package/lib/vendor/blamejs/lib/forms.js +113 -27
- package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
- package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
- package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
- package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
- package/lib/vendor/blamejs/lib/guard-html.js +26 -53
- package/lib/vendor/blamejs/lib/guard-image.js +24 -5
- package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
- package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
- package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
- package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
- package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
- package/lib/vendor/blamejs/lib/guard-time.js +1 -1
- package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
- package/lib/vendor/blamejs/lib/html-balance.js +3 -3
- package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
- package/lib/vendor/blamejs/lib/http-client.js +39 -7
- package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
- package/lib/vendor/blamejs/lib/i18n.js +35 -21
- package/lib/vendor/blamejs/lib/incident-report.js +8 -1
- package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
- package/lib/vendor/blamejs/lib/json-path.js +23 -1
- package/lib/vendor/blamejs/lib/jwk.js +20 -3
- package/lib/vendor/blamejs/lib/link-header.js +2 -1
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
- package/lib/vendor/blamejs/lib/log-stream.js +8 -3
- package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
- package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
- package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
- package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
- package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
- package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
- package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
- package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
- package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
- package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
- package/lib/vendor/blamejs/lib/mail.js +15 -5
- package/lib/vendor/blamejs/lib/metrics.js +268 -63
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
- package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
- package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
- package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
- package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
- package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
- package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
- package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
- package/lib/vendor/blamejs/lib/network-dns.js +21 -2
- package/lib/vendor/blamejs/lib/network-tls.js +69 -7
- package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
- package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
- package/lib/vendor/blamejs/lib/outbox.js +1 -1
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
- package/lib/vendor/blamejs/lib/permissions.js +6 -3
- package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
- package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
- package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
- package/lib/vendor/blamejs/lib/pubsub.js +20 -9
- package/lib/vendor/blamejs/lib/queue-local.js +8 -1
- package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
- package/lib/vendor/blamejs/lib/redact.js +54 -0
- package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
- package/lib/vendor/blamejs/lib/restore.js +19 -0
- package/lib/vendor/blamejs/lib/retention.js +12 -4
- package/lib/vendor/blamejs/lib/router.js +60 -6
- package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
- package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
- package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
- package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
- package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
- package/lib/vendor/blamejs/lib/safe-object.js +80 -0
- package/lib/vendor/blamejs/lib/safe-path.js +52 -4
- package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
- package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
- package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
- package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
- package/lib/vendor/blamejs/lib/scheduler.js +8 -1
- package/lib/vendor/blamejs/lib/security-assert.js +6 -6
- package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
- package/lib/vendor/blamejs/lib/self-update.js +517 -87
- package/lib/vendor/blamejs/lib/server-timing.js +2 -4
- package/lib/vendor/blamejs/lib/session.js +34 -12
- package/lib/vendor/blamejs/lib/sql.js +15 -1
- package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
- package/lib/vendor/blamejs/lib/static.js +55 -13
- package/lib/vendor/blamejs/lib/storage.js +8 -2
- package/lib/vendor/blamejs/lib/subject.js +6 -1
- package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
- package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
- package/lib/vendor/blamejs/lib/tsa.js +34 -13
- package/lib/vendor/blamejs/lib/uri-template.js +8 -1
- package/lib/vendor/blamejs/lib/vault/index.js +13 -0
- package/lib/vendor/blamejs/lib/vc.js +44 -5
- package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
- package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
- package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
- package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
- package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
- package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
- package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
- package/lib/vendor/blamejs/lib/watcher.js +89 -17
- package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
- package/lib/vendor/blamejs/lib/webhook.js +12 -2
- package/lib/vendor/blamejs/lib/ws-client.js +32 -1
- package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
- package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
- package/lib/vendor/blamejs/package-lock.json +2 -2
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
- package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
- package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
- package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
- package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
- package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
- package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
- package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
- package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
- package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
- package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
- package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
- package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
- package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
- package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
- package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
- package/lib/vendor/blamejs/socket.yml +94 -0
- package/lib/vendor/blamejs/test/00-primitives.js +605 -0
- package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
- package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
- package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
- package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
- package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
- package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
- package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
- package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
- package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
- package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
- package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
- package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
- package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
- package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
- package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
- package/lib/vendor/blamejs/test/smoke.js +2 -0
- package/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
- package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
- package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
- package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
- package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
- package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
- package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
- package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
- package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
- package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
- package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
- package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
- package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
- package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
|
@@ -0,0 +1,699 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) blamejs contributors
|
|
3
|
+
"use strict";
|
|
4
|
+
/**
|
|
5
|
+
* b.network.ntp.nts — NTS (RFC 8915) key-establishment + protected NTPv4
|
|
6
|
+
* exchange. This canonical suite drives the UNCOVERED error / adversarial /
|
|
7
|
+
* defensive / option-default branches of the primitive through its real
|
|
8
|
+
* consumer path:
|
|
9
|
+
*
|
|
10
|
+
* - AES-SIV-CMAC (RFC 5297) encrypt/decrypt roundtrip + bad-key +
|
|
11
|
+
* tamper-detection, exercising the s2v/cmac/ctr internals for 32/48/64
|
|
12
|
+
* byte keys and both short- and long-plaintext code paths.
|
|
13
|
+
* - performKeHandshake against a loopback TLS "ntske/1" server that
|
|
14
|
+
* returns each adversarial record shape (error record, missing/short
|
|
15
|
+
* AEAD, unsupported AEAD, no cookies, over-long record) plus the
|
|
16
|
+
* success path (real TLS exporter keys) and the fail-closed guards
|
|
17
|
+
* (bad ALPN, wall-clock timeout, socket reset).
|
|
18
|
+
* - querySingle against a loopback UDP server that crafts each hostile
|
|
19
|
+
* reply (too-short, unique-id mismatch, malformed extension, missing/
|
|
20
|
+
* truncated/overlong authenticator, AEAD verification failure) plus
|
|
21
|
+
* authenticated success for BOTH AEADs, exercising cookie rotation and
|
|
22
|
+
* the encrypted-extension walk.
|
|
23
|
+
* - query end-to-end: a loopback KE server exports the same TLS keying
|
|
24
|
+
* material its sibling UDP server uses to authenticate the reply, so
|
|
25
|
+
* the full govern→handshake→protected-query path resolves.
|
|
26
|
+
*
|
|
27
|
+
* No real network is touched — every server is a 127.0.0.1 listener and
|
|
28
|
+
* every key is injected. Adversarial packets assert the primitive fails
|
|
29
|
+
* closed with an `nts/*` typed error.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
var helpers = require("../helpers");
|
|
33
|
+
var check = helpers.check;
|
|
34
|
+
var b = helpers.b;
|
|
35
|
+
var nodeTls = require("node:tls");
|
|
36
|
+
var dgram = require("node:dgram");
|
|
37
|
+
var net = require("node:net");
|
|
38
|
+
var nodeCrypto = require("node:crypto");
|
|
39
|
+
|
|
40
|
+
// NTS-KE record types (RFC 8915 §4) and NTPv4 extension-field types
|
|
41
|
+
// (§5.3-5.7). Mirrored here so the test constructs on-wire bytes without
|
|
42
|
+
// reaching into the module's private encoders.
|
|
43
|
+
var REC_END = 0;
|
|
44
|
+
var REC_NEXT_PROTOCOL = 1;
|
|
45
|
+
var REC_ERROR = 2;
|
|
46
|
+
var REC_WARNING = 3;
|
|
47
|
+
var REC_AEAD = 4;
|
|
48
|
+
var REC_NEW_COOKIE = 5;
|
|
49
|
+
var REC_NTPV4_SERVER = 6;
|
|
50
|
+
var REC_NTPV4_PORT = 7;
|
|
51
|
+
|
|
52
|
+
var EXT_UNIQUE = 0x0104;
|
|
53
|
+
var EXT_COOKIE = 0x0204;
|
|
54
|
+
var EXT_AUTH = 0x0404;
|
|
55
|
+
|
|
56
|
+
var NTP_HEADER_BYTES = 48;
|
|
57
|
+
var NTP_EPOCH_OFFSET = 2208988800;
|
|
58
|
+
var EXPORTER_LABEL = "EXPORTER-network-time-security";
|
|
59
|
+
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// On-wire byte builders (test-local; the lib's encoders are private).
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
function _u16(v) { var buf = Buffer.alloc(2); buf.writeUInt16BE(v, 0); return buf; }
|
|
65
|
+
|
|
66
|
+
// NTS-KE record: u16 (critical<<15 | type) || u16 body-len || body.
|
|
67
|
+
function _rec(critical, type, body) {
|
|
68
|
+
var hdr = Buffer.alloc(4);
|
|
69
|
+
var tf = type & 0x7fff;
|
|
70
|
+
if (critical) tf |= 0x8000;
|
|
71
|
+
hdr.writeUInt16BE(tf, 0);
|
|
72
|
+
hdr.writeUInt16BE(body.length, 2);
|
|
73
|
+
return Buffer.concat([hdr, body]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// NTPv4 extension field, RFC 7822 4-byte alignment (matches the module's
|
|
77
|
+
// private _encodeExtensionField): u16 type || u16 (paddedBody+4) || body.
|
|
78
|
+
function _ext(type, body) {
|
|
79
|
+
var padLen = (4 - (body.length % 4)) % 4;
|
|
80
|
+
var padded = padLen === 0 ? body : Buffer.concat([body, Buffer.alloc(padLen)]);
|
|
81
|
+
var hdr = Buffer.alloc(4);
|
|
82
|
+
hdr.writeUInt16BE(type, 0);
|
|
83
|
+
hdr.writeUInt16BE(padded.length + 4, 2);
|
|
84
|
+
return Buffer.concat([hdr, padded]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Raw extension with a caller-chosen length field — for adversarial replies
|
|
88
|
+
// whose declared length disagrees with the body (truncated / overrun).
|
|
89
|
+
function _rawExt(type, len, body) {
|
|
90
|
+
var hdr = Buffer.alloc(4);
|
|
91
|
+
hdr.writeUInt16BE(type, 0);
|
|
92
|
+
hdr.writeUInt16BE(len, 2);
|
|
93
|
+
return Buffer.concat([hdr, body]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Locate an extension body inside a request/reply, walking from startOff.
|
|
97
|
+
function _findExtBody(msg, startOff, type) {
|
|
98
|
+
var off = startOff;
|
|
99
|
+
while (off + 4 <= msg.length) {
|
|
100
|
+
var t = msg.readUInt16BE(off);
|
|
101
|
+
var len = msg.readUInt16BE(off + 2);
|
|
102
|
+
if (len < 4 || off + len > msg.length) break;
|
|
103
|
+
if (t === type) return msg.slice(off + 4, off + len);
|
|
104
|
+
off += len;
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Mirror of the module's private _aeadEncrypt so a test UDP server can forge
|
|
110
|
+
// an authenticator the client will actually verify. Uses the public
|
|
111
|
+
// aesSivEncrypt primitive for the SIV branch.
|
|
112
|
+
function _aeadEncryptMirror(aeadId, key, nonce, plaintext, aad) {
|
|
113
|
+
if (aeadId === b.network.ntp.nts.AEAD_AES_SIV_CMAC_256) {
|
|
114
|
+
return b.network.ntp.nts.aesSivEncrypt(key, plaintext, [aad, nonce]);
|
|
115
|
+
}
|
|
116
|
+
var c = nodeCrypto.createCipheriv("chacha20-poly1305", key, nonce, { authTagLength: 16 });
|
|
117
|
+
c.setAAD(aad, { plaintextLength: plaintext.length });
|
|
118
|
+
var ct = Buffer.concat([c.update(plaintext), c.final()]);
|
|
119
|
+
return Buffer.concat([ct, c.getAuthTag()]);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Build a fully-formed protected NTPv4 reply: NTP header || unique-id ext ||
|
|
123
|
+
// authenticator ext, with the authenticator computed over the packet prefix
|
|
124
|
+
// exactly as the client recomputes its AAD (msg up to the authenticator).
|
|
125
|
+
function _buildReply(opts) {
|
|
126
|
+
var ntp = Buffer.alloc(NTP_HEADER_BYTES);
|
|
127
|
+
var secs = (Math.floor(Date.now() / 1000) + NTP_EPOCH_OFFSET) >>> 0;
|
|
128
|
+
ntp.writeUInt32BE(secs, 40);
|
|
129
|
+
ntp.writeUInt32BE(0, 44);
|
|
130
|
+
var uniqueExt = _ext(EXT_UNIQUE, opts.uniqueId);
|
|
131
|
+
var prefix = Buffer.concat([ntp, uniqueExt]);
|
|
132
|
+
var isSiv = opts.aeadId === b.network.ntp.nts.AEAD_AES_SIV_CMAC_256;
|
|
133
|
+
var nonce = nodeCrypto.randomBytes(isSiv ? 16 : 12);
|
|
134
|
+
var plaintext = opts.plaintext || Buffer.alloc(0);
|
|
135
|
+
var ct = _aeadEncryptMirror(opts.aeadId, opts.s2cKey, nonce, plaintext, prefix);
|
|
136
|
+
if (opts.corruptCt) { ct = Buffer.from(ct); ct[ct.length - 1] ^= 0xff; }
|
|
137
|
+
var authBody = Buffer.alloc(4 + nonce.length + ct.length);
|
|
138
|
+
authBody.writeUInt16BE(nonce.length, 0);
|
|
139
|
+
authBody.writeUInt16BE(ct.length, 2);
|
|
140
|
+
nonce.copy(authBody, 4);
|
|
141
|
+
ct.copy(authBody, 4 + nonce.length);
|
|
142
|
+
return Buffer.concat([prefix, _ext(EXT_AUTH, authBody)]);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
// Loopback listeners.
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
async function _makeCert() {
|
|
150
|
+
var ca = await b.mtlsEngine.generateCa({ name: "nts-test-ca" });
|
|
151
|
+
var leaf = await b.mtlsEngine.signClientCert({
|
|
152
|
+
cn: "localhost",
|
|
153
|
+
caCertPem: ca.caCertPem,
|
|
154
|
+
caKeyPem: ca.caKeyPem,
|
|
155
|
+
usage: "server",
|
|
156
|
+
sans: ["DNS:localhost", "IP:127.0.0.1"],
|
|
157
|
+
validityDays: 1,
|
|
158
|
+
});
|
|
159
|
+
return { ca: ca, leaf: leaf };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// cfg.onData(sock) → Buffer (written back) or null (stay silent). cfg.setAlpn
|
|
163
|
+
// false omits ALPNProtocols so the client sees a non-"ntske/1" negotiation.
|
|
164
|
+
function _startKeServer(cert, cfg) {
|
|
165
|
+
return new Promise(function (resolve) {
|
|
166
|
+
var tlsOpts = {
|
|
167
|
+
key: cert.leaf.key,
|
|
168
|
+
cert: cert.leaf.cert,
|
|
169
|
+
minVersion: "TLSv1.3",
|
|
170
|
+
maxVersion: "TLSv1.3",
|
|
171
|
+
};
|
|
172
|
+
if (cfg.setAlpn !== false) tlsOpts.ALPNProtocols = ["ntske/1"];
|
|
173
|
+
var server = nodeTls.createServer(tlsOpts, function (sock) {
|
|
174
|
+
sock.on("error", function () { /* client tears down on the reject path */ });
|
|
175
|
+
sock.once("data", function () {
|
|
176
|
+
var resp = cfg.onData ? cfg.onData(sock) : null;
|
|
177
|
+
if (resp && resp.length) { try { sock.write(resp); } catch (_e) { /* raced teardown */ } }
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
server.on("error", function () { /* best-effort loopback listener */ });
|
|
181
|
+
server.listen(0, "127.0.0.1", function () {
|
|
182
|
+
resolve({ server: server, port: server.address().port });
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function _startUdpServer(onMessage) {
|
|
188
|
+
return new Promise(function (resolve) {
|
|
189
|
+
var sock = dgram.createSocket("udp4");
|
|
190
|
+
sock.on("error", function () { /* best-effort loopback listener */ });
|
|
191
|
+
sock.on("message", function (msg, rinfo) { onMessage(msg, rinfo, sock); });
|
|
192
|
+
sock.bind(0, "127.0.0.1", function () {
|
|
193
|
+
resolve({ sock: sock, port: sock.address().port });
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
// AES-SIV-CMAC crypto internals (RFC 5297).
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
|
|
202
|
+
function testAesSivRoundtrip() {
|
|
203
|
+
var K = nodeCrypto.randomBytes(32);
|
|
204
|
+
var ad = [Buffer.from("associated-one"), Buffer.from("associated-two")];
|
|
205
|
+
|
|
206
|
+
// Plaintext > one AES block exercises the s2v head/tail xor path.
|
|
207
|
+
var longPt = Buffer.from("the quick brown fox jumps over the lazy dog twice");
|
|
208
|
+
var ct = b.network.ntp.nts.aesSivEncrypt(K, longPt, ad);
|
|
209
|
+
check("SIV roundtrip 32-byte key, multi-block plaintext",
|
|
210
|
+
b.network.ntp.nts.aesSivDecrypt(K, ct, ad).equals(longPt));
|
|
211
|
+
|
|
212
|
+
// Plaintext < one AES block exercises the s2v pad-and-double path.
|
|
213
|
+
var shortPt = Buffer.from("hi");
|
|
214
|
+
var ctShort = b.network.ntp.nts.aesSivEncrypt(K, shortPt, ad);
|
|
215
|
+
check("SIV roundtrip sub-block plaintext",
|
|
216
|
+
b.network.ntp.nts.aesSivDecrypt(K, ctShort, ad).equals(shortPt));
|
|
217
|
+
|
|
218
|
+
// 48- and 64-byte keys (AES-192/256 halves).
|
|
219
|
+
var K48 = nodeCrypto.randomBytes(48);
|
|
220
|
+
check("SIV roundtrip 48-byte key",
|
|
221
|
+
b.network.ntp.nts.aesSivDecrypt(K48, b.network.ntp.nts.aesSivEncrypt(K48, longPt, ad), ad).equals(longPt));
|
|
222
|
+
var K64 = nodeCrypto.randomBytes(64);
|
|
223
|
+
check("SIV roundtrip 64-byte key",
|
|
224
|
+
b.network.ntp.nts.aesSivDecrypt(K64, b.network.ntp.nts.aesSivEncrypt(K64, longPt, ad), ad).equals(longPt));
|
|
225
|
+
|
|
226
|
+
// Omitted associatedData → the `associatedData || []` default path.
|
|
227
|
+
var ctNoAd = b.network.ntp.nts.aesSivEncrypt(K, longPt);
|
|
228
|
+
check("SIV roundtrip with no associated data",
|
|
229
|
+
b.network.ntp.nts.aesSivDecrypt(K, ctNoAd).equals(longPt));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function testAesSivBadKey() {
|
|
233
|
+
var caught = null;
|
|
234
|
+
try { b.network.ntp.nts.aesSivEncrypt(nodeCrypto.randomBytes(31), Buffer.from("x"), []); }
|
|
235
|
+
catch (e) { caught = e; }
|
|
236
|
+
check("SIV bad-key is NtsError-typed", caught instanceof b.network.ntp.nts.NtsError);
|
|
237
|
+
check("SIV bad-key code", caught && caught.code === "nts/bad-key");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function testAesSivTamperFailsClosed() {
|
|
241
|
+
var K = nodeCrypto.randomBytes(32);
|
|
242
|
+
var pt = Buffer.from("authenticate me if you can");
|
|
243
|
+
var ct = Buffer.from(b.network.ntp.nts.aesSivEncrypt(K, pt, []));
|
|
244
|
+
ct[0] ^= 0xff; // corrupt the synthetic IV (V)
|
|
245
|
+
var caught = null;
|
|
246
|
+
try { b.network.ntp.nts.aesSivDecrypt(K, ct, []); }
|
|
247
|
+
catch (e) { caught = e; }
|
|
248
|
+
check("SIV tamper rejects", caught !== null);
|
|
249
|
+
check("SIV tamper code is nts/auth-failed", caught && caught.code === "nts/auth-failed");
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
// performKeHandshake / querySingle synchronous input validation.
|
|
254
|
+
// ---------------------------------------------------------------------------
|
|
255
|
+
|
|
256
|
+
function testKeInputValidation() {
|
|
257
|
+
var e1 = null;
|
|
258
|
+
try { b.network.ntp.nts.performKeHandshake({}); } catch (e) { e1 = e; }
|
|
259
|
+
check("KE missing host is nts/bad-host", e1 && e1.code === "nts/bad-host");
|
|
260
|
+
|
|
261
|
+
var e2 = null;
|
|
262
|
+
try { b.network.ntp.nts.performKeHandshake({ host: "h", port: 70000 }); } catch (e) { e2 = e; }
|
|
263
|
+
check("KE out-of-range port is nts/bad-ke-port", e2 && e2.code === "nts/bad-ke-port");
|
|
264
|
+
|
|
265
|
+
var e3 = null;
|
|
266
|
+
try { b.network.ntp.nts.performKeHandshake({ host: "h", bogus: 1 }); } catch (e) { e3 = e; }
|
|
267
|
+
check("KE unknown opt rejected", e3 && /unknown option/.test(e3.message));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function testQuerySingleInputValidation() {
|
|
271
|
+
var buf = Buffer.alloc(4);
|
|
272
|
+
var e1 = null;
|
|
273
|
+
try { b.network.ntp.nts.querySingle({ host: "h", port: 99999, c2sKey: buf, s2cKey: buf, cookies: [buf] }); }
|
|
274
|
+
catch (e) { e1 = e; }
|
|
275
|
+
check("querySingle out-of-range port is nts/bad-ntp-port", e1 && e1.code === "nts/bad-ntp-port");
|
|
276
|
+
|
|
277
|
+
var e2 = null;
|
|
278
|
+
try { b.network.ntp.nts.querySingle({ host: "h" }); } catch (e) { e2 = e; }
|
|
279
|
+
check("querySingle missing c2sKey", e2 && e2.code === "nts/no-c2s-key");
|
|
280
|
+
|
|
281
|
+
var e3 = null;
|
|
282
|
+
try { b.network.ntp.nts.querySingle({ host: "h", c2sKey: buf }); } catch (e) { e3 = e; }
|
|
283
|
+
check("querySingle missing s2cKey", e3 && e3.code === "nts/no-s2c-key");
|
|
284
|
+
|
|
285
|
+
var e4 = null;
|
|
286
|
+
try { b.network.ntp.nts.querySingle({ host: "h", c2sKey: buf, s2cKey: buf }); } catch (e) { e4 = e; }
|
|
287
|
+
check("querySingle missing cookies", e4 && e4.code === "nts/no-cookies");
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
// performKeHandshake network paths.
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
|
|
294
|
+
async function _connectKeExpectReject(cert, ke, expectedCode, label, timeoutMs) {
|
|
295
|
+
var caught = null;
|
|
296
|
+
try {
|
|
297
|
+
await helpers.withTestTimeout(label, function () {
|
|
298
|
+
return b.network.ntp.nts.performKeHandshake({
|
|
299
|
+
host: "127.0.0.1",
|
|
300
|
+
port: ke.port,
|
|
301
|
+
servername: "localhost",
|
|
302
|
+
ca: cert.ca.caCertPem,
|
|
303
|
+
timeoutMs: timeoutMs || 4000,
|
|
304
|
+
});
|
|
305
|
+
}, { timeoutMs: 9000 });
|
|
306
|
+
} catch (e) { caught = e; }
|
|
307
|
+
check(label + " rejects", caught !== null);
|
|
308
|
+
check(label + " code=" + expectedCode, caught && caught.code === expectedCode);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async function testKeBadAlpn(cert) {
|
|
312
|
+
var ke = await _startKeServer(cert, { setAlpn: false, onData: null });
|
|
313
|
+
try { await _connectKeExpectReject(cert, ke, "nts/bad-alpn", "KE non-ntske ALPN"); }
|
|
314
|
+
finally { try { ke.server.close(); } catch (_e) { /* best-effort */ } }
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async function testKeAdversarialRecords(cert) {
|
|
318
|
+
var aeadId = b.network.ntp.nts.AEAD_AES_SIV_CMAC_256;
|
|
319
|
+
|
|
320
|
+
var cases = [
|
|
321
|
+
{ label: "KE server error record", code: "nts/ke-error", onData: function () {
|
|
322
|
+
return Buffer.concat([_rec(true, REC_ERROR, _u16(1)), _rec(true, REC_END, Buffer.alloc(0))]);
|
|
323
|
+
} },
|
|
324
|
+
{ label: "KE missing AEAD record", code: "nts/no-aead", onData: function () {
|
|
325
|
+
return _rec(true, REC_END, Buffer.alloc(0));
|
|
326
|
+
} },
|
|
327
|
+
{ label: "KE short AEAD body", code: "nts/no-aead", onData: function () {
|
|
328
|
+
return Buffer.concat([_rec(true, REC_AEAD, Buffer.alloc(1)), _rec(true, REC_END, Buffer.alloc(0))]);
|
|
329
|
+
} },
|
|
330
|
+
{ label: "KE unsupported AEAD", code: "nts/unsupported-aead", onData: function () {
|
|
331
|
+
return Buffer.concat([
|
|
332
|
+
_rec(true, REC_AEAD, _u16(99)),
|
|
333
|
+
_rec(false, REC_NEW_COOKIE, nodeCrypto.randomBytes(16)),
|
|
334
|
+
_rec(true, REC_END, Buffer.alloc(0)),
|
|
335
|
+
]);
|
|
336
|
+
} },
|
|
337
|
+
{ label: "KE no cookies", code: "nts/no-cookies", onData: function () {
|
|
338
|
+
return Buffer.concat([_rec(true, REC_AEAD, _u16(aeadId)), _rec(true, REC_END, Buffer.alloc(0))]);
|
|
339
|
+
} },
|
|
340
|
+
{ label: "KE over-long record", code: "nts/bad-record", onData: function () {
|
|
341
|
+
var h = Buffer.alloc(4);
|
|
342
|
+
h.writeUInt16BE(REC_NEW_COOKIE & 0x7fff, 0);
|
|
343
|
+
h.writeUInt16BE(0xffff, 2); // claims 64 KiB body, sends none
|
|
344
|
+
return h;
|
|
345
|
+
} },
|
|
346
|
+
];
|
|
347
|
+
|
|
348
|
+
for (var i = 0; i < cases.length; i++) {
|
|
349
|
+
var c = cases[i];
|
|
350
|
+
var ke = await _startKeServer(cert, { onData: c.onData });
|
|
351
|
+
try { await _connectKeExpectReject(cert, ke, c.code, c.label); }
|
|
352
|
+
finally { try { ke.server.close(); } catch (_e) { /* best-effort */ } }
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function testKeSuccess(cert) {
|
|
357
|
+
var aeadId = b.network.ntp.nts.AEAD_AES_SIV_CMAC_256;
|
|
358
|
+
// No REC_NTPV4_SERVER / REC_NTPV4_PORT → the defaults (opts.host, 123)
|
|
359
|
+
// branches; a warning record → the warnings-capture branch.
|
|
360
|
+
var ke = await _startKeServer(cert, { onData: function () {
|
|
361
|
+
return Buffer.concat([
|
|
362
|
+
_rec(true, REC_NEXT_PROTOCOL, _u16(0)),
|
|
363
|
+
_rec(true, REC_AEAD, _u16(aeadId)),
|
|
364
|
+
_rec(false, REC_WARNING, _u16(7)),
|
|
365
|
+
_rec(false, REC_NEW_COOKIE, nodeCrypto.randomBytes(32)),
|
|
366
|
+
_rec(true, REC_END, Buffer.alloc(0)),
|
|
367
|
+
]);
|
|
368
|
+
} });
|
|
369
|
+
try {
|
|
370
|
+
var res = await helpers.withTestTimeout("KE handshake success", function () {
|
|
371
|
+
return b.network.ntp.nts.performKeHandshake({
|
|
372
|
+
host: "127.0.0.1", port: ke.port, servername: "localhost",
|
|
373
|
+
ca: cert.ca.caCertPem, timeoutMs: 4000,
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
check("KE success negotiates SIV", res.aeadId === aeadId);
|
|
377
|
+
check("KE success exports 32-byte c2sKey", Buffer.isBuffer(res.c2sKey) && res.c2sKey.length === 32);
|
|
378
|
+
check("KE success exports 32-byte s2cKey", Buffer.isBuffer(res.s2cKey) && res.s2cKey.length === 32);
|
|
379
|
+
check("KE success returns one cookie", res.cookies.length === 1);
|
|
380
|
+
check("KE success defaults ntpServer to host", res.ntpServer === "127.0.0.1");
|
|
381
|
+
check("KE success defaults ntpPort to 123", res.ntpPort === 123);
|
|
382
|
+
check("KE success captures the warning", res.warnings.length === 1 && res.warnings[0] === 7);
|
|
383
|
+
} finally { try { ke.server.close(); } catch (_e) { /* best-effort */ } }
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async function testKeTimeout(cert) {
|
|
387
|
+
var ke = await _startKeServer(cert, { onData: null }); // ALPN ok, never sends REC_END
|
|
388
|
+
try { await _connectKeExpectReject(cert, ke, "nts/ke-timeout", "KE wall-clock timeout", 300); }
|
|
389
|
+
finally { try { ke.server.close(); } catch (_e) { /* best-effort */ } }
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async function testKeByteCapFailsClosed(cert) {
|
|
393
|
+
// 128 KiB of well-formed non-END cookie records, no REC_END — the read
|
|
394
|
+
// accumulator must fail closed at the 64 KiB ceiling (memory bound), not
|
|
395
|
+
// hang until the wall-clock timer (time bound) fires.
|
|
396
|
+
var one = _rec(false, REC_NEW_COOKIE, Buffer.alloc(1020, 0x41)); // 1024 bytes
|
|
397
|
+
var chunks = [];
|
|
398
|
+
for (var i = 0; i < 128; i++) chunks.push(one);
|
|
399
|
+
var big = Buffer.concat(chunks);
|
|
400
|
+
var ke = await _startKeServer(cert, { onData: function () { return big; } });
|
|
401
|
+
try { await _connectKeExpectReject(cert, ke, "nts/ke-too-large", "KE handshake byte cap"); }
|
|
402
|
+
finally { try { ke.server.close(); } catch (_e) { /* best-effort */ } }
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async function testKeSocketError() {
|
|
406
|
+
var srv = net.createServer(function (s) { s.destroy(); }); // reset mid-TLS
|
|
407
|
+
await new Promise(function (res) { srv.listen(0, "127.0.0.1", res); });
|
|
408
|
+
var port = srv.address().port;
|
|
409
|
+
var caught = null;
|
|
410
|
+
try {
|
|
411
|
+
await helpers.withTestTimeout("KE socket reset", function () {
|
|
412
|
+
return b.network.ntp.nts.performKeHandshake({
|
|
413
|
+
host: "127.0.0.1", port: port, servername: "localhost", timeoutMs: 4000,
|
|
414
|
+
});
|
|
415
|
+
}, { timeoutMs: 9000 });
|
|
416
|
+
} catch (e) { caught = e; }
|
|
417
|
+
try { srv.close(); } catch (_e) { /* best-effort */ }
|
|
418
|
+
check("KE socket reset rejects", caught !== null);
|
|
419
|
+
check("KE socket reset code is nts/ke-socket", caught && caught.code === "nts/ke-socket");
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// ---------------------------------------------------------------------------
|
|
423
|
+
// querySingle network paths.
|
|
424
|
+
// ---------------------------------------------------------------------------
|
|
425
|
+
|
|
426
|
+
async function _udpExpectReject(makeReply, aeadId, expectedCode, label) {
|
|
427
|
+
var udp = await _startUdpServer(function (msg, rinfo, s) {
|
|
428
|
+
var reply = makeReply(msg);
|
|
429
|
+
if (reply) s.send(reply, 0, reply.length, rinfo.port, rinfo.address);
|
|
430
|
+
});
|
|
431
|
+
var caught = null;
|
|
432
|
+
try {
|
|
433
|
+
await helpers.withTestTimeout(label, function () {
|
|
434
|
+
return b.network.ntp.nts.querySingle({
|
|
435
|
+
host: "127.0.0.1", port: udp.port, aeadId: aeadId,
|
|
436
|
+
c2sKey: nodeCrypto.randomBytes(32), s2cKey: nodeCrypto.randomBytes(32),
|
|
437
|
+
cookies: [nodeCrypto.randomBytes(32)], timeoutMs: 4000,
|
|
438
|
+
});
|
|
439
|
+
}, { timeoutMs: 9000 });
|
|
440
|
+
} catch (e) { caught = e; }
|
|
441
|
+
try { udp.sock.close(); } catch (_e) { /* best-effort */ }
|
|
442
|
+
check(label + " rejects", caught !== null);
|
|
443
|
+
check(label + " code=" + expectedCode, caught && caught.code === expectedCode);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
async function testQuerySingleAdversarialReplies() {
|
|
447
|
+
var aeadId = b.network.ntp.nts.AEAD_AES_SIV_CMAC_256;
|
|
448
|
+
|
|
449
|
+
await _udpExpectReject(function () { return Buffer.alloc(10); },
|
|
450
|
+
aeadId, "nts/bad-reply", "querySingle short reply");
|
|
451
|
+
|
|
452
|
+
await _udpExpectReject(function () { return Buffer.alloc(NTP_HEADER_BYTES); },
|
|
453
|
+
aeadId, "nts/unique-mismatch", "querySingle no unique-id");
|
|
454
|
+
|
|
455
|
+
await _udpExpectReject(function () {
|
|
456
|
+
return Buffer.concat([Buffer.alloc(NTP_HEADER_BYTES), _rawExt(EXT_UNIQUE, 2, Buffer.alloc(0))]);
|
|
457
|
+
}, aeadId, "nts/bad-extension", "querySingle extension len<4");
|
|
458
|
+
|
|
459
|
+
await _udpExpectReject(function () {
|
|
460
|
+
return Buffer.concat([Buffer.alloc(NTP_HEADER_BYTES), _rawExt(EXT_UNIQUE, 40, Buffer.alloc(0))]);
|
|
461
|
+
}, aeadId, "nts/bad-extension", "querySingle extension overrun");
|
|
462
|
+
|
|
463
|
+
await _udpExpectReject(function (msg) {
|
|
464
|
+
var u = _findExtBody(msg, NTP_HEADER_BYTES, EXT_UNIQUE);
|
|
465
|
+
return Buffer.concat([Buffer.alloc(NTP_HEADER_BYTES), _ext(EXT_UNIQUE, u)]);
|
|
466
|
+
}, aeadId, "nts/no-authenticator", "querySingle missing authenticator");
|
|
467
|
+
|
|
468
|
+
await _udpExpectReject(function (msg) {
|
|
469
|
+
var u = _findExtBody(msg, NTP_HEADER_BYTES, EXT_UNIQUE);
|
|
470
|
+
return Buffer.concat([
|
|
471
|
+
Buffer.alloc(NTP_HEADER_BYTES), _ext(EXT_UNIQUE, u),
|
|
472
|
+
_rawExt(EXT_AUTH, 6, Buffer.from([0xaa, 0xbb])), // 2-byte body < 4
|
|
473
|
+
]);
|
|
474
|
+
}, aeadId, "nts/bad-authenticator", "querySingle truncated authenticator");
|
|
475
|
+
|
|
476
|
+
await _udpExpectReject(function (msg) {
|
|
477
|
+
var u = _findExtBody(msg, NTP_HEADER_BYTES, EXT_UNIQUE);
|
|
478
|
+
var ab = Buffer.alloc(8);
|
|
479
|
+
ab.writeUInt16BE(100, 0); // nonceLen
|
|
480
|
+
ab.writeUInt16BE(100, 2); // ctLen — 4+100+100 >> 8
|
|
481
|
+
return Buffer.concat([Buffer.alloc(NTP_HEADER_BYTES), _ext(EXT_UNIQUE, u), _ext(EXT_AUTH, ab)]);
|
|
482
|
+
}, aeadId, "nts/bad-authenticator", "querySingle overlong authenticator lengths");
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
async function testQuerySingleAuthFailed() {
|
|
486
|
+
var aeadId = b.network.ntp.nts.AEAD_AES_SIV_CMAC_256;
|
|
487
|
+
var s2cKey = nodeCrypto.randomBytes(32);
|
|
488
|
+
var udp = await _startUdpServer(function (msg, rinfo, s) {
|
|
489
|
+
var u = _findExtBody(msg, NTP_HEADER_BYTES, EXT_UNIQUE);
|
|
490
|
+
if (!u) return;
|
|
491
|
+
var reply = _buildReply({ aeadId: aeadId, s2cKey: s2cKey, uniqueId: u, plaintext: Buffer.alloc(0), corruptCt: true });
|
|
492
|
+
s.send(reply, 0, reply.length, rinfo.port, rinfo.address);
|
|
493
|
+
});
|
|
494
|
+
var caught = null;
|
|
495
|
+
try {
|
|
496
|
+
await helpers.withTestTimeout("querySingle authenticator forgery", function () {
|
|
497
|
+
return b.network.ntp.nts.querySingle({
|
|
498
|
+
host: "127.0.0.1", port: udp.port, aeadId: aeadId,
|
|
499
|
+
c2sKey: nodeCrypto.randomBytes(32), s2cKey: s2cKey,
|
|
500
|
+
cookies: [nodeCrypto.randomBytes(32)], timeoutMs: 4000,
|
|
501
|
+
});
|
|
502
|
+
}, { timeoutMs: 9000 });
|
|
503
|
+
} catch (e) { caught = e; }
|
|
504
|
+
try { udp.sock.close(); } catch (_e) { /* best-effort */ }
|
|
505
|
+
check("querySingle forged authenticator rejects", caught !== null);
|
|
506
|
+
check("querySingle forged authenticator code", caught && caught.code === "nts/auth-failed");
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
async function testQuerySingleUnsupportedAeadEncrypt() {
|
|
510
|
+
// An aeadId the request-side AEAD encoder does not recognise fails closed
|
|
511
|
+
// before any packet leaves the socket — no server required.
|
|
512
|
+
var caught = null;
|
|
513
|
+
try {
|
|
514
|
+
await b.network.ntp.nts.querySingle({
|
|
515
|
+
host: "127.0.0.1", port: 65000, aeadId: 99,
|
|
516
|
+
c2sKey: nodeCrypto.randomBytes(32), s2cKey: nodeCrypto.randomBytes(32),
|
|
517
|
+
cookies: [nodeCrypto.randomBytes(32)], timeoutMs: 1000,
|
|
518
|
+
});
|
|
519
|
+
} catch (e) { caught = e; }
|
|
520
|
+
check("querySingle unsupported aead rejects", caught !== null);
|
|
521
|
+
check("querySingle unsupported aead code is nts/aead-unsupported",
|
|
522
|
+
caught && caught.code === "nts/aead-unsupported");
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
async function testQuerySingleTimeout() {
|
|
526
|
+
var aeadId = b.network.ntp.nts.AEAD_AES_SIV_CMAC_256;
|
|
527
|
+
var udp = await _startUdpServer(function () { /* never reply */ });
|
|
528
|
+
var caught = null;
|
|
529
|
+
try {
|
|
530
|
+
await helpers.withTestTimeout("querySingle timeout", function () {
|
|
531
|
+
return b.network.ntp.nts.querySingle({
|
|
532
|
+
host: "127.0.0.1", port: udp.port, aeadId: aeadId,
|
|
533
|
+
c2sKey: nodeCrypto.randomBytes(32), s2cKey: nodeCrypto.randomBytes(32),
|
|
534
|
+
cookies: [nodeCrypto.randomBytes(32)], timeoutMs: 300,
|
|
535
|
+
});
|
|
536
|
+
}, { timeoutMs: 9000 });
|
|
537
|
+
} catch (e) { caught = e; }
|
|
538
|
+
try { udp.sock.close(); } catch (_e) { /* best-effort */ }
|
|
539
|
+
check("querySingle timeout rejects", caught !== null);
|
|
540
|
+
check("querySingle timeout code is nts/timeout", caught && caught.code === "nts/timeout");
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
async function testQuerySingleSivSuccess() {
|
|
544
|
+
var aeadId = b.network.ntp.nts.AEAD_AES_SIV_CMAC_256;
|
|
545
|
+
var s2cKey = nodeCrypto.randomBytes(32);
|
|
546
|
+
var newCookie = nodeCrypto.randomBytes(32);
|
|
547
|
+
// Encrypted extensions: one non-cookie ext (skipped) + one cookie ext
|
|
548
|
+
// (rotated in) — exercises both sides of the cookie-type predicate.
|
|
549
|
+
var plaintext = Buffer.concat([_ext(EXT_UNIQUE, Buffer.alloc(4, 0xaa)), _ext(EXT_COOKIE, newCookie)]);
|
|
550
|
+
var udp = await _startUdpServer(function (msg, rinfo, s) {
|
|
551
|
+
var u = _findExtBody(msg, NTP_HEADER_BYTES, EXT_UNIQUE);
|
|
552
|
+
if (!u) return;
|
|
553
|
+
var reply = _buildReply({ aeadId: aeadId, s2cKey: s2cKey, uniqueId: u, plaintext: plaintext });
|
|
554
|
+
s.send(reply, 0, reply.length, rinfo.port, rinfo.address);
|
|
555
|
+
});
|
|
556
|
+
try {
|
|
557
|
+
// Cookie length 30 (not 4-aligned) exercises the extension padding path.
|
|
558
|
+
var res = await helpers.withTestTimeout("querySingle SIV success", function () {
|
|
559
|
+
return b.network.ntp.nts.querySingle({
|
|
560
|
+
host: "127.0.0.1", port: udp.port, aeadId: aeadId,
|
|
561
|
+
c2sKey: nodeCrypto.randomBytes(32), s2cKey: s2cKey,
|
|
562
|
+
cookies: [nodeCrypto.randomBytes(30)], timeoutMs: 4000,
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
check("SIV querySingle authenticated", res.authenticated === true);
|
|
566
|
+
check("SIV querySingle drift is numeric", typeof res.driftMs === "number" && isFinite(res.driftMs));
|
|
567
|
+
check("SIV querySingle rotated one new cookie", res.newCookieCount === 1);
|
|
568
|
+
check("SIV querySingle cookie pool stays at one", res.cookiesRemaining === 1);
|
|
569
|
+
} finally { try { udp.sock.close(); } catch (_e) { /* best-effort */ } }
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
async function testQuerySingleChaChaSuccess() {
|
|
573
|
+
var aeadId = b.network.ntp.nts.AEAD_CHACHA20_POLY1305;
|
|
574
|
+
var s2cKey = nodeCrypto.randomBytes(32);
|
|
575
|
+
// A 4-byte-but-malformed encrypted extension: length >= 4 reaches the
|
|
576
|
+
// inner walk, whose throw is swallowed → zero cookies extracted.
|
|
577
|
+
var plaintext = Buffer.from([0x02, 0x04, 0x00, 0x02]);
|
|
578
|
+
var udp = await _startUdpServer(function (msg, rinfo, s) {
|
|
579
|
+
var u = _findExtBody(msg, NTP_HEADER_BYTES, EXT_UNIQUE);
|
|
580
|
+
if (!u) return;
|
|
581
|
+
var reply = _buildReply({ aeadId: aeadId, s2cKey: s2cKey, uniqueId: u, plaintext: plaintext });
|
|
582
|
+
s.send(reply, 0, reply.length, rinfo.port, rinfo.address);
|
|
583
|
+
});
|
|
584
|
+
try {
|
|
585
|
+
var res = await helpers.withTestTimeout("querySingle ChaCha success", function () {
|
|
586
|
+
return b.network.ntp.nts.querySingle({
|
|
587
|
+
host: "127.0.0.1", port: udp.port, aeadId: aeadId,
|
|
588
|
+
c2sKey: nodeCrypto.randomBytes(32), s2cKey: s2cKey,
|
|
589
|
+
cookies: [nodeCrypto.randomBytes(32)], timeoutMs: 4000,
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
check("ChaCha querySingle authenticated", res.authenticated === true);
|
|
593
|
+
check("ChaCha querySingle extracts no cookie from malformed exts", res.newCookieCount === 0);
|
|
594
|
+
check("ChaCha querySingle cookie pool unchanged", res.cookiesRemaining === 1);
|
|
595
|
+
} finally { try { udp.sock.close(); } catch (_e) { /* best-effort */ } }
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// ---------------------------------------------------------------------------
|
|
599
|
+
// query — end-to-end KE + protected query, keyed off shared TLS exporter.
|
|
600
|
+
// ---------------------------------------------------------------------------
|
|
601
|
+
|
|
602
|
+
async function testQueryFullFlow(cert) {
|
|
603
|
+
var aeadId = b.network.ntp.nts.AEAD_AES_SIV_CMAC_256;
|
|
604
|
+
var shared = { s2cKey: null };
|
|
605
|
+
|
|
606
|
+
var udp = await _startUdpServer(function (msg, rinfo, s) {
|
|
607
|
+
if (!shared.s2cKey) return;
|
|
608
|
+
var u = _findExtBody(msg, NTP_HEADER_BYTES, EXT_UNIQUE);
|
|
609
|
+
if (!u) return;
|
|
610
|
+
var plaintext = _ext(EXT_COOKIE, nodeCrypto.randomBytes(32));
|
|
611
|
+
var reply = _buildReply({ aeadId: aeadId, s2cKey: shared.s2cKey, uniqueId: u, plaintext: plaintext });
|
|
612
|
+
s.send(reply, 0, reply.length, rinfo.port, rinfo.address);
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
var ke = await _startKeServer(cert, { onData: function (sock) {
|
|
616
|
+
// The KE server exports the SAME s2c keying material the client derives
|
|
617
|
+
// (symmetric TLS 1.3 exporter), so its UDP sibling can authenticate.
|
|
618
|
+
var ctxS2C = Buffer.from([0x00, 0x00, (aeadId >> 8) & 0xff, aeadId & 0xff, 0x01]);
|
|
619
|
+
shared.s2cKey = sock.exportKeyingMaterial(32, EXPORTER_LABEL, ctxS2C);
|
|
620
|
+
return Buffer.concat([
|
|
621
|
+
_rec(true, REC_NEXT_PROTOCOL, _u16(0)),
|
|
622
|
+
_rec(true, REC_AEAD, _u16(aeadId)),
|
|
623
|
+
_rec(false, REC_NEW_COOKIE, nodeCrypto.randomBytes(30)),
|
|
624
|
+
_rec(false, REC_NTPV4_SERVER, Buffer.from("127.0.0.1", "ascii")),
|
|
625
|
+
_rec(false, REC_NTPV4_PORT, _u16(udp.port)),
|
|
626
|
+
_rec(true, REC_END, Buffer.alloc(0)),
|
|
627
|
+
]);
|
|
628
|
+
} });
|
|
629
|
+
|
|
630
|
+
try {
|
|
631
|
+
var res = await helpers.withTestTimeout("nts query end-to-end", function () {
|
|
632
|
+
return b.network.ntp.nts.query({
|
|
633
|
+
host: "127.0.0.1", kePort: ke.port, servername: "localhost",
|
|
634
|
+
ca: cert.ca.caCertPem, timeoutMs: 4000,
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
check("query resolves authenticated", res.authenticated === true);
|
|
638
|
+
check("query surfaces negotiated aeadId", res.aeadId === aeadId);
|
|
639
|
+
check("query drift is numeric", typeof res.driftMs === "number" && isFinite(res.driftMs));
|
|
640
|
+
check("query reports cookieCount", typeof res.cookieCount === "number" && res.cookieCount >= 1);
|
|
641
|
+
check("query routed to the KE-advertised NTP server", res.server === "127.0.0.1");
|
|
642
|
+
} finally {
|
|
643
|
+
try { ke.server.close(); } catch (_e) { /* best-effort */ }
|
|
644
|
+
try { udp.sock.close(); } catch (_e) { /* best-effort */ }
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Handles finalize asynchronously past a forked worker's grace window; poll
|
|
649
|
+
// until every TCP/UDP handle this suite opened has actually closed so none
|
|
650
|
+
// outlives run() and holds the event loop open on a slow runner.
|
|
651
|
+
async function _drainHandles() {
|
|
652
|
+
if (typeof process.getActiveResourcesInfo !== "function") return;
|
|
653
|
+
try {
|
|
654
|
+
await helpers.waitUntil(function () {
|
|
655
|
+
return process.getActiveResourcesInfo().filter(function (t) {
|
|
656
|
+
return t === "TCPSocketWrap" || t === "TCPServerWrap" || t === "UDPWrap";
|
|
657
|
+
}).length === 0;
|
|
658
|
+
}, { timeoutMs: 5000, label: "network-nts: TCP/UDP handle drain" });
|
|
659
|
+
} catch (_e) { /* explicit closes already issued; best-effort settle */ }
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
async function run() {
|
|
663
|
+
try {
|
|
664
|
+
// Pure-crypto + synchronous validation (no listeners).
|
|
665
|
+
testAesSivRoundtrip();
|
|
666
|
+
testAesSivBadKey();
|
|
667
|
+
testAesSivTamperFailsClosed();
|
|
668
|
+
testKeInputValidation();
|
|
669
|
+
testQuerySingleInputValidation();
|
|
670
|
+
|
|
671
|
+
// One cert reused across every TLS listener.
|
|
672
|
+
var cert = await _makeCert();
|
|
673
|
+
|
|
674
|
+
await testKeBadAlpn(cert);
|
|
675
|
+
await testKeAdversarialRecords(cert);
|
|
676
|
+
await testKeSuccess(cert);
|
|
677
|
+
await testKeByteCapFailsClosed(cert);
|
|
678
|
+
await testKeTimeout(cert);
|
|
679
|
+
await testKeSocketError();
|
|
680
|
+
|
|
681
|
+
await testQuerySingleAdversarialReplies();
|
|
682
|
+
await testQuerySingleAuthFailed();
|
|
683
|
+
await testQuerySingleUnsupportedAeadEncrypt();
|
|
684
|
+
await testQuerySingleTimeout();
|
|
685
|
+
await testQuerySingleSivSuccess();
|
|
686
|
+
await testQuerySingleChaChaSuccess();
|
|
687
|
+
|
|
688
|
+
await testQueryFullFlow(cert);
|
|
689
|
+
} finally {
|
|
690
|
+
await _drainHandles();
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
module.exports = { run: run };
|
|
695
|
+
|
|
696
|
+
if (require.main === module) {
|
|
697
|
+
run().then(function () { console.log("OK"); })
|
|
698
|
+
.catch(function (e) { console.error(e.stack || e); process.exit(1); });
|
|
699
|
+
}
|