@blamejs/blamejs-shop 0.5.11 → 0.5.13
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/SECURITY.md +6 -1
- package/lib/admin.js +56 -0
- package/lib/asset-manifest.json +1 -1
- package/lib/operator-sessions.js +68 -5
- 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
|
@@ -308,6 +308,490 @@ function testPrototypePollutionDefense() {
|
|
|
308
308
|
check("proto: header skipped", tree.headers.get("__proto__") === null);
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
// ---- Walk / findFirst guard clauses ---------------------------------------
|
|
312
|
+
|
|
313
|
+
function testWalkAndFindFirstGuards() {
|
|
314
|
+
var tree = b.safeMime.parse(_msg(["Content-Type: text/plain"], "x"));
|
|
315
|
+
// walk(null) is a documented no-op (returns undefined, no throw).
|
|
316
|
+
var r = b.safeMime.walk(null, function () {});
|
|
317
|
+
check("walk: null tree is a no-op", r === undefined);
|
|
318
|
+
// Non-function visitor is a caller error → TypeError (config-time throw).
|
|
319
|
+
var threwW = null;
|
|
320
|
+
try { b.safeMime.walk(tree, "not-a-function"); } catch (e) { threwW = e; }
|
|
321
|
+
check("walk: non-function visitor throws TypeError", threwW instanceof TypeError);
|
|
322
|
+
// findFirst with a non-function predicate → TypeError.
|
|
323
|
+
var threwF = null;
|
|
324
|
+
try { b.safeMime.findFirst(tree, 123); } catch (e) { threwF = e; }
|
|
325
|
+
check("findFirst: non-function predicate throws TypeError", threwF instanceof TypeError);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ---- extractText outside multipart/alternative ----------------------------
|
|
329
|
+
|
|
330
|
+
function testExtractTextNonAlternativePaths() {
|
|
331
|
+
// A bare text/plain leaf (not multipart/alternative) → the findFirst
|
|
332
|
+
// "preferred" branch.
|
|
333
|
+
var leafTree = b.safeMime.parse(_msg(["Content-Type: text/plain; charset=utf-8"], "just plain"));
|
|
334
|
+
var t1 = b.safeMime.extractText(leafTree, { prefer: "plain" });
|
|
335
|
+
check("extractText: single leaf plain", t1 && t1.body === "just plain" && t1.contentType === "text/plain");
|
|
336
|
+
|
|
337
|
+
// multipart/mixed carrying only text/html, prefer=plain → no preferred
|
|
338
|
+
// match, falls through to the any-text branch.
|
|
339
|
+
var htmlOnly = [
|
|
340
|
+
"Content-Type: multipart/mixed; boundary=M", "",
|
|
341
|
+
"--M", "Content-Type: text/html", "", "<b>hi</b>", "--M--",
|
|
342
|
+
].join("\r\n");
|
|
343
|
+
var t2 = b.safeMime.extractText(b.safeMime.parse(htmlOnly), { prefer: "plain" });
|
|
344
|
+
check("extractText: falls back to any text/*", t2 && t2.contentType === "text/html" && t2.body.trim() === "<b>hi</b>");
|
|
345
|
+
|
|
346
|
+
// multipart/mixed with no text part at all → null.
|
|
347
|
+
var noText = [
|
|
348
|
+
"Content-Type: multipart/mixed; boundary=M", "",
|
|
349
|
+
"--M", "Content-Type: application/octet-stream", "Content-Transfer-Encoding: base64", "", "AAAA", "--M--",
|
|
350
|
+
].join("\r\n");
|
|
351
|
+
var t3 = b.safeMime.extractText(b.safeMime.parse(noText), { prefer: "plain" });
|
|
352
|
+
check("extractText: no text part returns null", t3 === null);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function testExtractTextAlternativeFallback() {
|
|
356
|
+
// multipart/alternative but prefer=plain with only a text/html child:
|
|
357
|
+
// the last-wins loop misses, the fallback loop returns the html.
|
|
358
|
+
var altHtmlOnly = [
|
|
359
|
+
"Content-Type: multipart/alternative; boundary=A", "",
|
|
360
|
+
"--A", "Content-Type: text/html", "", "<i>x</i>", "--A--",
|
|
361
|
+
].join("\r\n");
|
|
362
|
+
var t1 = b.safeMime.extractText(b.safeMime.parse(altHtmlOnly), { prefer: "plain" });
|
|
363
|
+
check("extractText alt: fallback to text/html", t1 && t1.contentType === "text/html" && t1.body.trim() === "<i>x</i>");
|
|
364
|
+
|
|
365
|
+
// multipart/alternative with no text parts → null.
|
|
366
|
+
var altNoText = [
|
|
367
|
+
"Content-Type: multipart/alternative; boundary=A", "",
|
|
368
|
+
"--A", "Content-Type: application/json", "", "{}", "--A--",
|
|
369
|
+
].join("\r\n");
|
|
370
|
+
var t2 = b.safeMime.extractText(b.safeMime.parse(altNoText), { prefer: "plain" });
|
|
371
|
+
check("extractText alt: no text returns null", t2 === null);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// ---- LF-only line endings (CRLF is not the only wire form) -----------------
|
|
375
|
+
|
|
376
|
+
function testLfOnlyLineEndings() {
|
|
377
|
+
// A message with bare-LF separators exercises the LF (not CRLF) branch
|
|
378
|
+
// of both the header/body split and the header-section skip.
|
|
379
|
+
var tree = b.safeMime.parse("Subject: y\n\nbody-here");
|
|
380
|
+
check("LF-only: subject parsed", tree.headers.get("subject") === "y");
|
|
381
|
+
check("LF-only: body parsed", tree.leaf.body.toString("utf8") === "body-here");
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function testMultipartLfLineEndings() {
|
|
385
|
+
// LF-only multipart exercises the LF-trim of the byte before each
|
|
386
|
+
// boundary delimiter (both the interior and the final one).
|
|
387
|
+
var msg =
|
|
388
|
+
"Content-Type: multipart/mixed; boundary=B\n\n" +
|
|
389
|
+
"--B\nContent-Type: text/plain\n\naaa\n" +
|
|
390
|
+
"--B\nContent-Type: text/plain\n\nbbb\n" +
|
|
391
|
+
"--B--";
|
|
392
|
+
var tree = b.safeMime.parse(msg);
|
|
393
|
+
check("multipart LF: 2 parts", tree.parts.length === 2);
|
|
394
|
+
check("multipart LF: part 0", tree.parts[0].leaf.body.toString().trim() === "aaa");
|
|
395
|
+
check("multipart LF: part 1", tree.parts[1].leaf.body.toString().trim() === "bbb");
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// ---- Structural edge cases in the splitter ---------------------------------
|
|
399
|
+
|
|
400
|
+
function testNoBlankLineSeparator() {
|
|
401
|
+
// No blank-line separator at all: the whole buffer is the header
|
|
402
|
+
// section, the body is empty.
|
|
403
|
+
var tree = b.safeMime.parse("Subject: only-headers");
|
|
404
|
+
check("no-sep: subject parsed", tree.headers.get("subject") === "only-headers");
|
|
405
|
+
check("no-sep: empty body", tree.leaf.body.length === 0);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function testMultipartUnclosedLastPart() {
|
|
409
|
+
// No final "--B--" closing delimiter: the last part stays open and is
|
|
410
|
+
// materialized from its start offset to end-of-buffer.
|
|
411
|
+
var msg = "Content-Type: multipart/mixed; boundary=B\r\n\r\n--B\r\nContent-Type: text/plain\r\n\r\nonly-part\r\n";
|
|
412
|
+
var tree = b.safeMime.parse(msg);
|
|
413
|
+
check("unclosed: one part", tree.parts.length === 1);
|
|
414
|
+
check("unclosed: body captured", tree.parts[0].leaf.body.toString().indexOf("only-part") !== -1);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function testMultipartBoundaryNoTrailingNewline() {
|
|
418
|
+
// A boundary line at end-of-buffer with no terminating newline: the
|
|
419
|
+
// line-end scan returns -1 and the split stops cleanly.
|
|
420
|
+
var msg = "Content-Type: multipart/mixed; boundary=B\r\n\r\n--B\r\nContent-Type: text/plain\r\n\r\nx\r\n--B";
|
|
421
|
+
var tree = b.safeMime.parse(msg);
|
|
422
|
+
check("no-trailing-nl: at least one part", tree.parts.length >= 1);
|
|
423
|
+
check("no-trailing-nl: first body captured", tree.parts[0].leaf.body.toString().indexOf("x") !== -1);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function testMultipartBoundaryShapeMidLine() {
|
|
427
|
+
// A "--B" sequence appearing mid-line (not at a line start) MUST NOT be
|
|
428
|
+
// treated as a boundary delimiter (RFC 2046 §5.1.1). The preamble junk
|
|
429
|
+
// is skipped and only the real line-start boundary splits.
|
|
430
|
+
var msg = "Content-Type: multipart/mixed; boundary=B\r\n\r\n" +
|
|
431
|
+
"preamble--Bjunk\r\n--B\r\nContent-Type: text/plain\r\n\r\nreal\r\n--B--";
|
|
432
|
+
var tree = b.safeMime.parse(msg);
|
|
433
|
+
check("midline-boundary: one real part", tree.parts.length === 1);
|
|
434
|
+
check("midline-boundary: real body", tree.parts[0].leaf.body.toString().trim() === "real");
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ---- Cap / refusal branches not yet exercised ------------------------------
|
|
438
|
+
|
|
439
|
+
function testRefusesOversizeHeaderSection() {
|
|
440
|
+
expectRefused("refuses header section > maxHeaderBytes",
|
|
441
|
+
function () { b.safeMime.parse("Subject: hello there\r\nContent-Type: text/plain\r\n\r\nbody", { maxHeaderBytes: 5 }); },
|
|
442
|
+
"safe-mime/oversize-headers");
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function testRefusesOversizeBodyRaw() {
|
|
446
|
+
var body = new Array(101).join("a"); // 100 raw bytes, 7bit (no decode)
|
|
447
|
+
expectRefused("refuses raw body > maxBodyBytes",
|
|
448
|
+
function () { b.safeMime.parse(_msg(["Content-Type: text/plain"], body), { maxBodyBytes: 10 }); },
|
|
449
|
+
"safe-mime/oversize-body");
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function testRefusesTooManyHeaders() {
|
|
453
|
+
expectRefused("refuses header count > maxHeaderCount (DoS bound)",
|
|
454
|
+
function () { b.safeMime.parse("A: 1\r\nB: 2\r\nC: 3\r\nContent-Type: text/plain\r\n\r\nbody", { maxHeaderCount: 2 }); },
|
|
455
|
+
"safe-mime/too-many-headers");
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function testRefusesOversizeHeaderLine() {
|
|
459
|
+
var longVal = new Array(60).join("x"); // 59 chars → line well over 10 bytes
|
|
460
|
+
expectRefused("refuses header line > maxHeaderLineBytes (RFC 5322 §2.1.1)",
|
|
461
|
+
function () { b.safeMime.parse("Subject: " + longVal + "\r\n\r\nbody", { maxHeaderLineBytes: 10 }); },
|
|
462
|
+
"safe-mime/oversize-header-line");
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function testRefusesHeaderMissingColon() {
|
|
466
|
+
// A long (>64 char) header line with no colon: malformed-headers, and
|
|
467
|
+
// the error's byte-preview is truncated with an ellipsis.
|
|
468
|
+
var longNoColon = "ThisIsAHeaderLineWithNoColonAtAllAndItIsDefinitelyLongerThanSixtyFourCharacters";
|
|
469
|
+
var threw = null;
|
|
470
|
+
try { b.safeMime.parse(longNoColon + "\r\nContent-Type: text/plain\r\n\r\nbody"); }
|
|
471
|
+
catch (e) { threw = e; }
|
|
472
|
+
check("missing-colon: refused", threw && (threw.code || "").indexOf("safe-mime/malformed-headers") !== -1);
|
|
473
|
+
check("missing-colon: preview truncated", threw && threw.message.indexOf("...") !== -1);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function testRefusesMalformedBoundaryGrammar() {
|
|
477
|
+
// A boundary within the length cap but containing a char outside the
|
|
478
|
+
// RFC 2046 §5.1.1 bchars set ("!") must be refused.
|
|
479
|
+
expectRefused("refuses boundary violating RFC 2046 bchars grammar",
|
|
480
|
+
function () { b.safeMime.parse(_msg(["Content-Type: multipart/mixed; boundary=bad!boundary"], "x")); },
|
|
481
|
+
"safe-mime/malformed-boundary");
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// ---- Content-Type quoted parameter value -----------------------------------
|
|
485
|
+
|
|
486
|
+
function testQuotedContentTypeParams() {
|
|
487
|
+
var tree = b.safeMime.parse(_msg(["Content-Type: text/plain; charset=\"utf-8\""], "hi"));
|
|
488
|
+
check("quoted param: charset unquoted", tree.leaf.charset === "utf-8");
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// ---- RFC 2047 encoded-word header injection --------------------------------
|
|
492
|
+
|
|
493
|
+
function testRefusesRfc2047HeaderInjection() {
|
|
494
|
+
// RFC 2047 §5 — an encoded-word whose decoded bytes carry CR/LF/NUL is a
|
|
495
|
+
// header-injection attempt (a smuggled Bcc:) and must be refused.
|
|
496
|
+
var payload = Buffer.from("\r\nBcc: attacker@evil.example").toString("base64");
|
|
497
|
+
var msg = "Subject: =?utf-8?B?" + payload + "?=\r\nContent-Type: text/plain\r\n\r\nbody";
|
|
498
|
+
expectRefused("refuses RFC 2047 encoded-word header injection",
|
|
499
|
+
function () { b.safeMime.parse(msg); },
|
|
500
|
+
"safe-mime/rfc2047-header-injection");
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// ---- Charset decoders: utf-16 family + fall-through ------------------------
|
|
504
|
+
|
|
505
|
+
function testCharsetDecodingBranches() {
|
|
506
|
+
function decodedFor(charset, rawBuf) {
|
|
507
|
+
var tree = b.safeMime.parse(_msg(
|
|
508
|
+
["Content-Type: text/plain; charset=" + charset, "Content-Transfer-Encoding: base64"],
|
|
509
|
+
rawBuf.toString("base64")));
|
|
510
|
+
return tree.decoded;
|
|
511
|
+
}
|
|
512
|
+
var le = Buffer.from("Hi", "utf16le"); // [0x48,0x00,0x69,0x00]
|
|
513
|
+
var be = Buffer.from(le); be.swap16(); // [0x00,0x48,0x00,0x69] — UTF-16BE
|
|
514
|
+
check("charset utf-16le", decodedFor("utf-16le", le) === "Hi");
|
|
515
|
+
check("charset utf-16be", decodedFor("utf-16be", be) === "Hi");
|
|
516
|
+
check("charset utf-16 LE BOM", decodedFor("utf-16", Buffer.concat([Buffer.from([0xff, 0xfe]), le])) === "Hi");
|
|
517
|
+
check("charset utf-16 BE BOM", decodedFor("utf-16", Buffer.concat([Buffer.from([0xfe, 0xff]), be])) === "Hi");
|
|
518
|
+
check("charset utf-16 no BOM (BE default)", decodedFor("utf-16", be) === "Hi");
|
|
519
|
+
// windows-1252 is allowlisted but has no dedicated decoder branch → the
|
|
520
|
+
// utf-8 fall-through is used.
|
|
521
|
+
check("charset windows-1252 fall-through", decodedFor("windows-1252", Buffer.from("hi", "ascii")) === "hi");
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// ---- Attachment filename derivation ----------------------------------------
|
|
525
|
+
|
|
526
|
+
function testRfc2231ExtendedFilename() {
|
|
527
|
+
// RFC 2231 extended-parameter filename*=<charset>'<lang>'<pct-encoded>.
|
|
528
|
+
var msg = [
|
|
529
|
+
"Content-Type: multipart/mixed; boundary=B", "",
|
|
530
|
+
"--B",
|
|
531
|
+
"Content-Type: application/octet-stream",
|
|
532
|
+
"Content-Disposition: attachment; filename*=UTF-8''r%C3%A9port.pdf",
|
|
533
|
+
"Content-Transfer-Encoding: base64", "",
|
|
534
|
+
"AAAA",
|
|
535
|
+
"--B--",
|
|
536
|
+
].join("\r\n");
|
|
537
|
+
var atts = b.safeMime.extractAttachments(b.safeMime.parse(msg));
|
|
538
|
+
check("rfc2231: filename percent-decoded", atts.length === 1 && atts[0].filename === "réport.pdf");
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function testFilenameFromContentTypeName() {
|
|
542
|
+
// No filename in Content-Disposition → fall back to the Content-Type
|
|
543
|
+
// name= parameter (quoted form unwrapped).
|
|
544
|
+
var withName = [
|
|
545
|
+
"Content-Type: multipart/mixed; boundary=B", "",
|
|
546
|
+
"--B",
|
|
547
|
+
"Content-Type: application/octet-stream; name=\"doc.bin\"",
|
|
548
|
+
"Content-Disposition: attachment",
|
|
549
|
+
"Content-Transfer-Encoding: base64", "",
|
|
550
|
+
"AAAA",
|
|
551
|
+
"--B--",
|
|
552
|
+
].join("\r\n");
|
|
553
|
+
var a1 = b.safeMime.extractAttachments(b.safeMime.parse(withName));
|
|
554
|
+
check("name-fallback: quoted name used", a1.length === 1 && a1[0].filename === "doc.bin");
|
|
555
|
+
|
|
556
|
+
// Neither filename nor name present → null filename.
|
|
557
|
+
var noName = [
|
|
558
|
+
"Content-Type: multipart/mixed; boundary=B", "",
|
|
559
|
+
"--B",
|
|
560
|
+
"Content-Type: application/octet-stream",
|
|
561
|
+
"Content-Disposition: attachment",
|
|
562
|
+
"Content-Transfer-Encoding: base64", "",
|
|
563
|
+
"AAAA",
|
|
564
|
+
"--B--",
|
|
565
|
+
].join("\r\n");
|
|
566
|
+
var a2 = b.safeMime.extractAttachments(b.safeMime.parse(noName));
|
|
567
|
+
check("name-fallback: null when neither present", a2.length === 1 && a2[0].filename === null);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function testRfc2231MalformedFilenameNoThrow() {
|
|
571
|
+
// A hostile `filename*=<charset>'<lang>'<pct>` whose percent-escape is
|
|
572
|
+
// malformed (truncated `%`, non-hex digits) or decodes to invalid UTF-8
|
|
573
|
+
// must NOT crash extractAttachments with a raw URIError — the parser
|
|
574
|
+
// family's contract is that only typed SafeMimeError escapes, and every
|
|
575
|
+
// other decodeURIComponent site in the framework guards this. Degrade to
|
|
576
|
+
// the still-encoded segment (best-effort; downstream filename guards own
|
|
577
|
+
// the raw form) rather than throwing.
|
|
578
|
+
function attFor(fnParam) {
|
|
579
|
+
var msg = [
|
|
580
|
+
"Content-Type: multipart/mixed; boundary=B", "",
|
|
581
|
+
"--B",
|
|
582
|
+
"Content-Type: application/octet-stream",
|
|
583
|
+
"Content-Disposition: attachment; filename*=" + fnParam,
|
|
584
|
+
"Content-Transfer-Encoding: base64", "",
|
|
585
|
+
"AAAA",
|
|
586
|
+
"--B--",
|
|
587
|
+
].join("\r\n");
|
|
588
|
+
return b.safeMime.extractAttachments(b.safeMime.parse(msg));
|
|
589
|
+
}
|
|
590
|
+
// Truncated `%` with no following hex — decodeURIComponent throws URIError.
|
|
591
|
+
var a1 = attFor("UTF-8''%");
|
|
592
|
+
check("rfc2231 malformed: truncated % does not crash",
|
|
593
|
+
a1.length === 1 && a1[0].filename === "%");
|
|
594
|
+
// `%ZZ` — non-hex escape digits.
|
|
595
|
+
var a2 = attFor("UTF-8''bad%ZZname.pdf");
|
|
596
|
+
check("rfc2231 malformed: non-hex % escape does not crash",
|
|
597
|
+
a2.length === 1 && a2[0].filename === "bad%ZZname.pdf");
|
|
598
|
+
// `%FF%FE` — well-formed escapes that decode to invalid UTF-8.
|
|
599
|
+
var a3 = attFor("UTF-8''%FF%FE");
|
|
600
|
+
check("rfc2231 malformed: invalid-UTF-8 % escape does not crash",
|
|
601
|
+
a3.length === 1 && a3[0].filename === "%FF%FE");
|
|
602
|
+
// Regression guard — a valid ext-value still percent-decodes.
|
|
603
|
+
var a4 = attFor("UTF-8''r%65port.pdf");
|
|
604
|
+
check("rfc2231 valid: still decodes after guard",
|
|
605
|
+
a4.length === 1 && a4[0].filename === "report.pdf");
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// ---- Transfer-encoding allowlist edges -------------------------------------
|
|
609
|
+
|
|
610
|
+
function testCustomTransferEncodingAllowlist() {
|
|
611
|
+
// RFC 3030 BINARYMIME opt-in — "binary" decodes to the raw bytes
|
|
612
|
+
// (identity) once the operator adds it to the allowlist.
|
|
613
|
+
var tree = b.safeMime.parse(
|
|
614
|
+
_msg(["Content-Type: text/plain", "Content-Transfer-Encoding: binary"], "rawbytes"),
|
|
615
|
+
{ transferEncodingAllowlist: ["7bit", "binary"] });
|
|
616
|
+
check("binary opt-in: identity decode", tree.leaf.body.toString() === "rawbytes");
|
|
617
|
+
|
|
618
|
+
// An encoding allowlisted by the operator but with no decoder branch
|
|
619
|
+
// fails closed at the decoder rather than decoding as something else.
|
|
620
|
+
expectRefused("allowlisted-but-unimplemented encoding fails closed",
|
|
621
|
+
function () { b.safeMime.parse(
|
|
622
|
+
_msg(["Content-Type: text/plain", "Content-Transfer-Encoding: x-uuencode"], "data"),
|
|
623
|
+
{ transferEncodingAllowlist: ["7bit", "x-uuencode"] }); },
|
|
624
|
+
"safe-mime/unknown-transfer-encoding");
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// ---- Charset name normalization aliases ------------------------------------
|
|
628
|
+
|
|
629
|
+
function testCharsetAliasNormalization() {
|
|
630
|
+
function decodedFor(charset, rawBuf) {
|
|
631
|
+
return b.safeMime.parse(_msg(
|
|
632
|
+
["Content-Type: text/plain; charset=" + charset, "Content-Transfer-Encoding: base64"],
|
|
633
|
+
rawBuf.toString("base64"))).decoded;
|
|
634
|
+
}
|
|
635
|
+
var ascii = Buffer.from("hey", "ascii");
|
|
636
|
+
check("charset utf8 alias", decodedFor("utf8", Buffer.from("hi", "utf8")) === "hi");
|
|
637
|
+
check("charset ascii alias", decodedFor("ascii", ascii) === "hey");
|
|
638
|
+
check("charset latin1 alias", decodedFor("latin1", ascii) === "hey");
|
|
639
|
+
check("charset cp1252 alias", decodedFor("cp1252", ascii) === "hey");
|
|
640
|
+
check("charset shift-jis alias", decodedFor("shift-jis", ascii) === "hey");
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// ---- extractText / extractAttachments option branches ----------------------
|
|
644
|
+
|
|
645
|
+
function testExtractTextExtraBranches() {
|
|
646
|
+
var altTree = b.safeMime.parse([
|
|
647
|
+
"Content-Type: multipart/alternative; boundary=A", "",
|
|
648
|
+
"--A", "Content-Type: text/plain", "", "P",
|
|
649
|
+
"--A", "Content-Type: text/html", "", "<p>H</p>",
|
|
650
|
+
"--A--",
|
|
651
|
+
].join("\r\n"));
|
|
652
|
+
// No opts argument → prefer defaults to "plain".
|
|
653
|
+
var d = b.safeMime.extractText(altTree);
|
|
654
|
+
check("extractText: default prefer=plain", d && d.contentType === "text/plain");
|
|
655
|
+
// prefer=any on multipart/alternative → last-wins picks the last text/*.
|
|
656
|
+
var anyPick = b.safeMime.extractText(altTree, { prefer: "any" });
|
|
657
|
+
check("extractText: prefer any picks last text/*", anyPick && anyPick.contentType === "text/html");
|
|
658
|
+
|
|
659
|
+
// Non-alternative tree, prefer=html → the html arm of the findFirst.
|
|
660
|
+
var mixedHtml = b.safeMime.parse([
|
|
661
|
+
"Content-Type: multipart/mixed; boundary=M", "",
|
|
662
|
+
"--M", "Content-Type: text/plain", "", "p",
|
|
663
|
+
"--M", "Content-Type: text/html", "", "<b>h</b>",
|
|
664
|
+
"--M--",
|
|
665
|
+
].join("\r\n"));
|
|
666
|
+
var h = b.safeMime.extractText(mixedHtml, { prefer: "html" });
|
|
667
|
+
check("extractText: non-alt prefer html", h && h.contentType === "text/html");
|
|
668
|
+
|
|
669
|
+
// multipart/alternative whose FIRST child is itself a multipart (no
|
|
670
|
+
// leaf): the reverse last-wins loop visits the non-leaf child and skips
|
|
671
|
+
// it before matching the text/plain sibling.
|
|
672
|
+
var altNested = b.safeMime.parse([
|
|
673
|
+
"Content-Type: multipart/alternative; boundary=A", "",
|
|
674
|
+
"--A", "Content-Type: text/plain", "", "outer",
|
|
675
|
+
"--A", "Content-Type: multipart/mixed; boundary=N", "",
|
|
676
|
+
"--N", "Content-Type: text/plain", "", "inner", "--N--",
|
|
677
|
+
"--A--",
|
|
678
|
+
].join("\r\n"));
|
|
679
|
+
var nested = b.safeMime.extractText(altNested, { prefer: "plain" });
|
|
680
|
+
check("extractText: skips non-leaf alt child", nested && nested.body.trim() === "outer");
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function testExtractAttachmentsInline() {
|
|
684
|
+
var msg = [
|
|
685
|
+
"Content-Type: multipart/mixed; boundary=B", "",
|
|
686
|
+
"--B", "Content-Type: text/plain", "Content-Disposition: inline", "", "inline-body",
|
|
687
|
+
"--B", "Content-Type: application/pdf", "Content-Disposition: attachment; filename=a.pdf",
|
|
688
|
+
"Content-Transfer-Encoding: base64", "", "AAAA",
|
|
689
|
+
"--B--",
|
|
690
|
+
].join("\r\n");
|
|
691
|
+
var tree = b.safeMime.parse(msg);
|
|
692
|
+
// Default excludes inline parts.
|
|
693
|
+
var d = b.safeMime.extractAttachments(tree);
|
|
694
|
+
check("attachments: inline excluded by default", d.length === 1 && d[0].filename === "a.pdf");
|
|
695
|
+
// includeInline:true pulls inline in alongside the attachment.
|
|
696
|
+
var w = b.safeMime.extractAttachments(tree, { includeInline: true });
|
|
697
|
+
check("attachments: includeInline pulls inline too", w.length === 2);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// ---- Header accessor + input-shape branches --------------------------------
|
|
701
|
+
|
|
702
|
+
function testHeaderGetAllMissing() {
|
|
703
|
+
var tree = b.safeMime.parse(_msg(["Content-Type: text/plain"], "x"));
|
|
704
|
+
check("getAll missing header → empty array", tree.headers.getAll("x-absent").length === 0);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
function testUint8ArrayInput() {
|
|
708
|
+
var bytes = new Uint8Array(Buffer.from(_msg(["Content-Type: text/plain"], "u8")));
|
|
709
|
+
var tree = b.safeMime.parse(bytes);
|
|
710
|
+
check("Uint8Array input parsed", tree.leaf.body.toString() === "u8");
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
function testShortMalformedHeaderPreview() {
|
|
714
|
+
// A short (<64 char) header line with no colon: refused, and the
|
|
715
|
+
// byte-preview is returned untruncated (no ellipsis).
|
|
716
|
+
var threw = null;
|
|
717
|
+
try { b.safeMime.parse("nocolon\r\nContent-Type: text/plain\r\n\r\nbody"); }
|
|
718
|
+
catch (e) { threw = e; }
|
|
719
|
+
check("short missing-colon: refused", threw && (threw.code || "").indexOf("safe-mime/malformed-headers") !== -1);
|
|
720
|
+
check("short missing-colon: no ellipsis", threw && threw.message.indexOf("...") === -1);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// ---- Boundary grammar first/last-char rejection ----------------------------
|
|
724
|
+
|
|
725
|
+
function testBoundaryInvalidFirstLastChar() {
|
|
726
|
+
// Quoted boundary whose FIRST char is outside bcharsnospace.
|
|
727
|
+
expectRefused("boundary invalid first char refused",
|
|
728
|
+
function () { b.safeMime.parse(_msg(["Content-Type: multipart/mixed; boundary=\"!bad\""], "x")); },
|
|
729
|
+
"safe-mime/malformed-boundary");
|
|
730
|
+
// Quoted boundary whose LAST char is outside bcharsnospace.
|
|
731
|
+
expectRefused("boundary invalid last char refused",
|
|
732
|
+
function () { b.safeMime.parse(_msg(["Content-Type: multipart/mixed; boundary=\"bad!\""], "x")); },
|
|
733
|
+
"safe-mime/malformed-boundary");
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// ---- Content-Type poisoned parameter key -----------------------------------
|
|
737
|
+
|
|
738
|
+
function testContentTypePoisonedParamSkipped() {
|
|
739
|
+
var tree = b.safeMime.parse(_msg(["Content-Type: text/plain; __proto__=x; charset=utf-8"], "hi"));
|
|
740
|
+
check("ct poisoned param skipped", tree.leaf.charset === "utf-8" && ({}).x === undefined);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// ---- Malformed multipart bodies: empty-part slice clamps -------------------
|
|
744
|
+
|
|
745
|
+
function testMultipartEmptyPartClampsSlice() {
|
|
746
|
+
// A part opening immediately followed by the FINAL boundary (no body
|
|
747
|
+
// bytes between) clamps to a well-formed zero-length slice (RFC 2046
|
|
748
|
+
// §5.1.1 malformed-body handling).
|
|
749
|
+
var tree = b.safeMime.parse("Content-Type: multipart/mixed; boundary=B\r\n\r\n--B\r\n--B--");
|
|
750
|
+
check("empty-part clamp: one part", tree.parts.length === 1);
|
|
751
|
+
check("empty-part clamp: empty body", tree.parts[0].leaf.body.length === 0);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function testMultipartEmptyInteriorPartClamps() {
|
|
755
|
+
// A part opening immediately followed by a NON-final boundary clamps the
|
|
756
|
+
// same way, then a real second part follows.
|
|
757
|
+
var tree = b.safeMime.parse(
|
|
758
|
+
"Content-Type: multipart/mixed; boundary=B\r\n\r\n--B\r\n--B\r\nContent-Type: text/plain\r\n\r\nsecond\r\n--B--");
|
|
759
|
+
check("interior clamp: 2 parts", tree.parts.length === 2);
|
|
760
|
+
check("interior clamp: first empty", tree.parts[0].leaf.body.length === 0);
|
|
761
|
+
check("interior clamp: second body", tree.parts[1].leaf.body.toString().trim() === "second");
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// ---- extractText on a null/absent tree -------------------------------------
|
|
765
|
+
|
|
766
|
+
function testExtractTextNullTree() {
|
|
767
|
+
// extractText is commonly called on the result of a lookup that may be
|
|
768
|
+
// absent; a falsy tree must return null (not throw). Drives the
|
|
769
|
+
// `tree &&` short-circuit false arm plus the findFirst(null) → walk(null)
|
|
770
|
+
// no-op path.
|
|
771
|
+
check("extractText: null tree returns null", b.safeMime.extractText(null) === null);
|
|
772
|
+
check("extractText: undefined tree returns null", b.safeMime.extractText(undefined) === null);
|
|
773
|
+
check("extractText: null tree prefer=html null", b.safeMime.extractText(null, { prefer: "html" }) === null);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// ---- RFC 2046 §5.1.1 70-char boundary hard cap -----------------------------
|
|
777
|
+
|
|
778
|
+
function testBoundaryHardCapIndependentOfMaxBoundary() {
|
|
779
|
+
// The RFC 2046 §5.1.1 70-char boundary ceiling is enforced by the grammar
|
|
780
|
+
// validator itself, independent of the tunable `maxBoundary` opt. Raising
|
|
781
|
+
// maxBoundary above 70 does NOT permit a >70-char boundary: a 71-char
|
|
782
|
+
// otherwise-valid boundary still refuses as malformed. maxBoundary can
|
|
783
|
+
// only tighten the cap below 70, never loosen the RFC hard ceiling.
|
|
784
|
+
var boundary71 = new Array(72).join("a"); // 71 chars, all valid bchars
|
|
785
|
+
check("boundary71 is 71 chars", boundary71.length === 71);
|
|
786
|
+
expectRefused("71-char boundary refused even with maxBoundary raised to 200 (RFC 2046 §5.1.1 hard cap)",
|
|
787
|
+
function () {
|
|
788
|
+
b.safeMime.parse(
|
|
789
|
+
_msg(["Content-Type: multipart/mixed; boundary=" + boundary71], "x"),
|
|
790
|
+
{ maxBoundary: 200 });
|
|
791
|
+
},
|
|
792
|
+
"safe-mime/malformed-boundary");
|
|
793
|
+
}
|
|
794
|
+
|
|
311
795
|
async function run() {
|
|
312
796
|
testSurface();
|
|
313
797
|
testSimpleTextParse();
|
|
@@ -331,6 +815,40 @@ async function run() {
|
|
|
331
815
|
testHeaderFolding();
|
|
332
816
|
testMultiOccurrenceHeaders();
|
|
333
817
|
testPrototypePollutionDefense();
|
|
818
|
+
testWalkAndFindFirstGuards();
|
|
819
|
+
testExtractTextNonAlternativePaths();
|
|
820
|
+
testExtractTextAlternativeFallback();
|
|
821
|
+
testLfOnlyLineEndings();
|
|
822
|
+
testMultipartLfLineEndings();
|
|
823
|
+
testNoBlankLineSeparator();
|
|
824
|
+
testMultipartUnclosedLastPart();
|
|
825
|
+
testMultipartBoundaryNoTrailingNewline();
|
|
826
|
+
testMultipartBoundaryShapeMidLine();
|
|
827
|
+
testRefusesOversizeHeaderSection();
|
|
828
|
+
testRefusesOversizeBodyRaw();
|
|
829
|
+
testRefusesTooManyHeaders();
|
|
830
|
+
testRefusesOversizeHeaderLine();
|
|
831
|
+
testRefusesHeaderMissingColon();
|
|
832
|
+
testRefusesMalformedBoundaryGrammar();
|
|
833
|
+
testQuotedContentTypeParams();
|
|
834
|
+
testRefusesRfc2047HeaderInjection();
|
|
835
|
+
testCharsetDecodingBranches();
|
|
836
|
+
testRfc2231ExtendedFilename();
|
|
837
|
+
testFilenameFromContentTypeName();
|
|
838
|
+
testRfc2231MalformedFilenameNoThrow();
|
|
839
|
+
testCustomTransferEncodingAllowlist();
|
|
840
|
+
testCharsetAliasNormalization();
|
|
841
|
+
testExtractTextExtraBranches();
|
|
842
|
+
testExtractAttachmentsInline();
|
|
843
|
+
testHeaderGetAllMissing();
|
|
844
|
+
testUint8ArrayInput();
|
|
845
|
+
testShortMalformedHeaderPreview();
|
|
846
|
+
testBoundaryInvalidFirstLastChar();
|
|
847
|
+
testContentTypePoisonedParamSkipped();
|
|
848
|
+
testMultipartEmptyPartClampsSlice();
|
|
849
|
+
testMultipartEmptyInteriorPartClamps();
|
|
850
|
+
testExtractTextNullTree();
|
|
851
|
+
testBoundaryHardCapIndependentOfMaxBoundary();
|
|
334
852
|
}
|
|
335
853
|
|
|
336
854
|
module.exports = { run: run };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) blamejs contributors
|
|
3
|
+
"use strict";
|
|
4
|
+
/**
|
|
5
|
+
* b.safeObject — prototype-pollution-safe own-property access.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
var b = require("../..");
|
|
9
|
+
var helpers = require("../helpers");
|
|
10
|
+
var check = helpers.check;
|
|
11
|
+
|
|
12
|
+
function run() {
|
|
13
|
+
var so = b.safeObject;
|
|
14
|
+
check("b.safeObject.ownProp is a function", typeof so.ownProp === "function");
|
|
15
|
+
check("b.safeObject.ownSet is a function", typeof so.ownSet === "function");
|
|
16
|
+
|
|
17
|
+
// own data property → value
|
|
18
|
+
check("ownProp: own property returns value", so.ownProp({ a: 1 }, "a") === 1);
|
|
19
|
+
check("ownProp: own property valued undefined returns undefined",
|
|
20
|
+
so.ownProp({ a: undefined }, "a") === undefined);
|
|
21
|
+
check("ownProp: missing own property returns undefined",
|
|
22
|
+
so.ownProp({ a: 1 }, "b") === undefined);
|
|
23
|
+
|
|
24
|
+
// inherited / prototype-chain keys read as ABSENT (the whole point)
|
|
25
|
+
check("ownProp: inherited toString → undefined", so.ownProp({}, "toString") === undefined);
|
|
26
|
+
check("ownProp: __proto__ → undefined", so.ownProp({}, "__proto__") === undefined);
|
|
27
|
+
check("ownProp: constructor → undefined", so.ownProp({}, "constructor") === undefined);
|
|
28
|
+
check("ownProp: valueOf → undefined", so.ownProp({}, "valueOf") === undefined);
|
|
29
|
+
|
|
30
|
+
// an own key SHADOWING an inherited name is returned (it's own)
|
|
31
|
+
check("ownProp: own key shadowing an inherited name returns the own value",
|
|
32
|
+
so.ownProp({ toString: 7 }, "toString") === 7);
|
|
33
|
+
|
|
34
|
+
// a __proto__ accessor property cannot run on read (getOwnPropertyDescriptor,
|
|
35
|
+
// not a bracket read)
|
|
36
|
+
var trap = {};
|
|
37
|
+
Object.defineProperty(trap, "x", { get: function () { throw new Error("getter ran"); }, configurable: true });
|
|
38
|
+
var threw = false;
|
|
39
|
+
try { so.ownProp(trap, "x"); } catch (_e) { threw = true; }
|
|
40
|
+
check("ownProp: does not invoke an accessor getter on read", threw === false);
|
|
41
|
+
|
|
42
|
+
// null / undefined receivers are tolerated
|
|
43
|
+
check("ownProp: null receiver → undefined", so.ownProp(null, "a") === undefined);
|
|
44
|
+
check("ownProp: undefined receiver → undefined", so.ownProp(undefined, "a") === undefined);
|
|
45
|
+
|
|
46
|
+
// ownSet writes a plain own data property; never pollutes the prototype
|
|
47
|
+
var o = {};
|
|
48
|
+
so.ownSet(o, "__proto__", { polluted: 1 });
|
|
49
|
+
check("ownSet: __proto__ write does not pollute Object.prototype",
|
|
50
|
+
({}).polluted === undefined);
|
|
51
|
+
check("ownSet: the value lands as an OWN property", so.ownProp(o, "__proto__") &&
|
|
52
|
+
so.ownProp(o, "__proto__").polluted === 1);
|
|
53
|
+
so.ownSet(o, "k", 5);
|
|
54
|
+
check("ownSet: sets a normal own key", o.k === 5);
|
|
55
|
+
|
|
56
|
+
console.log("[safe-object] OK");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = { run: run };
|
|
60
|
+
if (require.main === module) {
|
|
61
|
+
try { run(); process.exit(0); } catch (e) { console.error(e); process.exit(1); }
|
|
62
|
+
}
|
|
@@ -129,6 +129,35 @@ function testCrossPlatformBackslashTraversalRefused() {
|
|
|
129
129
|
typeof ok === "string" && ok.indexOf("c.txt") !== -1);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
// confineToBase is the lexical-containment core resolve() layers its
|
|
133
|
+
// user-input strictness on top of. It contains traversal (escape → null)
|
|
134
|
+
// while NOT pre-judging segment content — so a consumer that wants only
|
|
135
|
+
// containment and runs its own, separately-calibrated filename validation
|
|
136
|
+
// (b.staticServe, with a per-file b.guardFilename basename gate) composes it
|
|
137
|
+
// instead of resolve. That layering divergence is why the primitive exists.
|
|
138
|
+
function testConfineToBaseContainsWithoutUserInputStrictness() {
|
|
139
|
+
var inRoot = b.safePath.confineToBase("/srv/www", "docs/a.html", { platform: "linux" });
|
|
140
|
+
check("confineToBase resolves an in-base path",
|
|
141
|
+
typeof inRoot === "string" && inRoot.indexOf("docs/a.html") !== -1);
|
|
142
|
+
check("confineToBase refuses a `..` escape (→ null)",
|
|
143
|
+
b.safePath.confineToBase("/srv/www", "../etc/passwd", { platform: "linux" }) === null);
|
|
144
|
+
// The two entry points diverge on a colon-bearing segment: confineToBase
|
|
145
|
+
// (pure containment) admits it; resolve() refuses it as a user-input ADS
|
|
146
|
+
// marker. The consumer decides how to validate segment content separately.
|
|
147
|
+
var colon = "2026-07-24T12:00:00.log";
|
|
148
|
+
check("confineToBase admits a colon-bearing segment (no user-input strictness)",
|
|
149
|
+
typeof b.safePath.confineToBase("/srv/www", colon, { platform: "linux" }) === "string");
|
|
150
|
+
check("resolve() still refuses the same colon name (user-input strictness)",
|
|
151
|
+
b.safePath.resolveOrNull("/srv/www", colon, { platform: "linux" }) === null);
|
|
152
|
+
// Windows-target backslash traversal is contained by the target-platform
|
|
153
|
+
// resolve, same as resolve()'s core.
|
|
154
|
+
var BS = String.fromCharCode(92);
|
|
155
|
+
check("confineToBase refuses a windows-target backslash traversal",
|
|
156
|
+
b.safePath.confineToBase("/srv/www", "ok" + BS + ".." + BS + ".." + BS + "x", { platform: "windows" }) === null);
|
|
157
|
+
check("confineToBase bad-input → null (empty base / non-string rel)",
|
|
158
|
+
b.safePath.confineToBase("", "x") === null && b.safePath.confineToBase("/srv", 5) === null);
|
|
159
|
+
}
|
|
160
|
+
|
|
132
161
|
function run() {
|
|
133
162
|
testHappyPath();
|
|
134
163
|
testRefusalClasses();
|
|
@@ -138,6 +167,7 @@ function run() {
|
|
|
138
167
|
testErrorClassExported();
|
|
139
168
|
testCrossPlatformContainment();
|
|
140
169
|
testCrossPlatformBackslashTraversalRefused();
|
|
170
|
+
testConfineToBaseContainsWithoutUserInputStrictness();
|
|
141
171
|
}
|
|
142
172
|
|
|
143
173
|
if (require.main === module) run();
|