@blamejs/core 0.15.12 → 0.15.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/index.js +2 -0
- package/lib/a2a-tasks.js +45 -29
- package/lib/acme.js +6 -5
- package/lib/agent-event-bus.js +18 -4
- package/lib/agent-idempotency.js +7 -6
- package/lib/agent-orchestrator.js +2 -5
- package/lib/agent-saga.js +3 -5
- package/lib/agent-snapshot.js +32 -2
- package/lib/agent-tenant.js +2 -5
- package/lib/ai-adverse-decision.js +2 -15
- package/lib/ai-aedt-bias-audit.js +2 -1
- package/lib/ai-capability.js +1 -6
- package/lib/ai-content-detect.js +1 -3
- package/lib/ai-dp.js +1 -5
- package/lib/ai-frontier-protocol.js +1 -1
- package/lib/ai-input.js +2 -2
- package/lib/ai-model-manifest.js +1 -1
- package/lib/ai-output.js +16 -7
- package/lib/ai-pref.js +3 -8
- package/lib/ai-quota.js +3 -14
- package/lib/api-key.js +37 -28
- package/lib/api-snapshot.js +4 -1
- package/lib/app-shutdown.js +7 -1
- package/lib/archive-adapters.js +2 -4
- package/lib/archive-entry-policy.js +32 -0
- package/lib/archive-gz.js +9 -0
- package/lib/archive-read.js +14 -24
- package/lib/archive-tar-read.js +56 -24
- package/lib/archive.js +6 -12
- package/lib/arg-parser.js +7 -6
- package/lib/asn1-der.js +70 -22
- package/lib/asyncapi-traits.js +2 -6
- package/lib/atomic-file.js +312 -33
- package/lib/audit-chain.js +183 -54
- package/lib/audit-daily-review.js +36 -16
- package/lib/audit-emit.js +82 -0
- package/lib/audit-sign.js +258 -0
- package/lib/audit-tools.js +108 -23
- package/lib/audit.js +91 -2
- package/lib/auth/access-lock.js +7 -29
- package/lib/auth/bot-challenge.js +1 -1
- package/lib/auth/ciba.js +43 -4
- package/lib/auth/dpop.js +29 -36
- package/lib/auth/fido-mds3.js +14 -16
- package/lib/auth/jwt-external.js +26 -8
- package/lib/auth/jwt.js +15 -17
- package/lib/auth/lockout.js +24 -27
- package/lib/auth/oauth.js +67 -45
- package/lib/auth/oid4vci.js +55 -32
- package/lib/auth/oid4vp.js +3 -2
- package/lib/auth/openid-federation.js +6 -6
- package/lib/auth/passkey.js +4 -4
- package/lib/auth/password.js +8 -2
- package/lib/auth/saml.js +70 -40
- package/lib/auth/sd-jwt-vc-holder.js +2 -14
- package/lib/auth/sd-jwt-vc-issuer.js +2 -14
- package/lib/auth/sd-jwt-vc.js +25 -5
- package/lib/auth/status-list.js +21 -9
- package/lib/auth/step-up.js +15 -13
- package/lib/auth-bot-challenge.js +27 -39
- package/lib/backup/bundle.js +18 -20
- package/lib/backup/crypto.js +23 -8
- package/lib/backup/index.js +55 -67
- package/lib/backup/manifest.js +7 -1
- package/lib/bounded-map.js +112 -1
- package/lib/breach-deadline.js +1 -11
- package/lib/break-glass.js +41 -22
- package/lib/cache.js +7 -18
- package/lib/cbor.js +36 -12
- package/lib/cdn-cache-control.js +15 -12
- package/lib/cert.js +8 -13
- package/lib/chain-writer.js +162 -47
- package/lib/cli.js +10 -2
- package/lib/client-hints.js +7 -9
- package/lib/cloud-events.js +43 -33
- package/lib/cluster-storage.js +9 -41
- package/lib/cms-codec.js +2 -1
- package/lib/codepoint-class.js +84 -1
- package/lib/compliance-ai-act-logging.js +1 -6
- package/lib/compliance-ai-act-transparency.js +2 -4
- package/lib/compliance-eaa.js +2 -12
- package/lib/compliance-sanctions-fetcher.js +21 -28
- package/lib/compliance-sanctions.js +11 -21
- package/lib/compliance.js +3 -10
- package/lib/config-drift.js +24 -20
- package/lib/content-credentials.js +11 -8
- package/lib/content-digest.js +21 -12
- package/lib/cookies.js +15 -13
- package/lib/cose.js +39 -11
- package/lib/cra-report.js +1 -11
- package/lib/crdt.js +2 -1
- package/lib/crypto-field.js +34 -33
- package/lib/crypto.js +138 -7
- package/lib/csp.js +239 -3
- package/lib/daemon.js +46 -42
- package/lib/data-act.js +46 -13
- package/lib/db-file-lifecycle.js +14 -6
- package/lib/db-query.js +75 -49
- package/lib/db.js +66 -27
- package/lib/dbsc.js +5 -6
- package/lib/ddl-change-control.js +18 -14
- package/lib/deprecate.js +4 -5
- package/lib/did.js +6 -2
- package/lib/dora.js +43 -13
- package/lib/dr-runbook.js +1 -1
- package/lib/dsa.js +2 -1
- package/lib/dsr.js +30 -20
- package/lib/early-hints.js +19 -0
- package/lib/eat.js +5 -1
- package/lib/external-db-migrate.js +21 -22
- package/lib/external-db.js +74 -30
- package/lib/fda-21cfr11.js +42 -13
- package/lib/fdx.js +22 -18
- package/lib/file-upload.js +80 -66
- package/lib/flag-evaluation-context.js +5 -8
- package/lib/flag-providers.js +6 -2
- package/lib/forms.js +1 -1
- package/lib/framework-error.js +12 -0
- package/lib/framework-schema.js +19 -0
- package/lib/fsm.js +7 -12
- package/lib/gate-contract.js +911 -39
- package/lib/gdpr-ropa.js +22 -22
- package/lib/graphql-federation.js +18 -5
- package/lib/guard-agent-registry.js +2 -1
- package/lib/guard-all.js +3 -2
- package/lib/guard-archive.js +9 -30
- package/lib/guard-auth.js +23 -80
- package/lib/guard-cidr.js +20 -96
- package/lib/guard-csv.js +135 -196
- package/lib/guard-domain.js +23 -106
- package/lib/guard-dsn.js +17 -14
- package/lib/guard-email.js +46 -53
- package/lib/guard-envelope.js +2 -2
- package/lib/guard-event-bus-topic.js +2 -1
- package/lib/guard-filename.js +12 -60
- package/lib/guard-graphql.js +28 -75
- package/lib/guard-html-wcag.js +15 -2
- package/lib/guard-html.js +74 -128
- package/lib/guard-idempotency-key.js +2 -1
- package/lib/guard-image.js +280 -77
- package/lib/guard-imap-command.js +9 -10
- package/lib/guard-jmap.js +1 -1
- package/lib/guard-json.js +101 -109
- package/lib/guard-jsonpath.js +20 -88
- package/lib/guard-jwt.js +32 -114
- package/lib/guard-list-id.js +2 -7
- package/lib/guard-list-unsubscribe.js +2 -7
- package/lib/guard-mail-compose.js +5 -6
- package/lib/guard-mail-move.js +3 -2
- package/lib/guard-mail-query.js +5 -3
- package/lib/guard-mail-sieve.js +6 -7
- package/lib/guard-managesieve-command.js +6 -5
- package/lib/guard-markdown.js +76 -110
- package/lib/guard-message-id.js +5 -6
- package/lib/guard-mime.js +20 -99
- package/lib/guard-oauth.js +19 -73
- package/lib/guard-pdf.js +65 -72
- package/lib/guard-pop3-command.js +13 -14
- package/lib/guard-posture-chain.js +2 -1
- package/lib/guard-regex.js +24 -99
- package/lib/guard-saga-config.js +2 -1
- package/lib/guard-shell.js +22 -87
- package/lib/guard-smtp-command.js +9 -12
- package/lib/guard-sql.js +15 -13
- package/lib/guard-stream-args.js +2 -1
- package/lib/guard-svg.js +103 -149
- package/lib/guard-template.js +23 -80
- package/lib/guard-tenant-id.js +2 -1
- package/lib/guard-text.js +592 -0
- package/lib/guard-time.js +27 -95
- package/lib/guard-uuid.js +21 -93
- package/lib/guard-xml.js +76 -106
- package/lib/guard-yaml.js +24 -60
- package/lib/html-balance.js +7 -3
- package/lib/http-client-cache.js +5 -12
- package/lib/http-client-cookie-jar.js +35 -16
- package/lib/http-client.js +233 -74
- package/lib/http-message-signature.js +3 -2
- package/lib/i18n-messageformat.js +5 -7
- package/lib/i18n.js +83 -26
- package/lib/iab-tcf.js +3 -2
- package/lib/importmap-integrity.js +41 -1
- package/lib/inbox.js +8 -8
- package/lib/incident-report.js +12 -27
- package/lib/ip-utils.js +49 -6
- package/lib/jobs.js +3 -2
- package/lib/json-patch.js +1 -1
- package/lib/json-path.js +24 -3
- package/lib/jtd.js +2 -2
- package/lib/keychain.js +6 -18
- package/lib/legal-hold.js +30 -23
- package/lib/log-stream-cloudwatch.js +44 -112
- package/lib/log-stream-otlp-grpc.js +17 -14
- package/lib/log-stream-otlp.js +16 -80
- package/lib/log-stream-webhook.js +20 -92
- package/lib/log.js +2 -2
- package/lib/mail-agent.js +2 -2
- package/lib/mail-arc-sign.js +8 -3
- package/lib/mail-arf.js +4 -3
- package/lib/mail-auth.js +43 -69
- package/lib/mail-bimi.js +35 -55
- package/lib/mail-bounce.js +3 -3
- package/lib/mail-crypto-pgp.js +3 -2
- package/lib/mail-crypto-smime.js +71 -6
- package/lib/mail-dav.js +8 -35
- package/lib/mail-deploy.js +15 -14
- package/lib/mail-dkim.js +19 -38
- package/lib/mail-greylist.js +17 -30
- package/lib/mail-helo.js +4 -7
- package/lib/mail-journal.js +13 -9
- package/lib/mail-mdn.js +12 -7
- package/lib/mail-rbl.js +7 -12
- package/lib/mail-scan.js +5 -7
- package/lib/mail-send-deliver.js +33 -20
- package/lib/mail-server-imap.js +32 -87
- package/lib/mail-server-jmap.js +39 -52
- package/lib/mail-server-managesieve.js +29 -83
- package/lib/mail-server-mx.js +33 -74
- package/lib/mail-server-net.js +177 -0
- package/lib/mail-server-pop3.js +30 -83
- package/lib/mail-server-rate-limit.js +30 -6
- package/lib/mail-server-registry.js +1 -1
- package/lib/mail-server-submission.js +34 -73
- package/lib/mail-server-tls.js +98 -2
- package/lib/mail-spam-score.js +9 -12
- package/lib/mail-store-fts.js +1 -1
- package/lib/mail-store.js +3 -2
- package/lib/mail.js +28 -13
- package/lib/markup-escape.js +31 -0
- package/lib/markup-tokenizer.js +78 -0
- package/lib/mcp-tool-registry.js +26 -23
- package/lib/mcp.js +7 -5
- package/lib/mdoc.js +36 -14
- package/lib/metrics.js +46 -33
- package/lib/middleware/age-gate.js +3 -23
- package/lib/middleware/api-encrypt.js +13 -24
- package/lib/middleware/assetlinks.js +2 -7
- package/lib/middleware/bearer-auth.js +2 -1
- package/lib/middleware/body-parser.js +41 -52
- package/lib/middleware/bot-disclose.js +7 -10
- package/lib/middleware/bot-guard.js +28 -28
- package/lib/middleware/clear-site-data.js +5 -1
- package/lib/middleware/compression.js +9 -0
- package/lib/middleware/cors.js +32 -23
- package/lib/middleware/csrf-protect.js +73 -23
- package/lib/middleware/daily-byte-quota.js +12 -30
- package/lib/middleware/deny-response.js +19 -1
- package/lib/middleware/fetch-metadata.js +35 -4
- package/lib/middleware/idempotency-key.js +4 -20
- package/lib/middleware/network-allowlist.js +61 -30
- package/lib/middleware/rate-limit.js +45 -44
- package/lib/middleware/scim-server.js +5 -3
- package/lib/middleware/security-headers.js +33 -7
- package/lib/middleware/security-txt.js +2 -6
- package/lib/middleware/speculation-rules.js +6 -3
- package/lib/middleware/tus-upload.js +14 -29
- package/lib/middleware/web-app-manifest.js +2 -7
- package/lib/migrations.js +4 -13
- package/lib/mime-parse.js +34 -17
- package/lib/module-loader.js +44 -0
- package/lib/money.js +105 -0
- package/lib/mtls-ca.js +125 -41
- package/lib/network-byte-quota.js +4 -18
- package/lib/network-dane.js +8 -6
- package/lib/network-dns-resolver.js +98 -7
- package/lib/network-dns.js +9 -2
- package/lib/network-dnssec.js +18 -17
- package/lib/network-heartbeat.js +3 -2
- package/lib/network-smtp-policy.js +52 -46
- package/lib/network-tls.js +67 -47
- package/lib/network-tsig.js +2 -2
- package/lib/nis2-report.js +2 -12
- package/lib/nist-crosswalk.js +1 -1
- package/lib/nonce-store.js +81 -3
- package/lib/ntp-check.js +28 -0
- package/lib/numeric-bounds.js +31 -8
- package/lib/object-store/azure-blob-bucket-ops.js +2 -6
- package/lib/object-store/azure-blob.js +6 -47
- package/lib/object-store/gcs-bucket-ops.js +4 -2
- package/lib/object-store/gcs.js +14 -75
- package/lib/object-store/http-put.js +2 -7
- package/lib/object-store/http-request.js +157 -0
- package/lib/object-store/local.js +37 -17
- package/lib/object-store/sigv4-bucket-ops.js +2 -1
- package/lib/object-store/sigv4.js +10 -79
- package/lib/observability-otlp-exporter.js +29 -29
- package/lib/observability.js +95 -0
- package/lib/openapi-paths-builder.js +7 -3
- package/lib/otel-export.js +7 -10
- package/lib/outbox.js +54 -41
- package/lib/pagination.js +11 -15
- package/lib/parsers/safe-env.js +5 -4
- package/lib/parsers/safe-ini.js +10 -4
- package/lib/parsers/safe-toml.js +11 -9
- package/lib/parsers/safe-xml.js +3 -3
- package/lib/parsers/safe-yaml.js +28 -9
- package/lib/pick.js +63 -5
- package/lib/pipl-cn.js +69 -59
- package/lib/privacy-pass.js +8 -6
- package/lib/problem-details.js +2 -5
- package/lib/pubsub.js +4 -8
- package/lib/queue-local.js +10 -3
- package/lib/redact.js +9 -4
- package/lib/render.js +4 -2
- package/lib/request-helpers.js +334 -29
- package/lib/resource-access-lock.js +3 -3
- package/lib/restore-bundle.js +46 -18
- package/lib/restore-rollback.js +10 -4
- package/lib/restore.js +24 -22
- package/lib/retention.js +23 -9
- package/lib/router.js +17 -4
- package/lib/safe-async.js +457 -0
- package/lib/safe-buffer.js +137 -6
- package/lib/safe-decompress.js +2 -1
- package/lib/safe-dns.js +2 -1
- package/lib/safe-ical.js +14 -28
- package/lib/safe-icap.js +1 -1
- package/lib/safe-json.js +51 -8
- package/lib/safe-jsonpath.js +6 -5
- package/lib/safe-mime.js +25 -29
- package/lib/safe-redirect.js +2 -5
- package/lib/safe-schema.js +7 -6
- package/lib/safe-sieve.js +1 -1
- package/lib/safe-sql.js +126 -0
- package/lib/safe-vcard.js +13 -27
- package/lib/sandbox-worker.js +15 -2
- package/lib/sandbox.js +4 -3
- package/lib/scheduler.js +22 -13
- package/lib/sec-cyber.js +82 -37
- package/lib/seeders.js +4 -11
- package/lib/self-update-standalone-verifier.js +16 -0
- package/lib/self-update.js +92 -69
- package/lib/session-device-binding.js +112 -66
- package/lib/session.js +219 -7
- package/lib/sql.js +228 -81
- package/lib/sse.js +6 -10
- package/lib/static.js +201 -111
- package/lib/storage.js +4 -2
- package/lib/structured-fields.js +275 -16
- package/lib/template.js +7 -5
- package/lib/tenant-quota.js +53 -38
- package/lib/tsa.js +16 -17
- package/lib/validate-opts.js +154 -8
- package/lib/vault/index.js +5 -0
- package/lib/vault/passphrase-ops.js +22 -26
- package/lib/vault/passphrase-source.js +8 -3
- package/lib/vault/rotate.js +13 -18
- package/lib/vault/seal-pem-file.js +34 -49
- package/lib/vault-aad.js +3 -2
- package/lib/vc.js +3 -8
- package/lib/vendor/MANIFEST.json +10 -10
- package/lib/vendor/public-suffix-list.dat +23 -10
- package/lib/vendor/public-suffix-list.data.js +5498 -5494
- package/lib/vex.js +35 -13
- package/lib/web-push-vapid.js +23 -20
- package/lib/webhook-dispatcher.js +706 -0
- package/lib/webhook.js +59 -19
- package/lib/websocket-channels.js +9 -7
- package/lib/websocket.js +8 -4
- package/lib/worm.js +3 -4
- package/lib/ws-client.js +65 -56
- package/lib/x509-chain.js +44 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/mail-send-deliver.js
CHANGED
|
@@ -441,16 +441,32 @@ function create(opts) {
|
|
|
441
441
|
validateOpts(opts,
|
|
442
442
|
["hostname", "resolver", "policy", "retry", "dsn", "timeouts", "audit", "transportFactory", "port"],
|
|
443
443
|
"mail.send.deliver.create");
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
//
|
|
448
|
-
//
|
|
449
|
-
//
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
|
|
444
|
+
// hostname is required; opts.port (when present) must be a valid connect
|
|
445
|
+
// port. Submission/smarthost relays listen on 587 (RFC 6409) or
|
|
446
|
+
// implicit-TLS 465 (RFC 8314) rather than the IANA SMTP port 25
|
|
447
|
+
// (RFC 5321 §2.3.4) that direct MX delivery uses. Operators routing
|
|
448
|
+
// through such a relay set opts.port; the value is range-checked here
|
|
449
|
+
// (RFC 6335 §6) so a typo fails at config time, not on the first
|
|
450
|
+
// connect attempt.
|
|
451
|
+
// The shape is the authoritative, exhaustive opts contract: every key
|
|
452
|
+
// the factory accepts is declared here. hostname + port carry their
|
|
453
|
+
// final per-field codes; the sub-object opts (policy / retry / dsn /
|
|
454
|
+
// timeouts) are shape-checked only for object-ness here, with their
|
|
455
|
+
// field-level validation (and the distinct per-field codes operators
|
|
456
|
+
// see) applied below where each sub-object is resolved.
|
|
457
|
+
validateOpts.shape(opts, {
|
|
458
|
+
hostname: { rule: "required-string", code: "deliver/bad-hostname",
|
|
459
|
+
label: "mail.send.deliver.create: hostname (local HELO/EHLO + DSN Reporting-MTA)" },
|
|
460
|
+
port: { rule: "optional-port", code: "deliver/bad-port" },
|
|
461
|
+
resolver: { rule: "optional-plain-object", code: "deliver/bad-resolver",
|
|
462
|
+
label: "mail.send.deliver.create: resolver (b.network.dns.resolver handle)" },
|
|
463
|
+
policy: { rule: "optional-plain-object", code: "deliver/bad-policy" },
|
|
464
|
+
retry: { rule: "optional-plain-object", code: "deliver/bad-retry" },
|
|
465
|
+
dsn: { rule: "optional-plain-object", code: "deliver/bad-dsn" },
|
|
466
|
+
timeouts: { rule: "optional-plain-object", code: "deliver/bad-timeouts" },
|
|
467
|
+
audit: { rule: "optional-boolean", code: "deliver/bad-audit" },
|
|
468
|
+
transportFactory: { rule: "optional-function", code: "deliver/bad-transport-factory" },
|
|
469
|
+
}, "mail.send.deliver.create", DeliverError, "deliver/bad-opts");
|
|
454
470
|
var port = opts.port || DEFAULT_PORT_SMTP;
|
|
455
471
|
|
|
456
472
|
var policy = opts.policy || {};
|
|
@@ -480,10 +496,12 @@ function create(opts) {
|
|
|
480
496
|
|
|
481
497
|
var timeouts = opts.timeouts || {};
|
|
482
498
|
validateOpts(timeouts, ["mxLookupMs", "perHostMs"], "mail.send.deliver.create.timeouts");
|
|
483
|
-
validateOpts.
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
499
|
+
validateOpts.shape(timeouts, {
|
|
500
|
+
mxLookupMs: { rule: "optional-positive-int", code: "deliver/bad-timeout-mxLookupMs",
|
|
501
|
+
label: "mail.send.deliver.create.timeouts.mxLookupMs" },
|
|
502
|
+
perHostMs: { rule: "optional-positive-int", code: "deliver/bad-timeout-perHostMs",
|
|
503
|
+
label: "mail.send.deliver.create.timeouts.perHostMs" },
|
|
504
|
+
}, "mail.send.deliver.create.timeouts", DeliverError, "deliver/bad-timeouts");
|
|
487
505
|
var mxLookupTimeoutMs = timeouts.mxLookupMs !== undefined
|
|
488
506
|
? timeouts.mxLookupMs : DEFAULT_MX_LOOKUP_TIMEOUT_MS;
|
|
489
507
|
var perHostTimeoutMs = timeouts.perHostMs !== undefined
|
|
@@ -502,12 +520,7 @@ function create(opts) {
|
|
|
502
520
|
}
|
|
503
521
|
|
|
504
522
|
var auditEnabled = opts.audit !== false;
|
|
505
|
-
|
|
506
|
-
if (!auditEnabled) return;
|
|
507
|
-
try {
|
|
508
|
-
audit().safeEmit({ action: action, outcome: outcome, metadata: metadata || {} });
|
|
509
|
-
} catch (_e) { /* drop-silent — hot-path audit */ }
|
|
510
|
-
}
|
|
523
|
+
var _auditEmit = audit().namespaced(null, { audit: auditEnabled });
|
|
511
524
|
|
|
512
525
|
async function deliver(envelope) {
|
|
513
526
|
if (!envelope || typeof envelope !== "object") {
|
package/lib/mail-server-imap.js
CHANGED
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
*/
|
|
118
118
|
|
|
119
119
|
var net = require("node:net");
|
|
120
|
-
var
|
|
120
|
+
var safeBuffer = require("./safe-buffer");
|
|
121
121
|
var C = require("./constants");
|
|
122
122
|
var bCrypto = require("./crypto");
|
|
123
123
|
var numericBounds = require("./numeric-bounds");
|
|
@@ -126,9 +126,10 @@ var guardImapCommand = require("./guard-imap-command");
|
|
|
126
126
|
var mailServerRateLimit = require("./mail-server-rate-limit");
|
|
127
127
|
var mailServerRegistry = require("./mail-server-registry");
|
|
128
128
|
var mailServerTls = require("./mail-server-tls");
|
|
129
|
+
var mailServerNet = require("./mail-server-net");
|
|
129
130
|
var { defineClass } = require("./framework-error");
|
|
130
131
|
|
|
131
|
-
var
|
|
132
|
+
var auditEmit = require("./audit-emit");
|
|
132
133
|
|
|
133
134
|
var MailServerImapError = defineClass("MailServerImapError", { alwaysPermanent: true });
|
|
134
135
|
|
|
@@ -138,6 +139,7 @@ var DEFAULT_IDLE_TIMEOUT_MS = C.TIME.minutes(30);
|
|
|
138
139
|
var IDLE_BANDWIDTH_TIMEOUT_MS = C.TIME.minutes(29); // RFC 2177 §3 — re-issue before 30
|
|
139
140
|
var DEFAULT_GREETING_VENDOR = "blamejs IMAP4rev2";
|
|
140
141
|
var pkgVersion = require("../package.json").version;
|
|
142
|
+
var codepointClass = require("./codepoint-class");
|
|
141
143
|
|
|
142
144
|
// Error-message clamp bytes — protocol-string clamp, not a byte count.
|
|
143
145
|
// Centralized so the marker lives in one place
|
|
@@ -196,10 +198,7 @@ function _parseImapDateTime(s) {
|
|
|
196
198
|
function _validateMailboxName(name, opts) {
|
|
197
199
|
if (typeof name !== "string" || name.length === 0) return false;
|
|
198
200
|
if (name.length > 1024) return false; // mailbox name cap
|
|
199
|
-
|
|
200
|
-
var c = name.charCodeAt(i);
|
|
201
|
-
if (c < 0x20 || c === 0x7F) return false; // control-byte refusal
|
|
202
|
-
}
|
|
201
|
+
if (codepointClass.firstControlCharOffset(name, { forbidTab: true }) !== -1) return false; // control-byte refusal
|
|
203
202
|
if (name.indexOf("..") !== -1) return false;
|
|
204
203
|
if (name === "/" || name[0] === "/" || name[name.length - 1] === "/") return false;
|
|
205
204
|
// Modified-UTF7 detection — RFC 3501 §5.1.3. Sequences are
|
|
@@ -275,40 +274,18 @@ function create(opts) {
|
|
|
275
274
|
var mailStore = opts.mailStore;
|
|
276
275
|
var allowLegacyMUtf7 = profile === "permissive";
|
|
277
276
|
|
|
278
|
-
var rateLimit;
|
|
279
|
-
if (opts.rateLimit === false) {
|
|
280
|
-
rateLimit = mailServerRateLimit.create({ disabled: true });
|
|
281
|
-
} else if (opts.rateLimit && typeof opts.rateLimit.admitConnection === "function") {
|
|
282
|
-
rateLimit = opts.rateLimit;
|
|
283
|
-
} else {
|
|
284
|
-
rateLimit = mailServerRateLimit.create(opts.rateLimit || {});
|
|
285
|
-
}
|
|
277
|
+
var rateLimit = mailServerRateLimit.resolve(opts.rateLimit);
|
|
286
278
|
|
|
287
|
-
var tcpServer = null;
|
|
288
|
-
var listening = false;
|
|
289
279
|
var connections = new Set();
|
|
290
280
|
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
audit().safeEmit({
|
|
294
|
-
action: action,
|
|
295
|
-
outcome: outcome || "success",
|
|
296
|
-
metadata: metadata || {},
|
|
297
|
-
});
|
|
298
|
-
} catch (_e) { /* drop-silent — audit best-effort */ }
|
|
299
|
-
}
|
|
281
|
+
var _emit = auditEmit.emit;
|
|
300
282
|
|
|
301
283
|
function _handleConnection(rawSocket) {
|
|
302
|
-
var remoteAddress = rawSocket
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
try { rawSocket.write("* BAD Too many connections from your IP\r\n"); }
|
|
308
|
-
catch (_e) { /* socket may be down */ }
|
|
309
|
-
try { rawSocket.destroy(); } catch (_e2) { /* idempotent */ }
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
284
|
+
var remoteAddress = mailServerNet.admitConnection(rawSocket, rateLimit, _emit, {
|
|
285
|
+
refusedEvent: "mail.server.imap.rate_limit_refused",
|
|
286
|
+
refusalLine: "* BAD Too many connections from your IP\r\n",
|
|
287
|
+
});
|
|
288
|
+
if (remoteAddress === null) return;
|
|
312
289
|
rawSocket.once("close", function () { rateLimit.releaseConnection(remoteAddress); });
|
|
313
290
|
|
|
314
291
|
var connectionId = "imapconn-" + bCrypto.generateToken(8); // connection-id length
|
|
@@ -389,7 +366,7 @@ function create(opts) {
|
|
|
389
366
|
}
|
|
390
367
|
var crlf = state.lineBuffer.indexOf("\r\n");
|
|
391
368
|
if (crlf === -1) {
|
|
392
|
-
if (state.lineBuffer
|
|
369
|
+
if (safeBuffer.byteLengthOf(state.lineBuffer) > maxLineBytes) {
|
|
393
370
|
_writeUntagged(socket, "BAD Line too long (cap " + maxLineBytes + ")");
|
|
394
371
|
_close(socket, state);
|
|
395
372
|
}
|
|
@@ -932,20 +909,17 @@ function create(opts) {
|
|
|
932
909
|
// would let the post-TLS state machine resume an exchange that
|
|
933
910
|
// started in plaintext, conflating cleartext + TLS-protected
|
|
934
911
|
// phases of the same SASL run.
|
|
935
|
-
//
|
|
936
|
-
//
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
912
|
+
// The pre-handshake state-drain (lineBuffer + pendingLiteral +
|
|
913
|
+
// authPending), listener-removal, idle-timeout re-arm, and the
|
|
914
|
+
// post-handshake read-pump live in the shared upgradeLineProtocol
|
|
915
|
+
// helper (b.mail.server.tls.upgradeLineProtocol).
|
|
916
|
+
mailServerTls.upgradeLineProtocol({
|
|
917
|
+
state: state,
|
|
918
|
+
socket: socket,
|
|
942
919
|
secureContext: opts.tlsContext,
|
|
943
920
|
idleTimeoutMs: idleTimeoutMs,
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
state.lineBuffer = Buffer.concat([state.lineBuffer, chunk]);
|
|
947
|
-
_drainBuffer(state, tlsSocket);
|
|
948
|
-
},
|
|
921
|
+
clearFields: ["pendingLiteral", "authPending"],
|
|
922
|
+
drain: _drainBuffer,
|
|
949
923
|
onError: function (err) {
|
|
950
924
|
_emit("mail.server.imap.tls_handshake_failed",
|
|
951
925
|
{ connectionId: state.id, error: (err && err.message) || String(err) }, "failure");
|
|
@@ -1476,7 +1450,7 @@ function create(opts) {
|
|
|
1476
1450
|
if (q && typeof q.usedBytes === "number" &&
|
|
1477
1451
|
typeof q.capBytes === "number" &&
|
|
1478
1452
|
q.capBytes > 0 &&
|
|
1479
|
-
q.usedBytes + literalBody
|
|
1453
|
+
q.usedBytes + safeBuffer.byteLengthOf(literalBody) > q.capBytes) {
|
|
1480
1454
|
var err = new Error("APPEND would exceed quota (used " + q.usedBytes +
|
|
1481
1455
|
" + " + literalBody.length + " > cap " + q.capBytes + ")");
|
|
1482
1456
|
err.code = "mail-server-imap/overquota";
|
|
@@ -1812,44 +1786,15 @@ function create(opts) {
|
|
|
1812
1786
|
}
|
|
1813
1787
|
|
|
1814
1788
|
// ---- Lifecycle ----------------------------------------------------------
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
return new Promise(function (resolve, reject) {
|
|
1825
|
-
tcpServer.once("error", reject);
|
|
1826
|
-
tcpServer.listen(port, address, function () {
|
|
1827
|
-
listening = true;
|
|
1828
|
-
tcpServer.removeListener("error", reject);
|
|
1829
|
-
_emit("mail.server.imap.listening",
|
|
1830
|
-
{ port: port, address: address });
|
|
1831
|
-
resolve({ port: tcpServer.address().port, address: address });
|
|
1832
|
-
});
|
|
1833
|
-
});
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
|
-
async function close() {
|
|
1837
|
-
if (!listening) return;
|
|
1838
|
-
listening = false;
|
|
1839
|
-
for (var s of connections) { try { s.destroy(); } catch (_e) { /* idempotent */ } }
|
|
1840
|
-
connections.clear();
|
|
1841
|
-
return new Promise(function (resolve) {
|
|
1842
|
-
tcpServer.close(function () {
|
|
1843
|
-
_emit("mail.server.imap.closed", {});
|
|
1844
|
-
resolve();
|
|
1845
|
-
});
|
|
1846
|
-
});
|
|
1847
|
-
}
|
|
1848
|
-
|
|
1849
|
-
return {
|
|
1850
|
-
listen: listen,
|
|
1851
|
-
close: close,
|
|
1852
|
-
};
|
|
1789
|
+
return mailServerNet.createStoreServer(net, {
|
|
1790
|
+
defaultPort: 143, // RFC 9051 IMAP port (IANA)
|
|
1791
|
+
handleConnection: _handleConnection,
|
|
1792
|
+
errorClass: MailServerImapError,
|
|
1793
|
+
errorCodePrefix: "mail-server-imap/",
|
|
1794
|
+
emit: _emit,
|
|
1795
|
+
connections: connections,
|
|
1796
|
+
eventBase: "mail.server.imap",
|
|
1797
|
+
});
|
|
1853
1798
|
}
|
|
1854
1799
|
|
|
1855
1800
|
module.exports = {
|
package/lib/mail-server-jmap.js
CHANGED
|
@@ -129,6 +129,7 @@ var mailServerRegistry = require("./mail-server-registry");
|
|
|
129
129
|
var { defineClass } = require("./framework-error");
|
|
130
130
|
|
|
131
131
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
132
|
+
var auditEmit = require("./audit-emit");
|
|
132
133
|
|
|
133
134
|
var MailServerJmapError = defineClass("MailServerJmapError", { alwaysPermanent: true });
|
|
134
135
|
|
|
@@ -232,15 +233,7 @@ function create(opts) {
|
|
|
232
233
|
});
|
|
233
234
|
var sessionState = bCrypto.generateToken(16); // opaque session-state token length
|
|
234
235
|
|
|
235
|
-
|
|
236
|
-
try {
|
|
237
|
-
audit().safeEmit({
|
|
238
|
-
action: action,
|
|
239
|
-
outcome: outcome || "success",
|
|
240
|
-
metadata: metadata || {},
|
|
241
|
-
});
|
|
242
|
-
} catch (_e) { /* drop-silent — audit best-effort */ }
|
|
243
|
-
}
|
|
236
|
+
var _emit = auditEmit.emit;
|
|
244
237
|
|
|
245
238
|
// ---- Back-reference resolution (RFC 8620 §3.7) -------------------------
|
|
246
239
|
//
|
|
@@ -520,7 +513,10 @@ function create(opts) {
|
|
|
520
513
|
});
|
|
521
514
|
}
|
|
522
515
|
|
|
523
|
-
|
|
516
|
+
// _requireActor(req, res) — resolve the authenticated actor; on absence,
|
|
517
|
+
// write the RFC 8620 401 forbidden Problem-Details body and return null so
|
|
518
|
+
// the caller returns. Shared by every JMAP handler that gates on actor.
|
|
519
|
+
function _requireActor(req, res) {
|
|
524
520
|
var actor = req.user || (req.actor || null);
|
|
525
521
|
if (!actor) {
|
|
526
522
|
res.statusCode = 401;
|
|
@@ -529,8 +525,28 @@ function create(opts) {
|
|
|
529
525
|
type: "urn:ietf:params:jmap:error:forbidden",
|
|
530
526
|
description: "Authentication required",
|
|
531
527
|
}));
|
|
532
|
-
return;
|
|
528
|
+
return null;
|
|
533
529
|
}
|
|
530
|
+
return actor;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// _forEachQueryParam(query, fn) — split a raw URL query string on "&" and
|
|
534
|
+
// hand each non-empty pair to fn(rawKey, rawValue): the key is the text
|
|
535
|
+
// before the first "=", the value the remainder (both still
|
|
536
|
+
// percent-encoded — the caller decodes the slices it keeps).
|
|
537
|
+
function _forEachQueryParam(query, fn) {
|
|
538
|
+
query.split("&").forEach(function (pair) {
|
|
539
|
+
if (!pair) return;
|
|
540
|
+
var eq = pair.indexOf("=");
|
|
541
|
+
var k = eq === -1 ? pair : pair.slice(0, eq);
|
|
542
|
+
var v = eq === -1 ? "" : pair.slice(eq + 1);
|
|
543
|
+
fn(k, v);
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function sessionHandler(req, res) {
|
|
548
|
+
var actor = _requireActor(req, res);
|
|
549
|
+
if (!actor) return;
|
|
534
550
|
Promise.resolve().then(function () { return opts.accountsFor(actor); })
|
|
535
551
|
.then(function (accountInfo) {
|
|
536
552
|
var info = accountInfo || { primaryAccounts: {}, accounts: {} };
|
|
@@ -592,16 +608,8 @@ function create(opts) {
|
|
|
592
608
|
// closeafter=no (default) — keep open until disconnect.
|
|
593
609
|
// ping=<seconds> — keepalive interval (default 30s, min 5s, max 900s).
|
|
594
610
|
function eventSourceHandler(req, res) {
|
|
595
|
-
var actor =
|
|
596
|
-
if (!actor)
|
|
597
|
-
res.statusCode = 401;
|
|
598
|
-
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
599
|
-
res.end(JSON.stringify({
|
|
600
|
-
type: "urn:ietf:params:jmap:error:forbidden",
|
|
601
|
-
description: "Authentication required",
|
|
602
|
-
}));
|
|
603
|
-
return;
|
|
604
|
-
}
|
|
611
|
+
var actor = _requireActor(req, res);
|
|
612
|
+
if (!actor) return;
|
|
605
613
|
if (typeof opts.mailStore.subscribePush !== "function") {
|
|
606
614
|
res.statusCode = 503;
|
|
607
615
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
@@ -618,11 +626,7 @@ function create(opts) {
|
|
|
618
626
|
var qIdx = url.indexOf("?");
|
|
619
627
|
var query = qIdx === -1 ? "" : url.slice(qIdx + 1);
|
|
620
628
|
var params = Object.create(null);
|
|
621
|
-
query
|
|
622
|
-
if (!pair) return;
|
|
623
|
-
var eq = pair.indexOf("=");
|
|
624
|
-
var k = eq === -1 ? pair : pair.slice(0, eq);
|
|
625
|
-
var v = eq === -1 ? "" : pair.slice(eq + 1);
|
|
629
|
+
_forEachQueryParam(query, function (k, v) {
|
|
626
630
|
try { params[decodeURIComponent(k)] = decodeURIComponent(v); }
|
|
627
631
|
catch (_e) { /* drop-silent — malformed % encoding */ }
|
|
628
632
|
});
|
|
@@ -797,16 +801,8 @@ function create(opts) {
|
|
|
797
801
|
}
|
|
798
802
|
|
|
799
803
|
function uploadHandler(req, res) {
|
|
800
|
-
var actor =
|
|
801
|
-
if (!actor)
|
|
802
|
-
res.statusCode = 401;
|
|
803
|
-
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
804
|
-
res.end(JSON.stringify({
|
|
805
|
-
type: "urn:ietf:params:jmap:error:forbidden",
|
|
806
|
-
description: "Authentication required",
|
|
807
|
-
}));
|
|
808
|
-
return;
|
|
809
|
-
}
|
|
804
|
+
var actor = _requireActor(req, res);
|
|
805
|
+
if (!actor) return;
|
|
810
806
|
if (typeof opts.mailStore.uploadBlob !== "function") {
|
|
811
807
|
res.statusCode = 503;
|
|
812
808
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
@@ -938,16 +934,8 @@ function create(opts) {
|
|
|
938
934
|
// shaped buffer (Buffer or async-iterable) + the canonical MIME
|
|
939
935
|
// type; the handler pipes it to the response.
|
|
940
936
|
function downloadHandler(req, res) {
|
|
941
|
-
var actor =
|
|
942
|
-
if (!actor)
|
|
943
|
-
res.statusCode = 401;
|
|
944
|
-
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
945
|
-
res.end(JSON.stringify({
|
|
946
|
-
type: "urn:ietf:params:jmap:error:forbidden",
|
|
947
|
-
description: "Authentication required",
|
|
948
|
-
}));
|
|
949
|
-
return;
|
|
950
|
-
}
|
|
937
|
+
var actor = _requireActor(req, res);
|
|
938
|
+
if (!actor) return;
|
|
951
939
|
if (typeof opts.mailStore.downloadBlob !== "function") {
|
|
952
940
|
res.statusCode = 503;
|
|
953
941
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
@@ -970,11 +958,7 @@ function create(opts) {
|
|
|
970
958
|
var qIdx2 = rawUrl.indexOf("?");
|
|
971
959
|
var query = qIdx2 === -1 ? "" : rawUrl.slice(qIdx2 + 1);
|
|
972
960
|
var acceptType = "";
|
|
973
|
-
query
|
|
974
|
-
if (!pair) return;
|
|
975
|
-
var eq = pair.indexOf("=");
|
|
976
|
-
var k = eq === -1 ? pair : pair.slice(0, eq);
|
|
977
|
-
var v = eq === -1 ? "" : pair.slice(eq + 1);
|
|
961
|
+
_forEachQueryParam(query, function (k, v) {
|
|
978
962
|
if (k === "accept") {
|
|
979
963
|
try { acceptType = decodeURIComponent(v); } catch (_e) { /* silent-catch: malformed % encoding */ }
|
|
980
964
|
}
|
|
@@ -1154,7 +1138,10 @@ function create(opts) {
|
|
|
1154
1138
|
return;
|
|
1155
1139
|
}
|
|
1156
1140
|
var text = data.toString("utf8");
|
|
1157
|
-
|
|
1141
|
+
// Byte cap measured on the raw frame buffer, not text.length (UTF-16
|
|
1142
|
+
// code units) — a multibyte payload is 2-4x larger in bytes than chars,
|
|
1143
|
+
// so a char-length check under-enforces the limit.
|
|
1144
|
+
if (data.length > (opts.webSocketMaxMessageBytes || (10 * 1024 * 1024))) { // allow:raw-byte-literal — mirrors handleUpgrade cap
|
|
1158
1145
|
_sendRequestError(null,
|
|
1159
1146
|
"urn:ietf:params:jmap:error:limit",
|
|
1160
1147
|
"WebSocket message exceeds maxSizeRequest");
|
|
@@ -127,8 +127,9 @@
|
|
|
127
127
|
*/
|
|
128
128
|
|
|
129
129
|
var net = require("node:net");
|
|
130
|
+
var safeBuffer = require("./safe-buffer");
|
|
130
131
|
var mailServerTls = require("./mail-server-tls");
|
|
131
|
-
var
|
|
132
|
+
var mailServerNet = require("./mail-server-net");
|
|
132
133
|
var C = require("./constants");
|
|
133
134
|
var bCrypto = require("./crypto");
|
|
134
135
|
var numericBounds = require("./numeric-bounds");
|
|
@@ -139,7 +140,7 @@ var mailServerRateLimit = require("./mail-server-rate-limit");
|
|
|
139
140
|
var mailServerRegistry = require("./mail-server-registry");
|
|
140
141
|
var { defineClass } = require("./framework-error");
|
|
141
142
|
|
|
142
|
-
var
|
|
143
|
+
var auditEmit = require("./audit-emit");
|
|
143
144
|
|
|
144
145
|
var MailServerManageSieveError = defineClass("MailServerManageSieveError",
|
|
145
146
|
{ alwaysPermanent: true });
|
|
@@ -226,40 +227,18 @@ function create(opts) {
|
|
|
226
227
|
// the actual script bytes — same cap on both sides).
|
|
227
228
|
var safeSieveProfile = profile;
|
|
228
229
|
|
|
229
|
-
var rateLimit;
|
|
230
|
-
if (opts.rateLimit === false) {
|
|
231
|
-
rateLimit = mailServerRateLimit.create({ disabled: true });
|
|
232
|
-
} else if (opts.rateLimit && typeof opts.rateLimit.admitConnection === "function") {
|
|
233
|
-
rateLimit = opts.rateLimit;
|
|
234
|
-
} else {
|
|
235
|
-
rateLimit = mailServerRateLimit.create(opts.rateLimit || {});
|
|
236
|
-
}
|
|
230
|
+
var rateLimit = mailServerRateLimit.resolve(opts.rateLimit);
|
|
237
231
|
|
|
238
|
-
var tcpServer = null;
|
|
239
|
-
var listening = false;
|
|
240
232
|
var connections = new Set();
|
|
241
233
|
|
|
242
|
-
|
|
243
|
-
try {
|
|
244
|
-
audit().safeEmit({
|
|
245
|
-
action: action,
|
|
246
|
-
outcome: outcome || "success",
|
|
247
|
-
metadata: metadata || {},
|
|
248
|
-
});
|
|
249
|
-
} catch (_e) { /* drop-silent — audit best-effort */ }
|
|
250
|
-
}
|
|
234
|
+
var _emit = auditEmit.emit;
|
|
251
235
|
|
|
252
236
|
function _handleConnection(rawSocket) {
|
|
253
|
-
var remoteAddress = rawSocket
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
try { rawSocket.write('NO "Too many connections from your IP"\r\n'); }
|
|
259
|
-
catch (_e) { /* socket may be down */ }
|
|
260
|
-
try { rawSocket.destroy(); } catch (_e2) { /* idempotent */ }
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
237
|
+
var remoteAddress = mailServerNet.admitConnection(rawSocket, rateLimit, _emit, {
|
|
238
|
+
refusedEvent: "mail.server.managesieve.rate_limit_refused",
|
|
239
|
+
refusalLine: 'NO "Too many connections from your IP"\r\n',
|
|
240
|
+
});
|
|
241
|
+
if (remoteAddress === null) return;
|
|
263
242
|
var connectionId = "msvconn-" + bCrypto.generateToken(8); // connection-id length
|
|
264
243
|
var socket = rawSocket;
|
|
265
244
|
connections.add(socket);
|
|
@@ -354,7 +333,7 @@ function create(opts) {
|
|
|
354
333
|
}
|
|
355
334
|
var crlf = state.lineBuffer.indexOf("\r\n");
|
|
356
335
|
if (crlf === -1) {
|
|
357
|
-
if (state.lineBuffer
|
|
336
|
+
if (safeBuffer.byteLengthOf(state.lineBuffer) > maxLineBytes) {
|
|
358
337
|
_writeNo(socket, "Line too long (cap " + maxLineBytes + ")");
|
|
359
338
|
_close(socket);
|
|
360
339
|
}
|
|
@@ -525,19 +504,18 @@ function create(opts) {
|
|
|
525
504
|
}
|
|
526
505
|
_writeOk(socket, "Begin TLS negotiation now");
|
|
527
506
|
// RFC 5804 §2.2 — discard any bytes the client queued before the
|
|
528
|
-
// upgrade
|
|
529
|
-
//
|
|
530
|
-
//
|
|
531
|
-
//
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
mailServerTls.upgradeSocket({
|
|
536
|
-
plainSocket: socket,
|
|
507
|
+
// upgrade (lineBuffer + pendingLiteral + pendingAuth) so pre-
|
|
508
|
+
// handshake injection can't survive into the post-TLS session.
|
|
509
|
+
// The shared upgradeLineProtocol helper owns that drain plus the
|
|
510
|
+
// CVE-2021-33515 / CVE-2021-38371 listener-strip + pause + read-pump.
|
|
511
|
+
mailServerTls.upgradeLineProtocol({
|
|
512
|
+
state: state,
|
|
513
|
+
socket: socket,
|
|
537
514
|
secureContext: tlsContext,
|
|
538
515
|
idleTimeoutMs: idleTimeoutMs,
|
|
516
|
+
clearFields: ["pendingLiteral", "pendingAuth"],
|
|
517
|
+
drain: _drainBuffer,
|
|
539
518
|
onSecure: function (tlsSocket) {
|
|
540
|
-
state.tls = true;
|
|
541
519
|
_emit("mail.server.managesieve.starttls_upgraded",
|
|
542
520
|
{ connectionId: state.id });
|
|
543
521
|
// RFC 5804 §2.2 — server MUST re-emit capabilities on the
|
|
@@ -546,10 +524,6 @@ function create(opts) {
|
|
|
546
524
|
_emitCapabilityBanner(state, tlsSocket);
|
|
547
525
|
_writeOk(tlsSocket, "TLS negotiation successful");
|
|
548
526
|
},
|
|
549
|
-
onData: function (tlsSocket, chunk) {
|
|
550
|
-
state.lineBuffer = Buffer.concat([state.lineBuffer, chunk]);
|
|
551
|
-
_drainBuffer(state, tlsSocket);
|
|
552
|
-
},
|
|
553
527
|
onError: function (err) {
|
|
554
528
|
_emit("mail.server.managesieve.starttls_handshake_failed",
|
|
555
529
|
{ connectionId: state.id, error: (err && err.message) || String(err) }, "failure");
|
|
@@ -863,43 +837,15 @@ function create(opts) {
|
|
|
863
837
|
}
|
|
864
838
|
|
|
865
839
|
// ---- Lifecycle ----------------------------------------------------------
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
return new Promise(function (resolve, reject) {
|
|
876
|
-
tcpServer.once("error", reject);
|
|
877
|
-
tcpServer.listen(port, address, function () {
|
|
878
|
-
listening = true;
|
|
879
|
-
tcpServer.removeListener("error", reject);
|
|
880
|
-
_emit("mail.server.managesieve.listening", { port: port, address: address });
|
|
881
|
-
resolve({ port: tcpServer.address().port, address: address });
|
|
882
|
-
});
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
async function close() {
|
|
887
|
-
if (!listening) return;
|
|
888
|
-
listening = false;
|
|
889
|
-
for (var s of connections) { try { s.destroy(); } catch (_e) { /* idempotent */ } }
|
|
890
|
-
connections.clear();
|
|
891
|
-
return new Promise(function (resolve) {
|
|
892
|
-
tcpServer.close(function () {
|
|
893
|
-
_emit("mail.server.managesieve.closed", {});
|
|
894
|
-
resolve();
|
|
895
|
-
});
|
|
896
|
-
});
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
return {
|
|
900
|
-
listen: listen,
|
|
901
|
-
close: close,
|
|
902
|
-
};
|
|
840
|
+
return mailServerNet.createStoreServer(net, {
|
|
841
|
+
defaultPort: DEFAULT_PORT,
|
|
842
|
+
handleConnection: _handleConnection,
|
|
843
|
+
errorClass: MailServerManageSieveError,
|
|
844
|
+
errorCodePrefix: "mail-server-managesieve/",
|
|
845
|
+
emit: _emit,
|
|
846
|
+
connections: connections,
|
|
847
|
+
eventBase: "mail.server.managesieve",
|
|
848
|
+
});
|
|
903
849
|
}
|
|
904
850
|
|
|
905
851
|
module.exports = {
|