@blamejs/blamejs-shop 0.4.55 → 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 +4 -0
- package/lib/admin.js +385 -2
- 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/lib/winback-campaigns.js +202 -42
- package/package.json +1 -1
|
@@ -46,7 +46,10 @@ var zlib = require("node:zlib");
|
|
|
46
46
|
var net = require("node:net");
|
|
47
47
|
var nodeCrypto = require("node:crypto");
|
|
48
48
|
var lazyRequire = require("./lazy-require");
|
|
49
|
+
var safeBuffer = require("./safe-buffer");
|
|
49
50
|
var validateOpts = require("./validate-opts");
|
|
51
|
+
var structuredFields = require("./structured-fields");
|
|
52
|
+
var markupEscape = require("./markup-escape").markupEscape;
|
|
50
53
|
var bCrypto = require("./crypto");
|
|
51
54
|
var C = require("./constants");
|
|
52
55
|
var dkim = require("./mail-dkim");
|
|
@@ -109,22 +112,11 @@ function _getDefaultResolver() {
|
|
|
109
112
|
return _defaultResolver;
|
|
110
113
|
}
|
|
111
114
|
|
|
115
|
+
// TXT resolution reuses the shared reshape in networkDnsResolver.resolveTxt,
|
|
116
|
+
// passing this module's own resolver so TXT shares the resolver (and cache)
|
|
117
|
+
// used for A / MX / PTR below.
|
|
112
118
|
async function _safeResolveTxt(qname, operatorLookup) {
|
|
113
|
-
|
|
114
|
-
var r = await _getDefaultResolver().queryTxt(qname);
|
|
115
|
-
var out = [];
|
|
116
|
-
for (var i = 0; i < r.rrs.length; i += 1) {
|
|
117
|
-
var rr = r.rrs[i];
|
|
118
|
-
if (rr && rr.type === 16) { // IANA DNS qtype TXT
|
|
119
|
-
out.push(Array.isArray(rr.decoded) ? rr.decoded : [String(rr.decoded)]);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (out.length === 0) {
|
|
123
|
-
var err = new Error("no TXT records for " + qname);
|
|
124
|
-
err.code = "ENODATA";
|
|
125
|
-
throw err;
|
|
126
|
-
}
|
|
127
|
-
return out;
|
|
119
|
+
return networkDnsResolver().resolveTxt(qname, operatorLookup, _getDefaultResolver());
|
|
128
120
|
}
|
|
129
121
|
|
|
130
122
|
async function _safeResolveA(qname, family /* 4|6 */, operatorLookup) {
|
|
@@ -1082,15 +1074,11 @@ async function _spfEvaluateDomain(domain, ip, dnsLookup, lookups, ctx) {
|
|
|
1082
1074
|
|
|
1083
1075
|
async function _fetchDmarcRecord(domain, dnsLookup) {
|
|
1084
1076
|
var qname = "_dmarc." + domain.toLowerCase();
|
|
1085
|
-
var records
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
throw new MailAuthError("mail-auth/dmarc-lookup-failed",
|
|
1091
|
-
"DMARC TXT lookup for " + qname + " failed: " +
|
|
1092
|
-
((e && e.message) || String(e)));
|
|
1093
|
-
}
|
|
1077
|
+
var records = await networkDnsResolver().safeResolveTxt(qname, {
|
|
1078
|
+
dnsLookup: dnsLookup,
|
|
1079
|
+
errorFactory: function (code, msg) { return new MailAuthError(code, msg); },
|
|
1080
|
+
code: "mail-auth/dmarc-lookup-failed",
|
|
1081
|
+
});
|
|
1094
1082
|
if (!Array.isArray(records)) return null;
|
|
1095
1083
|
var matches = [];
|
|
1096
1084
|
for (var i = 0; i < records.length; i += 1) {
|
|
@@ -1120,14 +1108,12 @@ var DMARCBIS_VALID_PSD = { y: 1, n: 1, u: 1 };
|
|
|
1120
1108
|
function _parseDmarcRecord(text) {
|
|
1121
1109
|
var policy = { v: null, p: null, sp: null, np: null, psd: null,
|
|
1122
1110
|
pct: 100, adkim: "r", aspf: "r" }; // RFC 7489 default pct
|
|
1123
|
-
|
|
1111
|
+
// RFC 7489 §6.4 DMARC tag-list grammar: `tag-spec *( ";" tag-spec )`,
|
|
1112
|
+
// tag-value carries NO quoted-string — the naive split is correct.
|
|
1113
|
+
var pairs = structuredFields.parseTagList(text);
|
|
1124
1114
|
for (var i = 0; i < pairs.length; i += 1) {
|
|
1125
|
-
var
|
|
1126
|
-
|
|
1127
|
-
var eq = kv.indexOf("=");
|
|
1128
|
-
if (eq === -1) continue;
|
|
1129
|
-
var key = kv.slice(0, eq).trim().toLowerCase();
|
|
1130
|
-
var val = kv.slice(eq + 1).trim();
|
|
1115
|
+
var key = pairs[i][0];
|
|
1116
|
+
var val = pairs[i][1];
|
|
1131
1117
|
if (key === "v") policy.v = val;
|
|
1132
1118
|
else if (key === "p") policy.p = val.toLowerCase();
|
|
1133
1119
|
else if (key === "sp") policy.sp = val.toLowerCase();
|
|
@@ -1417,10 +1403,10 @@ async function arcVerify(rfc822, opts) {
|
|
|
1417
1403
|
var orderTrail = []; // [{ inst, name, idx }]
|
|
1418
1404
|
for (var i = 0; i < headers.length; i += 1) {
|
|
1419
1405
|
var line = headers[i];
|
|
1420
|
-
var
|
|
1421
|
-
if (
|
|
1422
|
-
var name =
|
|
1423
|
-
var value =
|
|
1406
|
+
var khv = structuredFields.parseKeyValuePiece(line, ":");
|
|
1407
|
+
if (khv.value === null) continue;
|
|
1408
|
+
var name = khv.key;
|
|
1409
|
+
var value = khv.value.trim();
|
|
1424
1410
|
if (name !== "arc-seal" && name !== "arc-message-signature" &&
|
|
1425
1411
|
name !== "arc-authentication-results") continue;
|
|
1426
1412
|
// ARC hop instance per RFC 8617 §4.2.1 — bounded to 3 digits; the
|
|
@@ -1734,9 +1720,9 @@ async function _verifyAmsViaDkim(rfc822, hop, sigValue, tags, dkim, dnsLookup) {
|
|
|
1734
1720
|
var rebuilt = [];
|
|
1735
1721
|
for (var i = 0; i < headerLines.length; i += 1) {
|
|
1736
1722
|
var line = headerLines[i];
|
|
1737
|
-
var
|
|
1738
|
-
if (
|
|
1739
|
-
var name =
|
|
1723
|
+
var khv = structuredFields.parseKeyValuePiece(line, ":");
|
|
1724
|
+
if (khv.value === null) { rebuilt.push(line); continue; }
|
|
1725
|
+
var name = khv.key;
|
|
1740
1726
|
if (name === "arc-message-signature" ||
|
|
1741
1727
|
name === "arc-seal" ||
|
|
1742
1728
|
name === "dkim-signature") {
|
|
@@ -1747,7 +1733,7 @@ async function _verifyAmsViaDkim(rfc822, hop, sigValue, tags, dkim, dnsLookup) {
|
|
|
1747
1733
|
// canonicalizes it via h=). Pre-v0.8.17 stripped every AAR
|
|
1748
1734
|
// unconditionally, breaking verification on chains that
|
|
1749
1735
|
// included AAR in h= (Microsoft + Google interop).
|
|
1750
|
-
var instMatch = /\bi\s*=\s*(\d+)/.exec(
|
|
1736
|
+
var instMatch = /\bi\s*=\s*(\d+)/.exec(khv.value);
|
|
1751
1737
|
if (!instMatch || parseInt(instMatch[1], 10) !== hop.instance) continue;
|
|
1752
1738
|
}
|
|
1753
1739
|
rebuilt.push(line);
|
|
@@ -1763,16 +1749,11 @@ async function _verifyAmsViaDkim(rfc822, hop, sigValue, tags, dkim, dnsLookup) {
|
|
|
1763
1749
|
}
|
|
1764
1750
|
|
|
1765
1751
|
function _parseArcTagList(value) {
|
|
1752
|
+
// RFC 8617 §4 ARC tag-list grammar (same as DKIM's): `tag-spec *( ";"
|
|
1753
|
+
// tag-spec )`, tag-value contains no DQUOTE, FWS inside a value ignored.
|
|
1754
|
+
var pairs = structuredFields.parseTagList(value, { stripValueWs: true });
|
|
1766
1755
|
var tags = {};
|
|
1767
|
-
var
|
|
1768
|
-
|
|
1769
|
-
for (var i = 0; i < parts.length; i += 1) {
|
|
1770
|
-
var p = parts[i].trim();
|
|
1771
|
-
if (p.length === 0) continue;
|
|
1772
|
-
var eq = p.indexOf("=");
|
|
1773
|
-
if (eq === -1) continue;
|
|
1774
|
-
tags[p.slice(0, eq).trim().toLowerCase()] = p.slice(eq + 1).trim().replace(/\s+/g, "");
|
|
1775
|
-
}
|
|
1756
|
+
for (var i = 0; i < pairs.length; i += 1) tags[pairs[i][0]] = pairs[i][1];
|
|
1776
1757
|
return tags;
|
|
1777
1758
|
}
|
|
1778
1759
|
|
|
@@ -1791,11 +1772,9 @@ function _parseDkimKeyRecord(records) {
|
|
|
1791
1772
|
}
|
|
1792
1773
|
|
|
1793
1774
|
function _canonRelaxedHeader(name, value) {
|
|
1794
|
-
// RFC 6376 §3.4.2
|
|
1795
|
-
//
|
|
1796
|
-
|
|
1797
|
-
var trimmed = unfolded.replace(/[ \t]+/g, " ").replace(/^[ \t]+|[ \t]+$/g, "");
|
|
1798
|
-
return name.toLowerCase() + ":" + trimmed + "\r\n";
|
|
1775
|
+
// RFC 6376 §3.4.2 relaxed header canon — shared with the DKIM signer/verifier
|
|
1776
|
+
// so the DMARC/ARC paths reach a byte-identical canon (RFC 8617 §5.1.1).
|
|
1777
|
+
return dkim.canonHeaderRelaxed(name, value);
|
|
1799
1778
|
}
|
|
1800
1779
|
|
|
1801
1780
|
function _pemFromB64KeyMaterial(b64) {
|
|
@@ -1897,10 +1876,10 @@ async function arcEvaluate(rfc822, opts) {
|
|
|
1897
1876
|
var hopAr = {};
|
|
1898
1877
|
for (var hi = 0; hi < headers.length; hi += 1) {
|
|
1899
1878
|
var line = headers[hi];
|
|
1900
|
-
var
|
|
1901
|
-
if (
|
|
1902
|
-
var name =
|
|
1903
|
-
var value =
|
|
1879
|
+
var khv = structuredFields.parseKeyValuePiece(line, ":");
|
|
1880
|
+
if (khv.value === null) continue;
|
|
1881
|
+
var name = khv.key;
|
|
1882
|
+
var value = khv.value.trim();
|
|
1904
1883
|
if (name === "arc-seal") {
|
|
1905
1884
|
var iMatch = value.match(/(?:^|[;,\s])i=(\d+)/); // allow:regex-no-length-cap — header bounded by RFC 5322 998
|
|
1906
1885
|
var dMatch = value.match(/(?:^|[;,\s])d=([^\s;]+)/); // allow:regex-no-length-cap — header bounded by RFC 5322 998
|
|
@@ -2167,7 +2146,7 @@ function _countFromAuthors(value) {
|
|
|
2167
2146
|
// (RFC 7489 §6.6.1 — a multi-author From is the header-duplication
|
|
2168
2147
|
// spoofing shape and must not have "one" author picked from it).
|
|
2169
2148
|
function _extractFromHeaders(headerBlock) {
|
|
2170
|
-
var unfolded =
|
|
2149
|
+
var unfolded = structuredFields.unfoldHeaderContinuations(headerBlock);
|
|
2171
2150
|
var lines = unfolded.split(/\r?\n/);
|
|
2172
2151
|
var fromValues = [];
|
|
2173
2152
|
for (var i = 0; i < lines.length; i += 1) {
|
|
@@ -2552,12 +2531,7 @@ function _shapeAggregateReport(parsed) {
|
|
|
2552
2531
|
// before they reach here, but escaping is applied uniformly so a future
|
|
2553
2532
|
// caller can't bypass it.
|
|
2554
2533
|
function _xmlEscapeText(value) {
|
|
2555
|
-
return
|
|
2556
|
-
.replace(/&/g, "&")
|
|
2557
|
-
.replace(/</g, "<")
|
|
2558
|
-
.replace(/>/g, ">")
|
|
2559
|
-
.replace(/"/g, """)
|
|
2560
|
-
.replace(/'/g, "'");
|
|
2534
|
+
return markupEscape(value, { apos: "'" });
|
|
2561
2535
|
}
|
|
2562
2536
|
|
|
2563
2537
|
// Emit `<tag>escaped-text</tag>` when value is non-null/defined; emit
|
|
@@ -2984,9 +2958,9 @@ function dmarcParseForensicReport(input, opts) {
|
|
|
2984
2958
|
var maxBytes = (typeof opts.maxBytes === "number" && isFinite(opts.maxBytes) && opts.maxBytes > 0)
|
|
2985
2959
|
? opts.maxBytes
|
|
2986
2960
|
: DMARC_RUF_MAX_REPORT_BYTES;
|
|
2987
|
-
if (asString
|
|
2961
|
+
if (safeBuffer.byteLengthOf(asString) > maxBytes) {
|
|
2988
2962
|
return _rufError("mail-auth/dmarc-ruf-too-large",
|
|
2989
|
-
"dmarc.parseForensicReport: report exceeds " + maxBytes + " bytes (got " + asString
|
|
2963
|
+
"dmarc.parseForensicReport: report exceeds " + maxBytes + " bytes (got " + safeBuffer.byteLengthOf(asString) + ")");
|
|
2990
2964
|
}
|
|
2991
2965
|
|
|
2992
2966
|
// ---- Bisect top-level headers / body; require multipart/report ----
|
|
@@ -48,15 +48,16 @@
|
|
|
48
48
|
* RFC 9091 BIMI policy lookup, VMC + CMC fetch + chain validation, and Tiny-PS SVG profile enforcement for inbox brand-mark rendering.
|
|
49
49
|
*/
|
|
50
50
|
|
|
51
|
-
var dns = require("node:dns");
|
|
52
51
|
var nodeCrypto = require("node:crypto");
|
|
53
|
-
var dnsPromises = dns.promises;
|
|
54
52
|
|
|
55
53
|
var asn1 = require("./asn1-der");
|
|
56
54
|
var C = require("./constants");
|
|
57
55
|
var httpClient = require("./http-client");
|
|
58
56
|
var lazyRequire = require("./lazy-require");
|
|
57
|
+
var networkDnsResolver = lazyRequire(function () { return require("./network-dns-resolver"); });
|
|
59
58
|
var safeBuffer = require("./safe-buffer");
|
|
59
|
+
var markupTokenizer = require("./markup-tokenizer");
|
|
60
|
+
var structuredFields = require("./structured-fields");
|
|
60
61
|
var safeUrl = require("./safe-url");
|
|
61
62
|
var validateOpts = require("./validate-opts");
|
|
62
63
|
var { defineClass, MailBimiError } = require("./framework-error");
|
|
@@ -211,17 +212,12 @@ function recordShape(opts) {
|
|
|
211
212
|
function parseRecord(text) {
|
|
212
213
|
if (typeof text !== "string" || text.length === 0) return null;
|
|
213
214
|
if (text.length > BIMI_RECORD_MAX_BYTES) return null;
|
|
214
|
-
// RFC 9091 4
|
|
215
|
-
var
|
|
215
|
+
// RFC 9091 §4 — semicolon-separated key=value (no DQUOTE), leading "v=BIMI1".
|
|
216
|
+
var pairs = structuredFields.parseTagList(text);
|
|
216
217
|
var rv = { v: null, l: null, a: null };
|
|
217
|
-
for (var i = 0; i <
|
|
218
|
-
var
|
|
219
|
-
if (
|
|
220
|
-
var eq = p.indexOf("=");
|
|
221
|
-
if (eq === -1) continue;
|
|
222
|
-
var k = p.slice(0, eq).trim().toLowerCase();
|
|
223
|
-
var v = p.slice(eq + 1).trim();
|
|
224
|
-
if (k === "v" || k === "l" || k === "a") rv[k] = v;
|
|
218
|
+
for (var i = 0; i < pairs.length; i += 1) {
|
|
219
|
+
var k = pairs[i][0];
|
|
220
|
+
if (k === "v" || k === "l" || k === "a") rv[k] = pairs[i][1];
|
|
225
221
|
}
|
|
226
222
|
if (rv.v !== BIMI_VERSION || !rv.l) return null;
|
|
227
223
|
return rv;
|
|
@@ -264,16 +260,13 @@ async function fetchPolicy(domain, opts) {
|
|
|
264
260
|
opts = opts || {};
|
|
265
261
|
var selector = opts.selector || BIMI_DEFAULT_SELECTOR;
|
|
266
262
|
var qname = selector + "._bimi." + domain;
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
"bimi.fetchPolicy: TXT lookup for " + qname + " failed: " +
|
|
275
|
-
((e && e.message) || String(e)));
|
|
276
|
-
}
|
|
263
|
+
// Secure DNS path (DoH/DNSSEC via the framework resolver) — not plaintext
|
|
264
|
+
// dnsPromises, which a spoofed BIMI TXT could exploit to mislead VMC discovery.
|
|
265
|
+
var records = await networkDnsResolver().safeResolveTxt(qname, {
|
|
266
|
+
dnsLookup: opts.dnsLookup,
|
|
267
|
+
errorFactory: function (code, msg) { return new BimiError(code, msg); },
|
|
268
|
+
code: "mail-bimi/lookup-failed",
|
|
269
|
+
});
|
|
277
270
|
// RFC 9091 4.1 - a TXT lookup may return multiple chunks; pick
|
|
278
271
|
// the first record that begins with v=BIMI1.
|
|
279
272
|
for (var i = 0; i < (records || []).length; i += 1) {
|
|
@@ -542,32 +535,19 @@ function _tokenizeTinyPsSvg(s) {
|
|
|
542
535
|
continue;
|
|
543
536
|
}
|
|
544
537
|
|
|
545
|
-
var pp = lt + 1;
|
|
546
|
-
var inQuote = "";
|
|
547
|
-
while (pp < len) {
|
|
548
|
-
var ch = s.charAt(pp);
|
|
549
|
-
if (inQuote) {
|
|
550
|
-
if (ch === inQuote) inQuote = "";
|
|
551
|
-
} else {
|
|
552
|
-
if (ch === '"' || ch === "'") inQuote = ch;
|
|
553
|
-
else if (ch === ">") break;
|
|
554
|
-
}
|
|
555
|
-
pp += 1;
|
|
556
|
-
}
|
|
538
|
+
var pp = markupTokenizer.scanToTagEnd(s, lt + 1, len);
|
|
557
539
|
if (pp >= len) throw new Error("unterminated start tag"); // allow:bare-error-throw — caught by outer try/catch and re-thrown as MailBimiError("bimi/svg-tiny-ps-violation")
|
|
558
540
|
var raw = s.slice(lt, pp + 1);
|
|
559
541
|
var inner = raw.slice(1, raw.length - 1);
|
|
560
542
|
var selfClosing = inner.endsWith("/");
|
|
561
543
|
if (selfClosing) inner = inner.slice(0, inner.length - 1);
|
|
562
544
|
|
|
563
|
-
var
|
|
564
|
-
var tagName = nameMatch ? nameMatch[1].toLowerCase() : "";
|
|
565
|
-
var attrSrc = nameMatch ? inner.slice(nameMatch[0].length) : "";
|
|
545
|
+
var bimiParts = markupTokenizer.splitTagNameAttrs(inner, /^([A-Za-z][A-Za-z0-9:_-]*)/);
|
|
566
546
|
|
|
567
547
|
tokens.push({
|
|
568
548
|
type: "tag",
|
|
569
|
-
name: tagName,
|
|
570
|
-
attrs: _parseTinyPsAttrs(attrSrc),
|
|
549
|
+
name: bimiParts.tagName,
|
|
550
|
+
attrs: _parseTinyPsAttrs(bimiParts.attrSrc),
|
|
571
551
|
raw: raw,
|
|
572
552
|
selfClosing: selfClosing,
|
|
573
553
|
});
|
|
@@ -113,6 +113,7 @@
|
|
|
113
113
|
* band fingerprint pinning is the operator's responsibility)
|
|
114
114
|
*/
|
|
115
115
|
var lazyRequire = require("./lazy-require");
|
|
116
|
+
var safeBuffer = require("./safe-buffer");
|
|
116
117
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
117
118
|
var nodeCrypto = require("node:crypto");
|
|
118
119
|
var validateOpts = require("./validate-opts");
|
|
@@ -1168,7 +1169,7 @@ function wkdFetch(email, opts) {
|
|
|
1168
1169
|
var urls = wkdComputeUrl(email, { advancedHost: opts.advancedHost });
|
|
1169
1170
|
return Promise.resolve(opts.httpsGet(urls.direct)).then(function (resp) {
|
|
1170
1171
|
if (resp && resp.status === 200 && Buffer.isBuffer(resp.body) && resp.body.length > 0) { // HTTP 200
|
|
1171
|
-
if (resp.body
|
|
1172
|
+
if (safeBuffer.byteLengthOf(resp.body) > maxBytes) {
|
|
1172
1173
|
throw new MailCryptoError("mail-crypto/pgp/wkd-too-large",
|
|
1173
1174
|
"wkd.fetch: key bytes " + resp.body.length + " exceed maxKeyBytes=" + maxBytes);
|
|
1174
1175
|
}
|
|
@@ -1176,7 +1177,7 @@ function wkdFetch(email, opts) {
|
|
|
1176
1177
|
}
|
|
1177
1178
|
return Promise.resolve(opts.httpsGet(urls.advanced)).then(function (resp2) {
|
|
1178
1179
|
if (resp2 && resp2.status === 200 && Buffer.isBuffer(resp2.body) && resp2.body.length > 0) { // HTTP 200
|
|
1179
|
-
if (resp2.body
|
|
1180
|
+
if (safeBuffer.byteLengthOf(resp2.body) > maxBytes) {
|
|
1180
1181
|
throw new MailCryptoError("mail-crypto/pgp/wkd-too-large",
|
|
1181
1182
|
"wkd.fetch: key bytes " + resp2.body.length + " exceed maxKeyBytes=" + maxBytes);
|
|
1182
1183
|
}
|
|
@@ -129,8 +129,8 @@
|
|
|
129
129
|
* backend. Defends the RRULE-recursion expansion-DoS class at the PUT boundary.
|
|
130
130
|
*/
|
|
131
131
|
|
|
132
|
-
var lazyRequire = require("./lazy-require");
|
|
133
132
|
var C = require("./constants");
|
|
133
|
+
var markupEscape = require("./markup-escape").markupEscape;
|
|
134
134
|
var safeIcal = require("./safe-ical");
|
|
135
135
|
var safeVcard = require("./safe-vcard");
|
|
136
136
|
var safeBuffer = require("./safe-buffer");
|
|
@@ -138,7 +138,7 @@ var validateOpts = require("./validate-opts");
|
|
|
138
138
|
var xmlC14n = require("./xml-c14n");
|
|
139
139
|
var { defineClass } = require("./framework-error");
|
|
140
140
|
|
|
141
|
-
var
|
|
141
|
+
var auditEmit = require("./audit-emit");
|
|
142
142
|
|
|
143
143
|
var MailDavError = defineClass("MailDavError", { alwaysPermanent: true });
|
|
144
144
|
|
|
@@ -221,15 +221,7 @@ function create(opts) {
|
|
|
221
221
|
var calStorage = opts.storage.calendar || null;
|
|
222
222
|
var cardStorage = opts.storage.addressbook || null;
|
|
223
223
|
|
|
224
|
-
|
|
225
|
-
try {
|
|
226
|
-
audit().safeEmit({
|
|
227
|
-
action: action,
|
|
228
|
-
outcome: outcome || "success",
|
|
229
|
-
metadata: metadata || {},
|
|
230
|
-
});
|
|
231
|
-
} catch (_e) { /* drop-silent — audit best-effort */ }
|
|
232
|
-
}
|
|
224
|
+
var _emit = auditEmit.emit;
|
|
233
225
|
|
|
234
226
|
// ---- URL parsing (per-tenant principal isolation) ----------------------
|
|
235
227
|
//
|
|
@@ -299,28 +291,14 @@ function create(opts) {
|
|
|
299
291
|
resolve(Buffer.from(JSON.stringify(req.body), "utf8"));
|
|
300
292
|
return;
|
|
301
293
|
}
|
|
302
|
-
//
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
// single allocation in result() is bounded by maxBytes.
|
|
306
|
-
var collector = safeBuffer.boundedChunkCollector({
|
|
294
|
+
// collectStream's boundedChunkCollector enforces maxBytes inside push()
|
|
295
|
+
// (overflow throws → reject) and destroys the stream on cap/error.
|
|
296
|
+
safeBuffer.collectStream(req, {
|
|
307
297
|
maxBytes: maxBody,
|
|
308
298
|
errorClass: MailDavError,
|
|
309
299
|
sizeCode: "mail-dav/oversize-body",
|
|
310
300
|
sizeMessage: "request body exceeds " + maxBody + " bytes",
|
|
311
|
-
});
|
|
312
|
-
req.on("data", function (chunk) {
|
|
313
|
-
try { collector.push(chunk); }
|
|
314
|
-
catch (e) {
|
|
315
|
-
req.destroy();
|
|
316
|
-
reject(e);
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
req.on("end", function () {
|
|
320
|
-
try { resolve(collector.result()); }
|
|
321
|
-
catch (e) { reject(e); }
|
|
322
|
-
});
|
|
323
|
-
req.on("error", function (e) { reject(e); });
|
|
301
|
+
}).then(resolve, reject);
|
|
324
302
|
});
|
|
325
303
|
}
|
|
326
304
|
|
|
@@ -370,12 +348,7 @@ function create(opts) {
|
|
|
370
348
|
|
|
371
349
|
function _xmlEscape(s) {
|
|
372
350
|
if (s === null || s === undefined) return "";
|
|
373
|
-
return
|
|
374
|
-
.replace(/&/g, "&")
|
|
375
|
-
.replace(/</g, "<")
|
|
376
|
-
.replace(/>/g, ">")
|
|
377
|
-
.replace(/"/g, """)
|
|
378
|
-
.replace(/'/g, "'");
|
|
351
|
+
return markupEscape(s, { apos: "'" });
|
|
379
352
|
}
|
|
380
353
|
|
|
381
354
|
// Render a small subset of well-known DAV / CalDAV / CardDAV
|
|
@@ -51,8 +51,10 @@ var lazyRequire = require("./lazy-require");
|
|
|
51
51
|
var validateOpts = require("./validate-opts");
|
|
52
52
|
var numericBounds = require("./numeric-bounds");
|
|
53
53
|
var C = require("./constants");
|
|
54
|
+
var markupEscape = require("./markup-escape").markupEscape;
|
|
54
55
|
var safeJson = require("./safe-json");
|
|
55
56
|
var safeBuffer = require("./safe-buffer");
|
|
57
|
+
var codepointClass = require("./codepoint-class");
|
|
56
58
|
var guardJson = lazyRequire(function () { return require("./guard-json"); });
|
|
57
59
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
58
60
|
var { defineClass } = require("./framework-error");
|
|
@@ -73,18 +75,13 @@ function _domainOk(d) {
|
|
|
73
75
|
// header-injection class + XML-attribute-injection class.
|
|
74
76
|
for (var i = 0; i < d.length; i++) {
|
|
75
77
|
var c = d.charCodeAt(i);
|
|
76
|
-
if (c
|
|
78
|
+
if (codepointClass.isForbiddenControlChar(c, { forbidTab: true }) || c === 0x22) return false; // refuse C0 / DEL / "
|
|
77
79
|
}
|
|
78
80
|
return true;
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
function _xmlEscape(s) {
|
|
82
|
-
return
|
|
83
|
-
.replace(/&/g, "&")
|
|
84
|
-
.replace(/</g, "<")
|
|
85
|
-
.replace(/>/g, ">")
|
|
86
|
-
.replace(/"/g, """)
|
|
87
|
-
.replace(/'/g, "'");
|
|
84
|
+
return markupEscape(s, { apos: "'" });
|
|
88
85
|
}
|
|
89
86
|
|
|
90
87
|
/**
|
|
@@ -375,7 +372,7 @@ function autoConfigXml(opts) {
|
|
|
375
372
|
// Refuse control bytes / quote in the URL.
|
|
376
373
|
for (var k = 0; k < cfg.url.length; k++) {
|
|
377
374
|
var c = cfg.url.charCodeAt(k);
|
|
378
|
-
if (c
|
|
375
|
+
if (codepointClass.isForbiddenControlChar(c, { forbidTab: true }) || c === 0x22) { // C0 / DEL / "
|
|
379
376
|
throw new MailDeployError("mail-deploy/bad-jmap-url",
|
|
380
377
|
"autoConfigXml: opts.jmap.url contains control byte");
|
|
381
378
|
}
|
|
@@ -444,7 +441,7 @@ function autoDiscoverXml(opts) {
|
|
|
444
441
|
// Refuse CR / LF / NUL / control bytes in email (XML injection class).
|
|
445
442
|
for (var i = 0; i < opts.email.length; i++) {
|
|
446
443
|
var c = opts.email.charCodeAt(i);
|
|
447
|
-
if (c
|
|
444
|
+
if (codepointClass.isForbiddenControlChar(c, { forbidTab: true })) { // C0 / DEL
|
|
448
445
|
throw new MailDeployError("mail-deploy/bad-email",
|
|
449
446
|
"autoDiscoverXml: opts.email contains control byte");
|
|
450
447
|
}
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
*/
|
|
41
41
|
var lazyRequire = require("./lazy-require");
|
|
42
42
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
43
|
+
var structuredFields = require("./structured-fields");
|
|
43
44
|
var nodeCrypto = require("node:crypto");
|
|
44
45
|
var safeBuffer = require("./safe-buffer");
|
|
45
46
|
var validateOpts = require("./validate-opts");
|
|
@@ -85,7 +86,7 @@ var RSA_LEGACY_MIN_BITS = 1024;
|
|
|
85
86
|
function _canonHeaderRelaxed(name, value) {
|
|
86
87
|
// Lowercase name, unfold continuations, collapse internal WSP runs to
|
|
87
88
|
// single SP, strip leading/trailing WSP from value.
|
|
88
|
-
var unfolded =
|
|
89
|
+
var unfolded = structuredFields.unfoldHeaderContinuations(value);
|
|
89
90
|
var trimmed = unfolded.replace(/[ \t]+/g, " ").replace(/^[ \t]+|[ \t]+$/g, "");
|
|
90
91
|
return name.toLowerCase() + ":" + trimmed + "\r\n";
|
|
91
92
|
}
|
|
@@ -460,26 +461,13 @@ function create(opts) {
|
|
|
460
461
|
// hard dependency on it. When omitted, falls back to node:dns.
|
|
461
462
|
|
|
462
463
|
function _parseDkimTagList(value) {
|
|
463
|
-
// RFC 6376 §3.2 — tags are `key=value` separated by
|
|
464
|
-
// around `=` and `;` is
|
|
465
|
-
// DKIM-Signature
|
|
466
|
-
//
|
|
467
|
-
var
|
|
464
|
+
// RFC 6376 §3.2 — tags are `key=value` separated by `;`, no DQUOTE in
|
|
465
|
+
// the grammar. Whitespace around `=` and `;` is stripped; the signer
|
|
466
|
+
// folds the DKIM-Signature across CRLF + WSP, so unfold first, and FWS
|
|
467
|
+
// inside a tag value is ignored, so strip all value whitespace.
|
|
468
|
+
var pairs = structuredFields.parseTagList(value, { unfold: true, stripValueWs: true });
|
|
468
469
|
var tags = {};
|
|
469
|
-
var
|
|
470
|
-
for (var i = 0; i < parts.length; i += 1) {
|
|
471
|
-
var p = parts[i].trim();
|
|
472
|
-
if (p.length === 0) continue;
|
|
473
|
-
var eq = p.indexOf("=");
|
|
474
|
-
if (eq === -1) continue;
|
|
475
|
-
var key = p.slice(0, eq).trim().toLowerCase();
|
|
476
|
-
var val = p.slice(eq + 1).trim();
|
|
477
|
-
// Whitespace inside values is unfolded — RFC 6376 §3.2 says FWS
|
|
478
|
-
// (folding whitespace) is ignored within a tag value. Strip
|
|
479
|
-
// newlines + tabs while preserving the meaningful tokens.
|
|
480
|
-
val = val.replace(/\s+/g, "");
|
|
481
|
-
tags[key] = val;
|
|
482
|
-
}
|
|
470
|
+
for (var i = 0; i < pairs.length; i += 1) tags[pairs[i][0]] = pairs[i][1];
|
|
483
471
|
return tags;
|
|
484
472
|
}
|
|
485
473
|
|
|
@@ -570,25 +558,10 @@ function _getDefaultResolver() {
|
|
|
570
558
|
return _defaultResolver;
|
|
571
559
|
}
|
|
572
560
|
|
|
561
|
+
// Reshape TXT records off this module's own resolver via the shared
|
|
562
|
+
// networkDnsResolver.resolveTxt (the legacy `[[chunk1, chunk2], ...]` shape).
|
|
573
563
|
async function _safeResolveTxt(qname, operatorLookup) {
|
|
574
|
-
|
|
575
|
-
var r = await _getDefaultResolver().queryTxt(qname);
|
|
576
|
-
// Resolver returns parsed RRs; reshape to the legacy
|
|
577
|
-
// `[[chunk1, chunk2], ...]` shape so callers downstream don't care
|
|
578
|
-
// which path produced the bytes.
|
|
579
|
-
var out = [];
|
|
580
|
-
for (var i = 0; i < r.rrs.length; i += 1) {
|
|
581
|
-
var rr = r.rrs[i];
|
|
582
|
-
if (rr && rr.type === 16) { // IANA DNS qtype TXT
|
|
583
|
-
out.push(Array.isArray(rr.decoded) ? rr.decoded : [String(rr.decoded)]);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
if (out.length === 0) {
|
|
587
|
-
var err = new Error("no TXT records for " + qname);
|
|
588
|
-
err.code = "ENODATA";
|
|
589
|
-
throw err;
|
|
590
|
-
}
|
|
591
|
-
return out;
|
|
564
|
+
return networkDnsResolver().resolveTxt(qname, operatorLookup, _getDefaultResolver());
|
|
592
565
|
}
|
|
593
566
|
|
|
594
567
|
function _resetDkimKeyCacheForTest() { DKIM_KEY_CACHE.clear(); }
|
|
@@ -1244,8 +1217,16 @@ module.exports = {
|
|
|
1244
1217
|
DKIM_MAX_SIGNATURES_PER_MESSAGE: DKIM_MAX_SIGNATURES_PER_MESSAGE,
|
|
1245
1218
|
DKIM_MAX_SIGNATURES_PER_MESSAGE_CEILING: DKIM_MAX_SIGNATURES_PER_MESSAGE_CEILING,
|
|
1246
1219
|
DKIM_CLOCK_SKEW_MS_MAX: DKIM_CLOCK_SKEW_MS_MAX,
|
|
1220
|
+
canonHeaderRelaxed: _canonHeaderRelaxed, // RFC 6376 §3.4.2 — shared by the ARC signer + DMARC/ARC verifier
|
|
1247
1221
|
_canonHeaderRelaxedForTest: _canonHeaderRelaxed,
|
|
1248
1222
|
_canonBodyRelaxedForTest: _canonBodyRelaxed,
|
|
1249
1223
|
_canonBodySimpleForTest: _canonBodySimple,
|
|
1250
1224
|
_stripBTagValueForTest: _stripBTagValue,
|
|
1225
|
+
// The header-block parser that produces the { name, value } pairs fed to the
|
|
1226
|
+
// canonicalizers. Exposed so a golden-vector test can pin its byte-exact
|
|
1227
|
+
// extraction (folding, exact name, leading-SP-preserved value) — the
|
|
1228
|
+
// sign->verify round-trip cannot, since both sides share this parser, so a
|
|
1229
|
+
// parser byte-error is self-consistent and would only surface as a signature
|
|
1230
|
+
// rejection at a real external verifier.
|
|
1231
|
+
_parseHeadersForTest: _parseHeaders,
|
|
1251
1232
|
};
|
|
@@ -103,6 +103,7 @@ var bCrypto = require("./crypto");
|
|
|
103
103
|
var lazyRequire = require("./lazy-require");
|
|
104
104
|
var ipUtils = require("./ip-utils");
|
|
105
105
|
var gateContract = require("./gate-contract");
|
|
106
|
+
var { boundedMap } = require("./bounded-map");
|
|
106
107
|
|
|
107
108
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
108
109
|
|
|
@@ -129,9 +130,6 @@ var PROFILES = Object.freeze({
|
|
|
129
130
|
|
|
130
131
|
var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
|
|
131
132
|
|
|
132
|
-
var IPV4_RE = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/; // allow:regex-no-length-cap — anchored + per-octet repeat-cap
|
|
133
|
-
var IPV6_RE = /^[0-9a-fA-F:]+$/; // allow:regex-no-length-cap — length-checked separately
|
|
134
|
-
|
|
135
133
|
/**
|
|
136
134
|
* @primitive b.mail.greylist.create
|
|
137
135
|
* @signature b.mail.greylist.create(opts?)
|
|
@@ -163,7 +161,7 @@ var IPV6_RE = /^[0-9a-fA-F:]+$/;
|
|
|
163
161
|
*/
|
|
164
162
|
function create(opts) {
|
|
165
163
|
opts = opts || {};
|
|
166
|
-
var profile =
|
|
164
|
+
var profile = gateContract.resolveProfileName(opts, COMPLIANCE_POSTURES, DEFAULT_PROFILE);
|
|
167
165
|
if (!PROFILES[profile]) {
|
|
168
166
|
throw new MailGreylistError("mail-greylist/bad-profile",
|
|
169
167
|
"create: unknown profile '" + profile + "'");
|
|
@@ -341,7 +339,7 @@ function _hashFingerprint(cidr, mailFrom, rcptTo) {
|
|
|
341
339
|
}
|
|
342
340
|
|
|
343
341
|
function _cidrKey(ip, ipv4Prefix, ipv6Prefix) {
|
|
344
|
-
if (
|
|
342
|
+
if (ipUtils.isIPv4(ip)) {
|
|
345
343
|
var octets = ip.split(".").map(function (s) { return parseInt(s, 10); });
|
|
346
344
|
var prefix = Math.min(32, Math.max(0, ipv4Prefix)); // IPv4 address bit width
|
|
347
345
|
// Apply prefix: zero out the host bits.
|
|
@@ -355,7 +353,7 @@ function _cidrKey(ip, ipv4Prefix, ipv6Prefix) {
|
|
|
355
353
|
masked & 0xff,
|
|
356
354
|
].join(".") + "/" + prefix;
|
|
357
355
|
}
|
|
358
|
-
if (
|
|
356
|
+
if (ipUtils.looksLikeIPv6Hex(ip)) {
|
|
359
357
|
// Expand IPv6, then mask. Reuse the expansion approach from
|
|
360
358
|
// mail-rbl by inlining since this is a different prefix shape.
|
|
361
359
|
var expanded = ipUtils.expandIpv6Hex(ip);
|
|
@@ -390,41 +388,32 @@ function _emitAudit(auditImpl, action, metadata) {
|
|
|
390
388
|
}
|
|
391
389
|
|
|
392
390
|
function _memoryStore(maxEntries) {
|
|
393
|
-
|
|
394
|
-
|
|
391
|
+
// The in-memory backend is exactly the bounded-map ceiling primitive: cap
|
|
392
|
+
// the entry count and drop the oldest on insert at capacity. boundedMap owns
|
|
393
|
+
// the insertion-order tracking and eviction; this store layers greylist TTL
|
|
394
|
+
// semantics (putAt/ttlMs) on top.
|
|
395
|
+
var data = boundedMap({ maxEntries: maxEntries, policy: "evict-oldest" });
|
|
395
396
|
return {
|
|
396
397
|
get: async function (key) {
|
|
397
398
|
var entry = data.get(key);
|
|
398
399
|
return entry ? entry.value : null;
|
|
399
400
|
},
|
|
400
401
|
put: async function (key, value, ttlMs) {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
// Evict oldest.
|
|
404
|
-
var oldest = insertionOrder.shift();
|
|
405
|
-
if (oldest) data.delete(oldest);
|
|
406
|
-
}
|
|
407
|
-
insertionOrder.push(key);
|
|
408
|
-
}
|
|
402
|
+
// boundedMap evicts the oldest entry when a NEW key arrives at capacity;
|
|
403
|
+
// updating an existing key neither grows the map nor evicts.
|
|
409
404
|
data.set(key, { value: value, putAt: Date.now(), ttlMs: ttlMs });
|
|
410
405
|
},
|
|
411
406
|
delete: async function (key) {
|
|
412
407
|
data.delete(key);
|
|
413
|
-
var i = insertionOrder.indexOf(key);
|
|
414
|
-
if (i !== -1) insertionOrder.splice(i, 1);
|
|
415
408
|
},
|
|
416
409
|
gc: async function (olderThanMs) {
|
|
417
410
|
var now = Date.now();
|
|
418
|
-
var
|
|
411
|
+
var expired = [];
|
|
419
412
|
data.forEach(function (entry, key) {
|
|
420
|
-
if (now - entry.putAt > olderThanMs)
|
|
421
|
-
data.delete(key);
|
|
422
|
-
var i = insertionOrder.indexOf(key);
|
|
423
|
-
if (i !== -1) insertionOrder.splice(i, 1);
|
|
424
|
-
removed += 1;
|
|
425
|
-
}
|
|
413
|
+
if (now - entry.putAt > olderThanMs) expired.push(key);
|
|
426
414
|
});
|
|
427
|
-
|
|
415
|
+
expired.forEach(function (key) { data.delete(key); });
|
|
416
|
+
return expired.length;
|
|
428
417
|
},
|
|
429
418
|
};
|
|
430
419
|
}
|