@blamejs/blamejs-shop 0.4.56 → 0.4.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/lib/asset-manifest.json +1 -1
- package/lib/vendor/MANIFEST.json +426 -366
- package/lib/vendor/blamejs/.github/codeql/codeql-config.yml +25 -0
- package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
- package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/ci.yml +13 -13
- package/lib/vendor/blamejs/.github/workflows/codeql.yml +8 -7
- package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +2 -2
- package/lib/vendor/blamejs/.github/workflows/release-container.yml +4 -4
- package/lib/vendor/blamejs/.github/workflows/scorecard.yml +1 -1
- package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
- package/lib/vendor/blamejs/CHANGELOG.md +2 -0
- package/lib/vendor/blamejs/api-snapshot.json +1381 -4
- package/lib/vendor/blamejs/eslint.config.mjs +1 -0
- package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +4 -1
- package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +5 -2
- package/lib/vendor/blamejs/examples/wiki/routes/pages.js +4 -1
- package/lib/vendor/blamejs/fuzz/guard-text.fuzz.js +20 -0
- package/lib/vendor/blamejs/index.js +2 -0
- package/lib/vendor/blamejs/lib/a2a-tasks.js +7 -23
- package/lib/vendor/blamejs/lib/acme.js +6 -5
- package/lib/vendor/blamejs/lib/agent-event-bus.js +5 -4
- package/lib/vendor/blamejs/lib/agent-idempotency.js +2 -5
- package/lib/vendor/blamejs/lib/agent-orchestrator.js +2 -5
- package/lib/vendor/blamejs/lib/agent-saga.js +3 -5
- package/lib/vendor/blamejs/lib/agent-tenant.js +2 -5
- package/lib/vendor/blamejs/lib/ai-adverse-decision.js +2 -15
- package/lib/vendor/blamejs/lib/ai-capability.js +1 -6
- package/lib/vendor/blamejs/lib/ai-dp.js +1 -5
- package/lib/vendor/blamejs/lib/ai-input.js +2 -2
- package/lib/vendor/blamejs/lib/ai-pref.js +3 -8
- package/lib/vendor/blamejs/lib/ai-quota.js +3 -14
- package/lib/vendor/blamejs/lib/api-key.js +37 -28
- package/lib/vendor/blamejs/lib/archive-adapters.js +2 -4
- package/lib/vendor/blamejs/lib/archive-entry-policy.js +32 -0
- package/lib/vendor/blamejs/lib/archive-read.js +5 -17
- package/lib/vendor/blamejs/lib/archive-tar-read.js +5 -16
- package/lib/vendor/blamejs/lib/archive.js +2 -10
- package/lib/vendor/blamejs/lib/arg-parser.js +7 -6
- package/lib/vendor/blamejs/lib/asyncapi-traits.js +2 -6
- package/lib/vendor/blamejs/lib/atomic-file.js +108 -31
- package/lib/vendor/blamejs/lib/audit-chain.js +133 -53
- package/lib/vendor/blamejs/lib/audit-daily-review.js +24 -14
- package/lib/vendor/blamejs/lib/audit-emit.js +82 -0
- package/lib/vendor/blamejs/lib/audit-sign.js +257 -0
- package/lib/vendor/blamejs/lib/audit.js +84 -0
- package/lib/vendor/blamejs/lib/auth/access-lock.js +5 -27
- package/lib/vendor/blamejs/lib/auth/dpop.js +23 -35
- package/lib/vendor/blamejs/lib/auth/fido-mds3.js +9 -15
- package/lib/vendor/blamejs/lib/auth/jwt-external.js +26 -8
- package/lib/vendor/blamejs/lib/auth/jwt.js +13 -15
- package/lib/vendor/blamejs/lib/auth/lockout.js +6 -25
- package/lib/vendor/blamejs/lib/auth/oauth.js +67 -45
- package/lib/vendor/blamejs/lib/auth/oid4vci.js +55 -32
- package/lib/vendor/blamejs/lib/auth/oid4vp.js +3 -2
- package/lib/vendor/blamejs/lib/auth/openid-federation.js +6 -6
- package/lib/vendor/blamejs/lib/auth/passkey.js +3 -3
- package/lib/vendor/blamejs/lib/auth/password.js +7 -1
- package/lib/vendor/blamejs/lib/auth/saml.js +37 -27
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +2 -14
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +2 -14
- package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +1 -1
- package/lib/vendor/blamejs/lib/auth/status-list.js +7 -7
- package/lib/vendor/blamejs/lib/auth/step-up.js +6 -12
- package/lib/vendor/blamejs/lib/auth-bot-challenge.js +6 -37
- package/lib/vendor/blamejs/lib/backup/bundle.js +11 -18
- package/lib/vendor/blamejs/lib/backup/index.js +14 -47
- package/lib/vendor/blamejs/lib/bounded-map.js +112 -1
- package/lib/vendor/blamejs/lib/breach-deadline.js +1 -11
- package/lib/vendor/blamejs/lib/cache.js +7 -18
- package/lib/vendor/blamejs/lib/cbor.js +2 -1
- package/lib/vendor/blamejs/lib/cdn-cache-control.js +8 -9
- package/lib/vendor/blamejs/lib/cert.js +3 -10
- package/lib/vendor/blamejs/lib/chain-writer.js +162 -47
- package/lib/vendor/blamejs/lib/cli.js +5 -1
- package/lib/vendor/blamejs/lib/client-hints.js +7 -9
- package/lib/vendor/blamejs/lib/cloud-events.js +40 -31
- package/lib/vendor/blamejs/lib/cluster-storage.js +2 -38
- package/lib/vendor/blamejs/lib/cms-codec.js +2 -1
- package/lib/vendor/blamejs/lib/codepoint-class.js +67 -1
- package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +1 -6
- package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +2 -4
- package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -11
- package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +21 -28
- package/lib/vendor/blamejs/lib/compliance-sanctions.js +2 -14
- package/lib/vendor/blamejs/lib/compliance.js +2 -9
- package/lib/vendor/blamejs/lib/config-drift.js +2 -12
- package/lib/vendor/blamejs/lib/content-digest.js +10 -8
- package/lib/vendor/blamejs/lib/cookies.js +5 -11
- package/lib/vendor/blamejs/lib/cose.js +19 -11
- package/lib/vendor/blamejs/lib/cra-report.js +1 -11
- package/lib/vendor/blamejs/lib/crypto-field.js +5 -10
- package/lib/vendor/blamejs/lib/crypto.js +120 -3
- package/lib/vendor/blamejs/lib/csp.js +235 -3
- package/lib/vendor/blamejs/lib/daemon.js +42 -41
- package/lib/vendor/blamejs/lib/data-act.js +19 -9
- package/lib/vendor/blamejs/lib/db-query.js +6 -40
- package/lib/vendor/blamejs/lib/db.js +34 -12
- package/lib/vendor/blamejs/lib/dbsc.js +5 -6
- package/lib/vendor/blamejs/lib/ddl-change-control.js +18 -14
- package/lib/vendor/blamejs/lib/deprecate.js +4 -5
- package/lib/vendor/blamejs/lib/did.js +6 -2
- package/lib/vendor/blamejs/lib/dsr.js +8 -12
- package/lib/vendor/blamejs/lib/external-db-migrate.js +21 -22
- package/lib/vendor/blamejs/lib/external-db.js +14 -26
- package/lib/vendor/blamejs/lib/fda-21cfr11.js +12 -8
- package/lib/vendor/blamejs/lib/fdx.js +22 -18
- package/lib/vendor/blamejs/lib/file-upload.js +80 -66
- package/lib/vendor/blamejs/lib/flag-evaluation-context.js +5 -8
- package/lib/vendor/blamejs/lib/framework-error.js +12 -0
- package/lib/vendor/blamejs/lib/framework-schema.js +19 -0
- package/lib/vendor/blamejs/lib/fsm.js +7 -12
- package/lib/vendor/blamejs/lib/gate-contract.js +869 -38
- package/lib/vendor/blamejs/lib/gdpr-ropa.js +4 -13
- package/lib/vendor/blamejs/lib/graphql-federation.js +1 -1
- package/lib/vendor/blamejs/lib/guard-agent-registry.js +2 -1
- package/lib/vendor/blamejs/lib/guard-all.js +1 -0
- package/lib/vendor/blamejs/lib/guard-archive.js +9 -30
- package/lib/vendor/blamejs/lib/guard-auth.js +23 -80
- package/lib/vendor/blamejs/lib/guard-cidr.js +20 -96
- package/lib/vendor/blamejs/lib/guard-csv.js +135 -196
- package/lib/vendor/blamejs/lib/guard-domain.js +23 -106
- package/lib/vendor/blamejs/lib/guard-dsn.js +16 -13
- package/lib/vendor/blamejs/lib/guard-email.js +46 -53
- package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
- package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +2 -1
- package/lib/vendor/blamejs/lib/guard-filename.js +12 -60
- package/lib/vendor/blamejs/lib/guard-graphql.js +28 -75
- package/lib/vendor/blamejs/lib/guard-html-wcag.js +15 -2
- package/lib/vendor/blamejs/lib/guard-html.js +65 -117
- package/lib/vendor/blamejs/lib/guard-idempotency-key.js +2 -1
- package/lib/vendor/blamejs/lib/guard-image.js +280 -77
- package/lib/vendor/blamejs/lib/guard-imap-command.js +8 -9
- package/lib/vendor/blamejs/lib/guard-json.js +87 -103
- package/lib/vendor/blamejs/lib/guard-jsonpath.js +20 -88
- package/lib/vendor/blamejs/lib/guard-jwt.js +32 -114
- package/lib/vendor/blamejs/lib/guard-list-id.js +2 -7
- package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -7
- package/lib/vendor/blamejs/lib/guard-mail-compose.js +5 -6
- package/lib/vendor/blamejs/lib/guard-mail-move.js +2 -1
- package/lib/vendor/blamejs/lib/guard-mail-query.js +5 -3
- package/lib/vendor/blamejs/lib/guard-mail-sieve.js +6 -7
- package/lib/vendor/blamejs/lib/guard-managesieve-command.js +5 -4
- package/lib/vendor/blamejs/lib/guard-markdown.js +76 -110
- package/lib/vendor/blamejs/lib/guard-message-id.js +5 -6
- package/lib/vendor/blamejs/lib/guard-mime.js +20 -99
- package/lib/vendor/blamejs/lib/guard-oauth.js +19 -73
- package/lib/vendor/blamejs/lib/guard-pdf.js +65 -72
- package/lib/vendor/blamejs/lib/guard-pop3-command.js +12 -13
- package/lib/vendor/blamejs/lib/guard-posture-chain.js +2 -1
- package/lib/vendor/blamejs/lib/guard-regex.js +24 -99
- package/lib/vendor/blamejs/lib/guard-saga-config.js +2 -1
- package/lib/vendor/blamejs/lib/guard-shell.js +22 -87
- package/lib/vendor/blamejs/lib/guard-smtp-command.js +8 -11
- package/lib/vendor/blamejs/lib/guard-sql.js +15 -13
- package/lib/vendor/blamejs/lib/guard-stream-args.js +2 -1
- package/lib/vendor/blamejs/lib/guard-svg.js +95 -140
- package/lib/vendor/blamejs/lib/guard-template.js +23 -80
- package/lib/vendor/blamejs/lib/guard-tenant-id.js +2 -1
- package/lib/vendor/blamejs/lib/guard-text.js +592 -0
- package/lib/vendor/blamejs/lib/guard-time.js +27 -95
- package/lib/vendor/blamejs/lib/guard-uuid.js +21 -93
- package/lib/vendor/blamejs/lib/guard-xml.js +76 -106
- package/lib/vendor/blamejs/lib/guard-yaml.js +24 -60
- package/lib/vendor/blamejs/lib/http-client-cache.js +5 -12
- package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +2 -4
- package/lib/vendor/blamejs/lib/http-client.js +8 -21
- package/lib/vendor/blamejs/lib/http-message-signature.js +3 -2
- package/lib/vendor/blamejs/lib/i18n-messageformat.js +5 -7
- package/lib/vendor/blamejs/lib/i18n.js +83 -26
- package/lib/vendor/blamejs/lib/inbox.js +8 -8
- package/lib/vendor/blamejs/lib/incident-report.js +3 -21
- package/lib/vendor/blamejs/lib/ip-utils.js +49 -6
- package/lib/vendor/blamejs/lib/jobs.js +3 -2
- package/lib/vendor/blamejs/lib/keychain.js +6 -18
- package/lib/vendor/blamejs/lib/legal-hold.js +6 -15
- package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +44 -112
- package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +17 -14
- package/lib/vendor/blamejs/lib/log-stream-otlp.js +16 -80
- package/lib/vendor/blamejs/lib/log-stream-webhook.js +20 -92
- package/lib/vendor/blamejs/lib/mail-arc-sign.js +8 -3
- package/lib/vendor/blamejs/lib/mail-arf.js +3 -2
- package/lib/vendor/blamejs/lib/mail-auth.js +40 -66
- package/lib/vendor/blamejs/lib/mail-bimi.js +19 -39
- package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +3 -2
- package/lib/vendor/blamejs/lib/mail-dav.js +8 -35
- package/lib/vendor/blamejs/lib/mail-deploy.js +6 -9
- package/lib/vendor/blamejs/lib/mail-dkim.js +19 -38
- package/lib/vendor/blamejs/lib/mail-greylist.js +15 -26
- package/lib/vendor/blamejs/lib/mail-helo.js +2 -3
- package/lib/vendor/blamejs/lib/mail-journal.js +2 -1
- package/lib/vendor/blamejs/lib/mail-mdn.js +4 -3
- package/lib/vendor/blamejs/lib/mail-rbl.js +5 -8
- package/lib/vendor/blamejs/lib/mail-scan.js +2 -2
- package/lib/vendor/blamejs/lib/mail-send-deliver.js +33 -20
- package/lib/vendor/blamejs/lib/mail-server-imap.js +32 -87
- package/lib/vendor/blamejs/lib/mail-server-jmap.js +35 -51
- package/lib/vendor/blamejs/lib/mail-server-managesieve.js +29 -83
- package/lib/vendor/blamejs/lib/mail-server-mx.js +33 -74
- package/lib/vendor/blamejs/lib/mail-server-net.js +177 -0
- package/lib/vendor/blamejs/lib/mail-server-pop3.js +30 -83
- package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +30 -6
- package/lib/vendor/blamejs/lib/mail-server-submission.js +34 -73
- package/lib/vendor/blamejs/lib/mail-server-tls.js +89 -0
- package/lib/vendor/blamejs/lib/mail-spam-score.js +7 -8
- package/lib/vendor/blamejs/lib/mail-store.js +3 -2
- package/lib/vendor/blamejs/lib/mail.js +6 -11
- package/lib/vendor/blamejs/lib/markup-escape.js +31 -0
- package/lib/vendor/blamejs/lib/markup-tokenizer.js +54 -0
- package/lib/vendor/blamejs/lib/mcp-tool-registry.js +26 -23
- package/lib/vendor/blamejs/lib/mcp.js +1 -1
- package/lib/vendor/blamejs/lib/mdoc.js +11 -12
- package/lib/vendor/blamejs/lib/metrics.js +32 -30
- package/lib/vendor/blamejs/lib/middleware/age-gate.js +3 -23
- package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +11 -22
- package/lib/vendor/blamejs/lib/middleware/assetlinks.js +2 -7
- package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +2 -1
- package/lib/vendor/blamejs/lib/middleware/body-parser.js +31 -48
- package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +7 -10
- package/lib/vendor/blamejs/lib/middleware/bot-guard.js +2 -10
- package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +13 -2
- package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -26
- package/lib/vendor/blamejs/lib/middleware/deny-response.js +19 -1
- package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +7 -0
- package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +4 -20
- package/lib/vendor/blamejs/lib/middleware/rate-limit.js +20 -28
- package/lib/vendor/blamejs/lib/middleware/scim-server.js +3 -2
- package/lib/vendor/blamejs/lib/middleware/security-headers.js +9 -1
- package/lib/vendor/blamejs/lib/middleware/security-txt.js +2 -6
- package/lib/vendor/blamejs/lib/middleware/tus-upload.js +12 -27
- package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +2 -7
- package/lib/vendor/blamejs/lib/migrations.js +4 -13
- package/lib/vendor/blamejs/lib/mime-parse.js +34 -17
- package/lib/vendor/blamejs/lib/module-loader.js +44 -0
- package/lib/vendor/blamejs/lib/money.js +105 -0
- package/lib/vendor/blamejs/lib/mtls-ca.js +116 -36
- package/lib/vendor/blamejs/lib/network-byte-quota.js +4 -18
- package/lib/vendor/blamejs/lib/network-dane.js +8 -6
- package/lib/vendor/blamejs/lib/network-dns-resolver.js +97 -6
- package/lib/vendor/blamejs/lib/network-dnssec.js +16 -16
- package/lib/vendor/blamejs/lib/network-heartbeat.js +3 -2
- package/lib/vendor/blamejs/lib/network-smtp-policy.js +29 -41
- package/lib/vendor/blamejs/lib/network-tls.js +40 -42
- package/lib/vendor/blamejs/lib/nis2-report.js +1 -11
- package/lib/vendor/blamejs/lib/nonce-store.js +81 -3
- package/lib/vendor/blamejs/lib/numeric-bounds.js +22 -8
- package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +2 -6
- package/lib/vendor/blamejs/lib/object-store/azure-blob.js +5 -45
- package/lib/vendor/blamejs/lib/object-store/gcs.js +8 -71
- package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -5
- package/lib/vendor/blamejs/lib/object-store/http-request.js +128 -0
- package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +2 -1
- package/lib/vendor/blamejs/lib/object-store/sigv4.js +9 -77
- package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -25
- package/lib/vendor/blamejs/lib/observability.js +95 -0
- package/lib/vendor/blamejs/lib/openapi-paths-builder.js +7 -3
- package/lib/vendor/blamejs/lib/otel-export.js +7 -10
- package/lib/vendor/blamejs/lib/outbox.js +43 -37
- package/lib/vendor/blamejs/lib/pagination.js +11 -15
- package/lib/vendor/blamejs/lib/parsers/safe-env.js +5 -4
- package/lib/vendor/blamejs/lib/parsers/safe-ini.js +10 -4
- package/lib/vendor/blamejs/lib/parsers/safe-toml.js +11 -9
- package/lib/vendor/blamejs/lib/parsers/safe-xml.js +2 -2
- package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +7 -6
- package/lib/vendor/blamejs/lib/pick.js +63 -5
- package/lib/vendor/blamejs/lib/pipl-cn.js +69 -59
- package/lib/vendor/blamejs/lib/privacy-pass.js +8 -6
- package/lib/vendor/blamejs/lib/problem-details.js +2 -5
- package/lib/vendor/blamejs/lib/pubsub.js +4 -8
- package/lib/vendor/blamejs/lib/redact.js +2 -1
- package/lib/vendor/blamejs/lib/render.js +4 -2
- package/lib/vendor/blamejs/lib/request-helpers.js +133 -6
- package/lib/vendor/blamejs/lib/restore.js +5 -22
- package/lib/vendor/blamejs/lib/retention.js +3 -5
- package/lib/vendor/blamejs/lib/safe-async.js +457 -0
- package/lib/vendor/blamejs/lib/safe-buffer.js +137 -6
- package/lib/vendor/blamejs/lib/safe-decompress.js +2 -1
- package/lib/vendor/blamejs/lib/safe-dns.js +2 -1
- package/lib/vendor/blamejs/lib/safe-ical.js +12 -26
- package/lib/vendor/blamejs/lib/safe-json.js +7 -8
- package/lib/vendor/blamejs/lib/safe-jsonpath.js +6 -5
- package/lib/vendor/blamejs/lib/safe-mime.js +25 -29
- package/lib/vendor/blamejs/lib/safe-redirect.js +2 -5
- package/lib/vendor/blamejs/lib/safe-schema.js +7 -6
- package/lib/vendor/blamejs/lib/safe-sql.js +126 -0
- package/lib/vendor/blamejs/lib/safe-vcard.js +12 -26
- package/lib/vendor/blamejs/lib/sandbox-worker.js +9 -2
- package/lib/vendor/blamejs/lib/sandbox.js +3 -2
- package/lib/vendor/blamejs/lib/scheduler.js +5 -12
- package/lib/vendor/blamejs/lib/sec-cyber.js +82 -37
- package/lib/vendor/blamejs/lib/seeders.js +4 -11
- package/lib/vendor/blamejs/lib/self-update.js +92 -69
- package/lib/vendor/blamejs/lib/session-device-binding.js +112 -66
- package/lib/vendor/blamejs/lib/session.js +194 -6
- package/lib/vendor/blamejs/lib/sql.js +225 -78
- package/lib/vendor/blamejs/lib/sse.js +6 -10
- package/lib/vendor/blamejs/lib/static.js +136 -98
- package/lib/vendor/blamejs/lib/storage.js +4 -2
- package/lib/vendor/blamejs/lib/structured-fields.js +275 -16
- package/lib/vendor/blamejs/lib/tenant-quota.js +2 -20
- package/lib/vendor/blamejs/lib/tsa.js +11 -15
- package/lib/vendor/blamejs/lib/validate-opts.js +154 -8
- package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +30 -48
- package/lib/vendor/blamejs/lib/vault-aad.js +3 -2
- package/lib/vendor/blamejs/lib/vc.js +2 -7
- package/lib/vendor/blamejs/lib/vex.js +35 -13
- package/lib/vendor/blamejs/lib/web-push-vapid.js +23 -20
- package/lib/vendor/blamejs/lib/webhook-dispatcher.js +706 -0
- package/lib/vendor/blamejs/lib/webhook.js +43 -18
- package/lib/vendor/blamejs/lib/websocket-channels.js +9 -7
- package/lib/vendor/blamejs/lib/websocket.js +7 -3
- package/lib/vendor/blamejs/lib/worm.js +2 -3
- package/lib/vendor/blamejs/lib/ws-client.js +8 -10
- package/lib/vendor/blamejs/package.json +1 -1
- package/lib/vendor/blamejs/release-notes/v0.15.13.json +81 -0
- package/lib/vendor/blamejs/scripts/check-changelog-extract.js +1 -1
- package/lib/vendor/blamejs/test/00-primitives.js +136 -7
- package/lib/vendor/blamejs/test/10-state.js +9 -3
- package/lib/vendor/blamejs/test/30-chain.js +40 -0
- package/lib/vendor/blamejs/test/helpers/check.js +18 -0
- package/lib/vendor/blamejs/test/helpers/db.js +4 -0
- package/lib/vendor/blamejs/test/helpers/index.js +1 -0
- package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +2 -1
- package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +2 -1
- package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +8 -1
- package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +1 -1
- package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +2 -1
- package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +269 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +149 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +51 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +88 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +55 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/backup-object-store-adapter.test.js +2 -2
- package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/bounded-map.test.js +129 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/chain-writer-multichain.test.js +107 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +12 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +2788 -3214
- package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +63 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +2 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +50 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +2 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-resolve-opts.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +9 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract-content-gate.test.js +290 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +84 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +78 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +23 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-gate-disposition-coverage.test.js +93 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +60 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +184 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +54 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +45 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +101 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +76 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-text.test.js +365 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +35 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +20 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +83 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +10 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +36 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +39 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mime-parse.test.js +106 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +17 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-revocation.test.js +98 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-release.test.js +77 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +48 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-memory-getorinsert.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +88 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +278 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +37 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +14 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +19 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +2 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +18 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +1 -1
- package/lib/vendor/blamejs/test/layer-0-primitives/session-valid-from.test.js +73 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +100 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +80 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/validate-opts-shape.test.js +235 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +374 -0
- package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +75 -8
- package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @module b.guardText
|
|
4
|
+
* @nav Guards
|
|
5
|
+
* @title Guard Text
|
|
6
|
+
*
|
|
7
|
+
* @intro
|
|
8
|
+
* General-purpose UTF-8 free-text content-safety guard — the screen for
|
|
9
|
+
* unconstrained human text (a comment, a note, a review body, a gift
|
|
10
|
+
* message, a display name) where the legitimate content is "arbitrary
|
|
11
|
+
* letters in any writing system" but the dangerous content is a hidden
|
|
12
|
+
* codepoint that renders as nothing yet changes meaning.
|
|
13
|
+
*
|
|
14
|
+
* Unlike the format-specific members of the guard family (csv / html / svg /
|
|
15
|
+
* json / yaml / xml / markdown), this guard imposes NO grammar on its input.
|
|
16
|
+
* Cyrillic, Han, Arabic, emoji, combining marks — all pass. What it screens
|
|
17
|
+
* is the codepoint threat catalog shared across the family:
|
|
18
|
+
*
|
|
19
|
+
* - Unicode bidi overrides (CVE-2021-42574 Trojan Source — U+202A..U+202E,
|
|
20
|
+
* U+2066..U+2069, U+200E/F, U+061C). Visible text reads one way; the
|
|
21
|
+
* logical order is reversed.
|
|
22
|
+
* - C0 control characters (minus tab / lf / cr, which are legitimate in
|
|
23
|
+
* free text) — terminal-escape and log-injection vectors.
|
|
24
|
+
* - Null bytes — truncation / C-string-boundary attacks downstream.
|
|
25
|
+
* - Zero-width / invisible formatting chars (ZWSP / ZWNJ / ZWJ / WJ / SHY /
|
|
26
|
+
* BOM) — payload-hiding and watermark channels.
|
|
27
|
+
* - Unicode Tags block (U+E0000..U+E007F) — "ASCII smuggling": an invisible
|
|
28
|
+
* copy of an ASCII instruction an LLM tokenizer reads verbatim
|
|
29
|
+
* (prompt-injection over a comment field).
|
|
30
|
+
* - Mixed-script confusables (UTS #39) — a Cyrillic letter inside an
|
|
31
|
+
* otherwise-Latin word. Audit severity by default (legitimate
|
|
32
|
+
* multilingual text mixes scripts); promoted to refuse under the strict
|
|
33
|
+
* profile and the regulated postures.
|
|
34
|
+
*
|
|
35
|
+
* Three profiles ship — `strict` / `balanced` / `permissive` — plus four
|
|
36
|
+
* compliance postures (`hipaa` / `pci-dss` / `gdpr` / `soc2`). `strict`
|
|
37
|
+
* rejects bidi / control / null; `balanced` strips them and serves the
|
|
38
|
+
* cleaned text; `permissive` strips the invisibles and only audits the rest.
|
|
39
|
+
* Sanitize is a SHRINKING operation by contract — stripping invisible
|
|
40
|
+
* codepoints never grows the string; an amplification past
|
|
41
|
+
* `sanitizeAmplificationCap` (default 1.5x) is refused.
|
|
42
|
+
*
|
|
43
|
+
* `b.guardText.gate(opts)` plugs into `b.fileUpload` / `b.staticServe` /
|
|
44
|
+
* `b.mail` / `b.objectStore` / `b.guardAll` like every other content guard.
|
|
45
|
+
*
|
|
46
|
+
* Threat-detection regex literals are composed from the numeric codepoint
|
|
47
|
+
* tables in `b.codepointClass`. The source file never embeds the attack
|
|
48
|
+
* characters themselves (the family ASCII-purity invariant).
|
|
49
|
+
*
|
|
50
|
+
* @card
|
|
51
|
+
* General-purpose UTF-8 free-text guard — allows arbitrary letters in any script, screens bidi / control / null / zero-width / Unicode-Tags / confusable codepoints.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
var codepointClass = require("./codepoint-class");
|
|
55
|
+
var C = require("./constants");
|
|
56
|
+
var numericBounds = require("./numeric-bounds");
|
|
57
|
+
var gateContract = require("./gate-contract");
|
|
58
|
+
var { GuardTextError } = require("./framework-error");
|
|
59
|
+
|
|
60
|
+
var _err = GuardTextError.factory;
|
|
61
|
+
var HEX_RADIX = 16; // base-16 radix, not byte size
|
|
62
|
+
|
|
63
|
+
// ---- Shared codepoint catalog (composed from lib/codepoint-class) ----
|
|
64
|
+
// Pre-compiled regexes pulled from the shared catalog; this guard adds no
|
|
65
|
+
// codepoint table of its own.
|
|
66
|
+
var TAG_RE = codepointClass.TAG_RE;
|
|
67
|
+
|
|
68
|
+
// ---- Profile presets ----
|
|
69
|
+
// policy axis vocabulary mirrors the codepoint-class opt names so
|
|
70
|
+
// detectCharThreats / assertNoCharThreats / applyCharStripPolicies read them
|
|
71
|
+
// directly: bidiPolicy / controlPolicy / nullBytePolicy / zeroWidthPolicy /
|
|
72
|
+
// tagsPolicy each in "reject" | "strip" | "audit" | "allow". confusablePolicy
|
|
73
|
+
// ("reject" | "audit" | "allow") is text-specific — no strip, because you
|
|
74
|
+
// cannot repair a confusable without guessing the intended script.
|
|
75
|
+
var PROFILES = Object.freeze({
|
|
76
|
+
"strict": {
|
|
77
|
+
...gateContract.CHAR_THREATS_REJECT_ALL,
|
|
78
|
+
tagsPolicy: "reject",
|
|
79
|
+
confusablePolicy: "reject",
|
|
80
|
+
allowedScripts: null,
|
|
81
|
+
maxBytes: C.BYTES.mib(1),
|
|
82
|
+
},
|
|
83
|
+
"balanced": {
|
|
84
|
+
bidiPolicy: "strip",
|
|
85
|
+
controlPolicy: "strip",
|
|
86
|
+
nullBytePolicy: "strip",
|
|
87
|
+
zeroWidthPolicy: "strip",
|
|
88
|
+
tagsPolicy: "strip",
|
|
89
|
+
confusablePolicy: "audit",
|
|
90
|
+
allowedScripts: null,
|
|
91
|
+
maxBytes: C.BYTES.mib(4),
|
|
92
|
+
},
|
|
93
|
+
"permissive": {
|
|
94
|
+
bidiPolicy: "audit",
|
|
95
|
+
controlPolicy: "strip",
|
|
96
|
+
nullBytePolicy: "strip",
|
|
97
|
+
zeroWidthPolicy: "strip",
|
|
98
|
+
tagsPolicy: "strip",
|
|
99
|
+
confusablePolicy: "allow",
|
|
100
|
+
allowedScripts: null,
|
|
101
|
+
maxBytes: C.BYTES.mib(16),
|
|
102
|
+
encodingPolicy: "audit",
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
var DEFAULTS = gateContract.strictDefaults(PROFILES, {
|
|
107
|
+
// Encoding/keyspace axis (byte→codepoint layer + codepoint range), distinct
|
|
108
|
+
// from the bad-codepoint regexes. encodingPolicy: reject malformed UTF-8 by
|
|
109
|
+
// default; asciiOnly / maxCodepoint are opt-in keyspace ceilings.
|
|
110
|
+
encodingPolicy: "reject", // "reject" | "audit" | "allow"
|
|
111
|
+
asciiOnly: false,
|
|
112
|
+
maxCodepoint: null,
|
|
113
|
+
sanitizeAmplificationCap: 1.5,
|
|
114
|
+
forensicSnippetBytes: 0,
|
|
115
|
+
maxRuntimeMs: C.TIME.seconds(30),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
var COMPLIANCE_POSTURES = gateContract.compliancePostures(PROFILES, { base: 256 });
|
|
119
|
+
|
|
120
|
+
// ---- Internal helpers ----
|
|
121
|
+
|
|
122
|
+
function _resolveOpts(opts) {
|
|
123
|
+
return gateContract.resolveProfileAndPosture(opts, {
|
|
124
|
+
profiles: PROFILES,
|
|
125
|
+
compliancePostures: COMPLIANCE_POSTURES,
|
|
126
|
+
defaults: DEFAULTS,
|
|
127
|
+
errorClass: GuardTextError,
|
|
128
|
+
errCodePrefix: "text",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function _firstMatch(text, re) {
|
|
133
|
+
if (typeof text !== "string") return null;
|
|
134
|
+
var m = text.match(re);
|
|
135
|
+
if (!m) return null;
|
|
136
|
+
return { index: m.index, char: m[0] };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// _STRICT_UTF8 — fatal-mode decoder: an overlong encoding, an invalid
|
|
140
|
+
// continuation byte, or a truncated multibyte sequence THROWS instead of
|
|
141
|
+
// lossily substituting U+FFFD. A guard that only `toString("utf8")`s its bytes
|
|
142
|
+
// silently launders an overlong-encoded "/" or NUL into U+FFFD, defeating a
|
|
143
|
+
// downstream filter (the classic UTF-8 overlong filter-bypass). Validating the
|
|
144
|
+
// ENCODING (the byte→codepoint layer) is distinct from the codepoint regexes.
|
|
145
|
+
var _STRICT_UTF8 = new TextDecoder("utf-8", { fatal: true });
|
|
146
|
+
// Unpaired UTF-16 surrogate in an already-decoded JS string (malformed Unicode
|
|
147
|
+
// that a Buffer round-trip can't represent).
|
|
148
|
+
var _LONE_SURROGATE_RE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:^|[^\uD800-\uDBFF])[\uDC00-\uDFFF]/;
|
|
149
|
+
|
|
150
|
+
// _strictText — decode `input` to a JS string AND report a malformed encoding.
|
|
151
|
+
// Buffer → strict UTF-8 (fatal); string → unpaired-surrogate check. Returns
|
|
152
|
+
// { text, encodingError } where encodingError is null for well-formed input.
|
|
153
|
+
function _strictText(input) {
|
|
154
|
+
if (Buffer.isBuffer(input)) {
|
|
155
|
+
try { return { text: _STRICT_UTF8.decode(input), encodingError: null }; }
|
|
156
|
+
catch (_e) {
|
|
157
|
+
return { text: input.toString("utf8"),
|
|
158
|
+
encodingError: "malformed UTF-8 (overlong / invalid continuation / truncated multibyte)" };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (typeof input === "string") {
|
|
162
|
+
return { text: input,
|
|
163
|
+
// allow:regex-no-length-cap — _LONE_SURROGATE_RE is a single-pass char-class
|
|
164
|
+
// alternation (no quantifier, no backtracking); O(n) on any input length.
|
|
165
|
+
encodingError: _LONE_SURROGATE_RE.test(input) ? "unpaired UTF-16 surrogate" : null };
|
|
166
|
+
}
|
|
167
|
+
return { text: null, encodingError: null };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// _firstCodepointAbove — first codepoint exceeding `max` (keyspace ceiling),
|
|
171
|
+
// iterating by codepoint so an astral char counts once. Returns { index, cp }.
|
|
172
|
+
function _firstCodepointAbove(text, max) {
|
|
173
|
+
for (var i = 0; i < text.length; ) {
|
|
174
|
+
var cp = text.codePointAt(i);
|
|
175
|
+
if (cp > max) return { index: i, cp: cp };
|
|
176
|
+
i += cp > 0xFFFF ? 2 : 1;
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// _detectIssues — pure inspection; never mutates / throws. Emits at most one
|
|
182
|
+
// issue per class (the codepoint catalog classes + the text-specific
|
|
183
|
+
// confusable class). An "allow" policy suppresses the class entirely;
|
|
184
|
+
// everything else surfaces the issue and the gate/sanitize layer decides
|
|
185
|
+
// serve / strip / refuse.
|
|
186
|
+
function _detectIssues(text, opts) {
|
|
187
|
+
var issues = [];
|
|
188
|
+
if (typeof text !== "string") return issues;
|
|
189
|
+
|
|
190
|
+
// bidi / null-byte / control / zero-width — delegate to the shared catalog
|
|
191
|
+
// detector so the per-class match-and-push block lives in exactly one place.
|
|
192
|
+
// Invisible chars spoof displayed text (homoglyph), so zero-width is `high`.
|
|
193
|
+
issues.push.apply(issues, codepointClass.detectCharThreats(text, opts, "text", "high"));
|
|
194
|
+
|
|
195
|
+
if (opts.tagsPolicy !== "allow") {
|
|
196
|
+
// TAG_RE uses the `u` flag (astral block U+E0000..U+E007F); index is the
|
|
197
|
+
// UTF-16 offset of the first tag codepoint.
|
|
198
|
+
var tagMatch = text.match(TAG_RE);
|
|
199
|
+
if (tagMatch) {
|
|
200
|
+
issues.push({
|
|
201
|
+
kind: "unicode-tags", severity: "critical", ruleId: "text.unicode-tags",
|
|
202
|
+
location: tagMatch.index,
|
|
203
|
+
snippet: "Unicode Tags block char (ASCII-smuggling / prompt-injection) at offset " +
|
|
204
|
+
tagMatch.index,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (opts.confusablePolicy !== "allow") {
|
|
210
|
+
var scripts = codepointClass.detectMixedScripts(text, opts.allowedScripts || null);
|
|
211
|
+
if (scripts) {
|
|
212
|
+
// Mixed-script is an audit signal by default (legitimate multilingual
|
|
213
|
+
// text mixes scripts); strict / regulated postures set confusablePolicy
|
|
214
|
+
// "reject", which promotes the severity below so the gate refuses.
|
|
215
|
+
issues.push({
|
|
216
|
+
kind: "mixed-script-confusable",
|
|
217
|
+
severity: opts.confusablePolicy === "reject" ? "high" : "warn",
|
|
218
|
+
ruleId: "text.confusable",
|
|
219
|
+
location: 0,
|
|
220
|
+
snippet: "mixed-script text (UTS #39 confusable risk): " + scripts.join(", "),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Keyspace bounds — restrict the allowed codepoint range. asciiOnly pins the
|
|
226
|
+
// keyspace to US-ASCII (cp <= 0x7F); maxCodepoint sets an arbitrary ceiling.
|
|
227
|
+
// Distinct from the script/confusable axis: this is the raw codepoint range,
|
|
228
|
+
// not which writing systems mix.
|
|
229
|
+
if (opts.asciiOnly) {
|
|
230
|
+
var na = _firstCodepointAbove(text, 0x7F);
|
|
231
|
+
if (na) {
|
|
232
|
+
issues.push({
|
|
233
|
+
kind: "non-ascii", severity: "high", ruleId: "text.non-ascii",
|
|
234
|
+
location: na.index,
|
|
235
|
+
snippet: "non-ASCII codepoint U+" + na.cp.toString(HEX_RADIX) +
|
|
236
|
+
" at offset " + na.index + " (asciiOnly keyspace)",
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (typeof opts.maxCodepoint === "number") {
|
|
241
|
+
var oor = _firstCodepointAbove(text, opts.maxCodepoint);
|
|
242
|
+
if (oor) {
|
|
243
|
+
issues.push({
|
|
244
|
+
kind: "codepoint-out-of-range", severity: "high", ruleId: "text.codepoint-range",
|
|
245
|
+
location: oor.index,
|
|
246
|
+
snippet: "codepoint U+" + oor.cp.toString(HEX_RADIX) + " at offset " +
|
|
247
|
+
oor.index + " exceeds maxCodepoint U+" + opts.maxCodepoint.toString(HEX_RADIX),
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return issues;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// _STRIPPABLE — issue kinds whose codepoints the sanitizer can physically
|
|
256
|
+
// remove. A confusable / too-large / operator-rule hit is NOT in this set:
|
|
257
|
+
// there is no safe automated repair, so its disposition can only be serve /
|
|
258
|
+
// audit / refuse — never sanitize.
|
|
259
|
+
var _STRIPPABLE = Object.freeze({
|
|
260
|
+
"bidi-override": true, "control-char": true, "null-byte": true,
|
|
261
|
+
"zero-width": true, "unicode-tags": true,
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// _dispositionFor — map a fired issue to the operator's chosen disposition
|
|
265
|
+
// for its class, drawn from the resolved policy axis (not a generic severity
|
|
266
|
+
// threshold). This is what makes the profile semantics honest: under
|
|
267
|
+
// `permissive`, bidiPolicy "audit" means report-and-serve, while controlPolicy
|
|
268
|
+
// "strip" means remove-and-serve. Returns "reject" | "strip" | "audit" |
|
|
269
|
+
// "serve". A non-strippable class that an operator marked dangerous (a
|
|
270
|
+
// confusable under "reject", an oversized input, a high/critical operator
|
|
271
|
+
// rule) resolves to "reject" — never "strip" — so the gate refuses rather than
|
|
272
|
+
// serving a file it cannot actually clean.
|
|
273
|
+
function _dispositionFor(issue, opts) {
|
|
274
|
+
switch (issue.kind) {
|
|
275
|
+
case "bidi-override": return opts.bidiPolicy;
|
|
276
|
+
case "control-char": return opts.controlPolicy;
|
|
277
|
+
case "null-byte": return opts.nullBytePolicy;
|
|
278
|
+
case "zero-width": return opts.zeroWidthPolicy;
|
|
279
|
+
case "unicode-tags": return opts.tagsPolicy;
|
|
280
|
+
case "mixed-script-confusable":
|
|
281
|
+
// No "strip" — a confusable cannot be repaired without guessing the
|
|
282
|
+
// intended script. reject → refuse; anything else → audit-and-serve.
|
|
283
|
+
return opts.confusablePolicy === "reject" ? "reject" : "audit";
|
|
284
|
+
case "invalid-encoding":
|
|
285
|
+
// Malformed UTF-8 is not repairable by stripping. reject → refuse;
|
|
286
|
+
// audit → serve-with-note. ("allow" never produces this issue.)
|
|
287
|
+
return opts.encodingPolicy === "reject" ? "reject" : "audit";
|
|
288
|
+
case "non-ascii":
|
|
289
|
+
case "codepoint-out-of-range":
|
|
290
|
+
// A keyspace violation under an operator-set ceiling — not strippable
|
|
291
|
+
// (can't drop arbitrary letters), so refuse.
|
|
292
|
+
return "reject";
|
|
293
|
+
case "too-large":
|
|
294
|
+
case "bad-input":
|
|
295
|
+
return "reject";
|
|
296
|
+
default:
|
|
297
|
+
// Operator rule (or any custom kind): a high/critical hit blocks; a
|
|
298
|
+
// warn rides along as an audit note. Operator rules are never strippable.
|
|
299
|
+
return (issue.severity === "high" || issue.severity === "critical")
|
|
300
|
+
? "reject" : "audit";
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// _stripIssues — sanitize path. Removes only the invisible / dangerous
|
|
305
|
+
// codepoints whose policy is "strip"; never touches legitimate letters, never
|
|
306
|
+
// repairs a confusable (no safe automated repair). Delegates the bidi /
|
|
307
|
+
// control / null / zero-width / tags strips to the shared catalog helper so
|
|
308
|
+
// the replace() sequence lives once.
|
|
309
|
+
function _stripIssues(text, opts) {
|
|
310
|
+
if (typeof text !== "string") return text;
|
|
311
|
+
return codepointClass.applyCharStripPolicies(text, opts);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// ---- Public surface ----
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* @primitive b.guardText.validate
|
|
318
|
+
* @signature b.guardText.validate(input, opts?)
|
|
319
|
+
* @since 0.15.13
|
|
320
|
+
* @status stable
|
|
321
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
322
|
+
* @related b.guardText.sanitize, b.guardText.gate, b.guardAll.gate
|
|
323
|
+
*
|
|
324
|
+
* Inspect `input` (string or Buffer of UTF-8 text) and return `{ ok, issues }`.
|
|
325
|
+
* Each issue carries `{ kind, severity, ruleId, location, snippet }` with
|
|
326
|
+
* severity in `"warn"|"high"|"critical"`. Three validation axes: (1) ENCODING —
|
|
327
|
+
* a Buffer is decoded as STRICT UTF-8, so a malformed / overlong / truncated
|
|
328
|
+
* sequence is flagged `invalid-encoding` rather than silently lossily decoded
|
|
329
|
+
* to U+FFFD (the overlong-encoding filter-bypass); a JS string is checked for
|
|
330
|
+
* unpaired surrogates. (2) KEYSPACE — `asciiOnly` pins the allowed codepoint
|
|
331
|
+
* range to US-ASCII and `maxCodepoint` sets a ceiling (distinct from the script
|
|
332
|
+
* axis: the raw codepoint range, not which writing systems mix). (3) CODEPOINT
|
|
333
|
+
* THREATS — Unicode bidi override (CVE-2021-42574 Trojan Source), C0 control
|
|
334
|
+
* char, null byte, zero-width / invisible char, Unicode Tags block char (ASCII
|
|
335
|
+
* smuggling), and mixed-script confusable. Arbitrary letters in any single
|
|
336
|
+
* script are NOT issues — this guard imposes no grammar. `ok` is `false` only
|
|
337
|
+
* when at least one issue is `high` or `critical`. Pure inspection — never
|
|
338
|
+
* mutates input or throws (other than the `maxBytes` positive-finite-integer
|
|
339
|
+
* opt check). The `maxBytes` limit is measured in UTF-8 BYTES. Passing
|
|
340
|
+
* `Infinity` for `maxBytes` throws.
|
|
341
|
+
*
|
|
342
|
+
* @opts
|
|
343
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
344
|
+
* compliancePosture: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
345
|
+
* bidiPolicy: "reject"|"strip"|"audit"|"allow",
|
|
346
|
+
* controlPolicy: "reject"|"strip"|"allow",
|
|
347
|
+
* nullBytePolicy: "reject"|"strip"|"allow",
|
|
348
|
+
* zeroWidthPolicy: "reject"|"strip"|"allow",
|
|
349
|
+
* tagsPolicy: "reject"|"strip"|"allow",
|
|
350
|
+
* confusablePolicy: "reject"|"audit"|"allow",
|
|
351
|
+
* encodingPolicy: "reject"|"audit"|"allow", // malformed UTF-8 (default reject)
|
|
352
|
+
* asciiOnly: boolean, // keyspace = US-ASCII only (default false)
|
|
353
|
+
* maxCodepoint: number, // keyspace ceiling (e.g. 0xFFFF for BMP-only)
|
|
354
|
+
* allowedScripts: Array, // confusable allowlist (e.g. ["latin","han"])
|
|
355
|
+
* maxBytes: number, // default 1 MiB, measured in UTF-8 bytes
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* var rv = b.guardText.validate("hello world", { profile: "strict" });
|
|
359
|
+
* rv.ok; // → true
|
|
360
|
+
* // Build the hostile input programmatically so the source stays ASCII.
|
|
361
|
+
* var RLO = String.fromCharCode(0x202E);
|
|
362
|
+
* var bad = b.guardText.validate("review " + RLO + "txt.exe", { profile: "strict" });
|
|
363
|
+
* bad.ok; // → false
|
|
364
|
+
* bad.issues[0].kind; // → "bidi-override"
|
|
365
|
+
*/
|
|
366
|
+
function validate(input, opts) {
|
|
367
|
+
opts = _resolveOpts(opts);
|
|
368
|
+
numericBounds.requireAllPositiveFiniteIntIfPresent(opts,
|
|
369
|
+
["maxBytes"], "guardText.validate", GuardTextError, "text.bad-opt");
|
|
370
|
+
|
|
371
|
+
var decoded = _strictText(input);
|
|
372
|
+
if (decoded.text == null) {
|
|
373
|
+
return gateContract.runIssueValidator(input, opts, _detectIssues);
|
|
374
|
+
}
|
|
375
|
+
// Encoding-validity is the byte→codepoint layer, checked before the codepoint
|
|
376
|
+
// regexes — a malformed/overlong sequence is a critical refuse-or-audit issue
|
|
377
|
+
// depending on encodingPolicy (default reject).
|
|
378
|
+
var encIssue = (decoded.encodingError && opts.encodingPolicy !== "allow")
|
|
379
|
+
? { kind: "invalid-encoding",
|
|
380
|
+
severity: opts.encodingPolicy === "reject" ? "critical" : "warn",
|
|
381
|
+
ruleId: "text.invalid-encoding", snippet: decoded.encodingError }
|
|
382
|
+
: null;
|
|
383
|
+
var byteLen = Buffer.byteLength(decoded.text, "utf8");
|
|
384
|
+
if (byteLen > opts.maxBytes) {
|
|
385
|
+
var big = [{ kind: "too-large", severity: "high", ruleId: "text.too-large",
|
|
386
|
+
snippet: "input " + byteLen + " bytes exceeds maxBytes " + opts.maxBytes }];
|
|
387
|
+
if (encIssue) big.unshift(encIssue);
|
|
388
|
+
return { ok: false, issues: big };
|
|
389
|
+
}
|
|
390
|
+
var rv = gateContract.runIssueValidator(decoded.text, opts, _detectIssues);
|
|
391
|
+
if (!encIssue) return rv;
|
|
392
|
+
var issues = [encIssue].concat(rv.issues);
|
|
393
|
+
var ok = issues.every(function (i) { return i.severity !== "critical" && i.severity !== "high"; });
|
|
394
|
+
return { ok: ok, issues: issues };
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* @primitive b.guardText.sanitize
|
|
399
|
+
* @signature b.guardText.sanitize(input, opts?)
|
|
400
|
+
* @since 0.15.13
|
|
401
|
+
* @status stable
|
|
402
|
+
* @related b.guardText.validate, b.guardText.gate
|
|
403
|
+
*
|
|
404
|
+
* Best-effort cleanup of `input` (string or Buffer): strips bidi overrides
|
|
405
|
+
* (when `bidiPolicy: "strip"`), C0 control chars (`controlPolicy: "strip"`),
|
|
406
|
+
* null bytes (`nullBytePolicy: "strip"`), zero-width / invisible chars
|
|
407
|
+
* (`zeroWidthPolicy: "strip"`), and Unicode Tags block chars (`tagsPolicy:
|
|
408
|
+
* "strip"`). Legitimate letters in any script are preserved; a mixed-script
|
|
409
|
+
* confusable is NEVER auto-repaired (there is no safe automated repair — the
|
|
410
|
+
* gate refuses it instead). Sanitize is a SHRINKING operation by contract:
|
|
411
|
+
* when the output exceeds `sanitizeAmplificationCap` (default 1.5x) the
|
|
412
|
+
* function throws `GuardTextError("text.sanitize-amplified")`.
|
|
413
|
+
*
|
|
414
|
+
* @opts
|
|
415
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
416
|
+
* compliancePosture: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
417
|
+
* bidiPolicy: "reject"|"strip"|"audit"|"allow",
|
|
418
|
+
* controlPolicy: "reject"|"strip"|"allow",
|
|
419
|
+
* nullBytePolicy: "reject"|"strip"|"allow",
|
|
420
|
+
* zeroWidthPolicy: "reject"|"strip"|"allow",
|
|
421
|
+
* tagsPolicy: "reject"|"strip"|"allow",
|
|
422
|
+
* sanitizeAmplificationCap: number, // default 1.5
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* var ZWSP = String.fromCharCode(0x200B);
|
|
426
|
+
* var clean = b.guardText.sanitize("nice" + ZWSP + "review", { profile: "balanced" });
|
|
427
|
+
* clean.indexOf(ZWSP) === -1; // → true
|
|
428
|
+
* clean; // → "nicereview"
|
|
429
|
+
*/
|
|
430
|
+
function sanitize(input, opts) {
|
|
431
|
+
opts = _resolveOpts(opts);
|
|
432
|
+
var decoded = _strictText(input);
|
|
433
|
+
if (decoded.text == null) {
|
|
434
|
+
throw _err("text.bad-input", "sanitize requires string or Buffer input");
|
|
435
|
+
}
|
|
436
|
+
// Malformed UTF-8 is not safely repairable by stripping codepoints; under the
|
|
437
|
+
// default reject policy, refuse rather than serve a lossily-decoded string.
|
|
438
|
+
if (decoded.encodingError && opts.encodingPolicy === "reject") {
|
|
439
|
+
throw _err("text.invalid-encoding",
|
|
440
|
+
"cannot sanitize input with " + decoded.encodingError + " (not repairable)");
|
|
441
|
+
}
|
|
442
|
+
var text = decoded.text;
|
|
443
|
+
var byteLen = Buffer.byteLength(text, "utf8");
|
|
444
|
+
if (byteLen > opts.maxBytes) {
|
|
445
|
+
throw _err("text.too-large",
|
|
446
|
+
"input " + byteLen + " bytes exceeds maxBytes " + opts.maxBytes);
|
|
447
|
+
}
|
|
448
|
+
var sanitized = _stripIssues(text, opts);
|
|
449
|
+
var amplification = sanitized.length / Math.max(text.length, 1);
|
|
450
|
+
if (amplification > opts.sanitizeAmplificationCap) {
|
|
451
|
+
throw _err("text.sanitize-amplified",
|
|
452
|
+
"sanitize grew output " + amplification.toFixed(2) +
|
|
453
|
+
"x; cap " + opts.sanitizeAmplificationCap);
|
|
454
|
+
}
|
|
455
|
+
return sanitized;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* @primitive b.guardText.gate
|
|
460
|
+
* @signature b.guardText.gate(opts?)
|
|
461
|
+
* @since 0.15.13
|
|
462
|
+
* @status stable
|
|
463
|
+
* @compliance hipaa, pci-dss, gdpr, soc2
|
|
464
|
+
* @related b.guardText.validate, b.guardText.sanitize, b.fileUpload.create, b.staticServe.create
|
|
465
|
+
*
|
|
466
|
+
* Build a `b.gateContract` gate suitable for plugging into
|
|
467
|
+
* `b.fileUpload({ contentSafety: { "text/plain": gate } })`,
|
|
468
|
+
* `b.staticServe({ contentSafety: { ".txt": gate } })`, `b.mail`, or
|
|
469
|
+
* `b.objectStore`. Action chain on inspection: `serve` (no issues) →
|
|
470
|
+
* `audit-only` (warn-only issues — e.g. a mixed-script confusable under
|
|
471
|
+
* `confusablePolicy: "audit"`) → `sanitize` (critical/high but no `reject`
|
|
472
|
+
* policy active — strips the invisible codepoints and serves the cleaned text)
|
|
473
|
+
* → `refuse` (critical/high under any `reject` policy, a confusable under
|
|
474
|
+
* `confusablePolicy: "reject"`, or when sanitize fails / amplifies past cap).
|
|
475
|
+
*
|
|
476
|
+
* Operator extensibility: pass `operatorRules: [{ id, severity, detect:
|
|
477
|
+
* fn(ctx)->boolean, reason }]` to inject custom detectors alongside the
|
|
478
|
+
* built-in catalog. Rules run best-effort — a throwing detector is skipped
|
|
479
|
+
* (the framework cannot crash a request because an operator rule mishandled
|
|
480
|
+
* bytes).
|
|
481
|
+
*
|
|
482
|
+
* @opts
|
|
483
|
+
* profile: "strict"|"balanced"|"permissive",
|
|
484
|
+
* compliancePosture: "hipaa"|"pci-dss"|"gdpr"|"soc2",
|
|
485
|
+
* name: string, // gate identity for audit / observability
|
|
486
|
+
* operatorRules: Array, // [{ id, severity, detect: function, reason }]
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* var textGate = b.guardText.gate({ profile: "strict" });
|
|
490
|
+
* var upload = b.fileUpload.create({ contentSafety: { "text/plain": textGate } });
|
|
491
|
+
* var RLO = String.fromCharCode(0x202E);
|
|
492
|
+
* var hostile = Buffer.from("ok " + RLO + "danger", "utf8");
|
|
493
|
+
* var verdict = await textGate.check({ bytes: hostile });
|
|
494
|
+
* verdict.action; // → "refuse"
|
|
495
|
+
*/
|
|
496
|
+
function gate(opts) {
|
|
497
|
+
opts = _resolveOpts(opts);
|
|
498
|
+
return gateContract.buildGuardGate(
|
|
499
|
+
opts.name || "guardText:" + (opts.profile || "default"),
|
|
500
|
+
opts,
|
|
501
|
+
async function (ctx) {
|
|
502
|
+
var text = gateContract.extractBytesAsText(ctx);
|
|
503
|
+
if (!text) return { ok: true, action: "serve" };
|
|
504
|
+
// Validate the RAW bytes when present so strict UTF-8 decoding can catch a
|
|
505
|
+
// malformed / overlong sequence (extractBytesAsText already lossily
|
|
506
|
+
// decoded it to a string).
|
|
507
|
+
var rawInput = (ctx && Buffer.isBuffer(ctx.bytes)) ? ctx.bytes : text;
|
|
508
|
+
var rv = validate(rawInput, opts);
|
|
509
|
+
|
|
510
|
+
var operatorIssues = [];
|
|
511
|
+
if (Array.isArray(opts.operatorRules)) {
|
|
512
|
+
for (var ri = 0; ri < opts.operatorRules.length; ri += 1) {
|
|
513
|
+
var rule = opts.operatorRules[ri];
|
|
514
|
+
try {
|
|
515
|
+
if (rule.detect && rule.detect({ bytes: text, ctx: ctx })) {
|
|
516
|
+
operatorIssues.push({
|
|
517
|
+
kind: rule.id, severity: rule.severity || "warn",
|
|
518
|
+
ruleId: rule.id, snippet: rule.reason || rule.id,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
} catch (_e) { /* operator rule best-effort — never crash the request */ }
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
var allIssues = rv.issues.concat(operatorIssues);
|
|
525
|
+
if (allIssues.length === 0) return { ok: true, action: "serve" };
|
|
526
|
+
|
|
527
|
+
// Resolve the strongest disposition across every fired issue, driven by
|
|
528
|
+
// the per-class policy (reject > strip > audit > serve). One "reject"
|
|
529
|
+
// refuses; otherwise a "strip" sanitizes the strippable codepoints and
|
|
530
|
+
// serves the cleaned text; otherwise the issues are audit-only.
|
|
531
|
+
var dispositions = allIssues.map(function (i) { return _dispositionFor(i, opts); });
|
|
532
|
+
if (dispositions.indexOf("reject") !== -1) {
|
|
533
|
+
return { ok: false, action: "refuse", issues: allIssues };
|
|
534
|
+
}
|
|
535
|
+
if (dispositions.indexOf("strip") !== -1) {
|
|
536
|
+
// Fail-closed invariant: every issue we're about to "sanitize away"
|
|
537
|
+
// must be a codepoint class the stripper can physically remove. If a
|
|
538
|
+
// future kind ever resolves to "strip" without being strippable,
|
|
539
|
+
// refuse rather than serve a file we only claimed to clean.
|
|
540
|
+
var stripUnrepairable = allIssues.some(function (i, idx) {
|
|
541
|
+
return dispositions[idx] === "strip" && !_STRIPPABLE[i.kind];
|
|
542
|
+
});
|
|
543
|
+
if (stripUnrepairable) {
|
|
544
|
+
return { ok: false, action: "refuse", issues: allIssues };
|
|
545
|
+
}
|
|
546
|
+
// Amplify-past-cap / bad-input refuses instead.
|
|
547
|
+
try {
|
|
548
|
+
var clean = sanitize(text, opts);
|
|
549
|
+
return {
|
|
550
|
+
ok: true, action: "sanitize",
|
|
551
|
+
sanitized: Buffer.from(clean, "utf8"),
|
|
552
|
+
issues: allIssues,
|
|
553
|
+
};
|
|
554
|
+
} catch (_e) {
|
|
555
|
+
return { ok: false, action: "refuse", issues: allIssues };
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return { ok: true, action: "audit-only", issues: allIssues };
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// ---- adaptive integration-test fixtures (consumed by layer-5 host harness) ----
|
|
563
|
+
var INTEGRATION_FIXTURES = Object.freeze({
|
|
564
|
+
kind: "content",
|
|
565
|
+
contentType: "text/plain",
|
|
566
|
+
extension: ".txt",
|
|
567
|
+
benignBytes: Buffer.from("a perfectly ordinary review of the product", "utf8"),
|
|
568
|
+
// Hostile: a bidi override (U+202E RTLO) embedded mid-string — strict
|
|
569
|
+
// profile refuses; CVE-2021-42574 Trojan Source. Built from a numeric
|
|
570
|
+
// codepoint so this source stays pure ASCII.
|
|
571
|
+
hostileBytes: Buffer.from("ok " + String.fromCharCode(0x202E) + "danger", "utf8"),
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// Assembled from the gate-contract guard factory: error class, registry
|
|
575
|
+
// exports (NAME / KIND / MIME_TYPES / EXTENSIONS / INTEGRATION_FIXTURES),
|
|
576
|
+
// buildProfile / compliancePosture / loadRulePack wiring, plus the per-guard
|
|
577
|
+
// inspection surface (validate / sanitize / gate). The bespoke `gate` carries
|
|
578
|
+
// the text sanitize-then-refuse chain (confusables are non-repairable).
|
|
579
|
+
module.exports = gateContract.defineGuard({
|
|
580
|
+
name: "text",
|
|
581
|
+
kind: "content",
|
|
582
|
+
errorClass: GuardTextError,
|
|
583
|
+
profiles: PROFILES,
|
|
584
|
+
defaults: DEFAULTS,
|
|
585
|
+
postures: COMPLIANCE_POSTURES,
|
|
586
|
+
mimeTypes: ["text/plain"],
|
|
587
|
+
extensions: [".txt"],
|
|
588
|
+
integrationFixtures: INTEGRATION_FIXTURES,
|
|
589
|
+
validate: validate,
|
|
590
|
+
sanitize: sanitize,
|
|
591
|
+
gate: gate,
|
|
592
|
+
});
|