@serve.zone/dcrouter 2.12.4
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/.dockerignore +1 -0
- package/.gitea/workflows/docker_nottags.yaml +71 -0
- package/.gitea/workflows/docker_tags.yaml +106 -0
- package/.vscode/launch.json +11 -0
- package/.vscode/settings.json +26 -0
- package/Dockerfile +46 -0
- package/changelog.md +247 -0
- package/cli.child.js +4 -0
- package/cli.child.ts +4 -0
- package/cli.js +4 -0
- package/cli.ts.js +5 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.dcrouter.d.ts +238 -0
- package/dist_ts/classes.dcrouter.js +1008 -0
- package/dist_ts/config/index.d.ts +1 -0
- package/dist_ts/config/index.js +3 -0
- package/dist_ts/config/validator.d.ts +104 -0
- package/dist_ts/config/validator.js +152 -0
- package/dist_ts/deliverability/classes.ipwarmupmanager.d.ts +253 -0
- package/dist_ts/deliverability/classes.ipwarmupmanager.js +639 -0
- package/dist_ts/deliverability/classes.senderreputationmonitor.d.ts +300 -0
- package/dist_ts/deliverability/classes.senderreputationmonitor.js +961 -0
- package/dist_ts/deliverability/index.d.ts +2 -0
- package/dist_ts/deliverability/index.js +3 -0
- package/dist_ts/errors/base.errors.d.ts +224 -0
- package/dist_ts/errors/base.errors.js +310 -0
- package/dist_ts/errors/email.errors.d.ts +175 -0
- package/dist_ts/errors/email.errors.js +265 -0
- package/dist_ts/errors/error-handler.d.ts +98 -0
- package/dist_ts/errors/error-handler.js +282 -0
- package/dist_ts/errors/error.codes.d.ts +115 -0
- package/dist_ts/errors/error.codes.js +136 -0
- package/dist_ts/errors/index.d.ts +56 -0
- package/dist_ts/errors/index.js +138 -0
- package/dist_ts/errors/mta.errors.d.ts +259 -0
- package/dist_ts/errors/mta.errors.js +472 -0
- package/dist_ts/errors/reputation.errors.d.ts +183 -0
- package/dist_ts/errors/reputation.errors.js +292 -0
- package/dist_ts/index.d.ts +4 -0
- package/dist_ts/index.js +6 -0
- package/dist_ts/logger.d.ts +17 -0
- package/dist_ts/logger.js +77 -0
- package/dist_ts/mail/core/classes.bouncemanager.d.ts +200 -0
- package/dist_ts/mail/core/classes.bouncemanager.js +778 -0
- package/dist_ts/mail/core/classes.email.d.ts +291 -0
- package/dist_ts/mail/core/classes.email.js +780 -0
- package/dist_ts/mail/core/classes.emailvalidator.d.ts +61 -0
- package/dist_ts/mail/core/classes.emailvalidator.js +182 -0
- package/dist_ts/mail/core/classes.templatemanager.d.ts +95 -0
- package/dist_ts/mail/core/classes.templatemanager.js +239 -0
- package/dist_ts/mail/core/index.d.ts +4 -0
- package/dist_ts/mail/core/index.js +6 -0
- package/dist_ts/mail/delivery/classes.delivery.queue.d.ts +163 -0
- package/dist_ts/mail/delivery/classes.delivery.queue.js +485 -0
- package/dist_ts/mail/delivery/classes.delivery.system.d.ts +186 -0
- package/dist_ts/mail/delivery/classes.delivery.system.js +846 -0
- package/dist_ts/mail/delivery/classes.emailsendjob.d.ts +84 -0
- package/dist_ts/mail/delivery/classes.emailsendjob.js +362 -0
- package/dist_ts/mail/delivery/classes.emailsignjob.d.ts +18 -0
- package/dist_ts/mail/delivery/classes.emailsignjob.js +44 -0
- package/dist_ts/mail/delivery/classes.mta.config.d.ts +22 -0
- package/dist_ts/mail/delivery/classes.mta.config.js +51 -0
- package/dist_ts/mail/delivery/classes.ratelimiter.d.ts +98 -0
- package/dist_ts/mail/delivery/classes.ratelimiter.js +205 -0
- package/dist_ts/mail/delivery/classes.smtp.client.legacy.d.ts +275 -0
- package/dist_ts/mail/delivery/classes.smtp.client.legacy.js +973 -0
- package/dist_ts/mail/delivery/classes.unified.rate.limiter.d.ts +200 -0
- package/dist_ts/mail/delivery/classes.unified.rate.limiter.js +817 -0
- package/dist_ts/mail/delivery/index.d.ts +12 -0
- package/dist_ts/mail/delivery/index.js +18 -0
- package/dist_ts/mail/delivery/interfaces.d.ts +243 -0
- package/dist_ts/mail/delivery/interfaces.js +17 -0
- package/dist_ts/mail/delivery/smtpclient/auth-handler.d.ts +43 -0
- package/dist_ts/mail/delivery/smtpclient/auth-handler.js +188 -0
- package/dist_ts/mail/delivery/smtpclient/command-handler.d.ts +67 -0
- package/dist_ts/mail/delivery/smtpclient/command-handler.js +276 -0
- package/dist_ts/mail/delivery/smtpclient/connection-manager.d.ts +48 -0
- package/dist_ts/mail/delivery/smtpclient/connection-manager.js +238 -0
- package/dist_ts/mail/delivery/smtpclient/constants.d.ts +129 -0
- package/dist_ts/mail/delivery/smtpclient/constants.js +135 -0
- package/dist_ts/mail/delivery/smtpclient/create-client.d.ts +22 -0
- package/dist_ts/mail/delivery/smtpclient/create-client.js +86 -0
- package/dist_ts/mail/delivery/smtpclient/error-handler.d.ts +28 -0
- package/dist_ts/mail/delivery/smtpclient/error-handler.js +110 -0
- package/dist_ts/mail/delivery/smtpclient/index.d.ts +16 -0
- package/dist_ts/mail/delivery/smtpclient/index.js +21 -0
- package/dist_ts/mail/delivery/smtpclient/interfaces.d.ts +183 -0
- package/dist_ts/mail/delivery/smtpclient/interfaces.js +19 -0
- package/dist_ts/mail/delivery/smtpclient/smtp-client.d.ts +58 -0
- package/dist_ts/mail/delivery/smtpclient/smtp-client.js +279 -0
- package/dist_ts/mail/delivery/smtpclient/tls-handler.d.ts +33 -0
- package/dist_ts/mail/delivery/smtpclient/tls-handler.js +202 -0
- package/dist_ts/mail/delivery/smtpclient/utils/helpers.d.ts +77 -0
- package/dist_ts/mail/delivery/smtpclient/utils/helpers.js +196 -0
- package/dist_ts/mail/delivery/smtpclient/utils/logging.d.ts +46 -0
- package/dist_ts/mail/delivery/smtpclient/utils/logging.js +153 -0
- package/dist_ts/mail/delivery/smtpclient/utils/validation.d.ts +38 -0
- package/dist_ts/mail/delivery/smtpclient/utils/validation.js +139 -0
- package/dist_ts/mail/delivery/smtpserver/certificate-utils.d.ts +45 -0
- package/dist_ts/mail/delivery/smtpserver/certificate-utils.js +345 -0
- package/dist_ts/mail/delivery/smtpserver/command-handler.d.ts +156 -0
- package/dist_ts/mail/delivery/smtpserver/command-handler.js +1159 -0
- package/dist_ts/mail/delivery/smtpserver/connection-manager.d.ts +159 -0
- package/dist_ts/mail/delivery/smtpserver/connection-manager.js +894 -0
- package/dist_ts/mail/delivery/smtpserver/constants.d.ts +130 -0
- package/dist_ts/mail/delivery/smtpserver/constants.js +162 -0
- package/dist_ts/mail/delivery/smtpserver/create-server.d.ts +14 -0
- package/dist_ts/mail/delivery/smtpserver/create-server.js +28 -0
- package/dist_ts/mail/delivery/smtpserver/data-handler.d.ts +123 -0
- package/dist_ts/mail/delivery/smtpserver/data-handler.js +1148 -0
- package/dist_ts/mail/delivery/smtpserver/index.d.ts +20 -0
- package/dist_ts/mail/delivery/smtpserver/index.js +27 -0
- package/dist_ts/mail/delivery/smtpserver/interfaces.d.ts +530 -0
- package/dist_ts/mail/delivery/smtpserver/interfaces.js +10 -0
- package/dist_ts/mail/delivery/smtpserver/secure-server.d.ts +15 -0
- package/dist_ts/mail/delivery/smtpserver/secure-server.js +79 -0
- package/dist_ts/mail/delivery/smtpserver/security-handler.d.ts +86 -0
- package/dist_ts/mail/delivery/smtpserver/security-handler.js +234 -0
- package/dist_ts/mail/delivery/smtpserver/session-manager.d.ts +140 -0
- package/dist_ts/mail/delivery/smtpserver/session-manager.js +469 -0
- package/dist_ts/mail/delivery/smtpserver/smtp-server.d.ts +137 -0
- package/dist_ts/mail/delivery/smtpserver/smtp-server.js +666 -0
- package/dist_ts/mail/delivery/smtpserver/starttls-handler.d.ts +21 -0
- package/dist_ts/mail/delivery/smtpserver/starttls-handler.js +207 -0
- package/dist_ts/mail/delivery/smtpserver/tls-handler.d.ts +66 -0
- package/dist_ts/mail/delivery/smtpserver/tls-handler.js +261 -0
- package/dist_ts/mail/delivery/smtpserver/utils/adaptive-logging.d.ts +117 -0
- package/dist_ts/mail/delivery/smtpserver/utils/adaptive-logging.js +411 -0
- package/dist_ts/mail/delivery/smtpserver/utils/helpers.d.ts +78 -0
- package/dist_ts/mail/delivery/smtpserver/utils/helpers.js +208 -0
- package/dist_ts/mail/delivery/smtpserver/utils/logging.d.ts +106 -0
- package/dist_ts/mail/delivery/smtpserver/utils/logging.js +181 -0
- package/dist_ts/mail/delivery/smtpserver/utils/validation.d.ts +69 -0
- package/dist_ts/mail/delivery/smtpserver/utils/validation.js +360 -0
- package/dist_ts/mail/index.d.ts +8 -0
- package/dist_ts/mail/index.js +13 -0
- package/dist_ts/mail/routing/classes.dns.manager.d.ts +65 -0
- package/dist_ts/mail/routing/classes.dns.manager.js +413 -0
- package/dist_ts/mail/routing/classes.dnsmanager.d.ts +165 -0
- package/dist_ts/mail/routing/classes.dnsmanager.js +430 -0
- package/dist_ts/mail/routing/classes.domain.registry.d.ts +54 -0
- package/dist_ts/mail/routing/classes.domain.registry.js +118 -0
- package/dist_ts/mail/routing/classes.email.config.d.ts +64 -0
- package/dist_ts/mail/routing/classes.email.config.js +2 -0
- package/dist_ts/mail/routing/classes.email.router.d.ts +171 -0
- package/dist_ts/mail/routing/classes.email.router.js +491 -0
- package/dist_ts/mail/routing/classes.unified.email.server.d.ts +426 -0
- package/dist_ts/mail/routing/classes.unified.email.server.js +1454 -0
- package/dist_ts/mail/routing/index.d.ts +5 -0
- package/dist_ts/mail/routing/index.js +7 -0
- package/dist_ts/mail/routing/interfaces.d.ts +187 -0
- package/dist_ts/mail/routing/interfaces.js +2 -0
- package/dist_ts/mail/security/classes.dkimcreator.d.ts +68 -0
- package/dist_ts/mail/security/classes.dkimcreator.js +346 -0
- package/dist_ts/mail/security/classes.dkimverifier.d.ts +46 -0
- package/dist_ts/mail/security/classes.dkimverifier.js +317 -0
- package/dist_ts/mail/security/classes.dmarcverifier.d.ts +123 -0
- package/dist_ts/mail/security/classes.dmarcverifier.js +365 -0
- package/dist_ts/mail/security/classes.spfverifier.d.ts +103 -0
- package/dist_ts/mail/security/classes.spfverifier.js +492 -0
- package/dist_ts/mail/security/index.d.ts +4 -0
- package/dist_ts/mail/security/index.js +6 -0
- package/dist_ts/opsserver/classes.opsserver.d.ts +14 -0
- package/dist_ts/opsserver/classes.opsserver.js +37 -0
- package/dist_ts/opsserver/index.d.ts +1 -0
- package/dist_ts/opsserver/index.js +2 -0
- package/dist_ts/paths.d.ts +14 -0
- package/dist_ts/paths.js +39 -0
- package/dist_ts/plugins.d.ts +43 -0
- package/dist_ts/plugins.js +50 -0
- package/dist_ts/security/classes.contentscanner.d.ts +160 -0
- package/dist_ts/security/classes.contentscanner.js +634 -0
- package/dist_ts/security/classes.ipreputationchecker.d.ts +150 -0
- package/dist_ts/security/classes.ipreputationchecker.js +508 -0
- package/dist_ts/security/classes.securitylogger.d.ts +140 -0
- package/dist_ts/security/classes.securitylogger.js +232 -0
- package/dist_ts/security/index.d.ts +3 -0
- package/dist_ts/security/index.js +4 -0
- package/dist_ts/sms/classes.smsservice.d.ts +15 -0
- package/dist_ts/sms/classes.smsservice.js +72 -0
- package/dist_ts/sms/config/sms.config.d.ts +93 -0
- package/dist_ts/sms/config/sms.config.js +2 -0
- package/dist_ts/sms/config/sms.schema.d.ts +5 -0
- package/dist_ts/sms/config/sms.schema.js +121 -0
- package/dist_ts/sms/index.d.ts +1 -0
- package/dist_ts/sms/index.js +2 -0
- package/dist_ts/storage/classes.storagemanager.d.ts +82 -0
- package/dist_ts/storage/classes.storagemanager.js +341 -0
- package/dist_ts/storage/index.d.ts +1 -0
- package/dist_ts/storage/index.js +3 -0
- package/dist_ts/ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/ts/00_commitinfo_data.js +9 -0
- package/dist_ts/ts/classes.dcrouter.d.ts +238 -0
- package/dist_ts/ts/classes.dcrouter.js +1008 -0
- package/dist_ts/ts/config/index.d.ts +1 -0
- package/dist_ts/ts/config/index.js +3 -0
- package/dist_ts/ts/config/validator.d.ts +104 -0
- package/dist_ts/ts/config/validator.js +152 -0
- package/dist_ts/ts/deliverability/classes.ipwarmupmanager.d.ts +253 -0
- package/dist_ts/ts/deliverability/classes.ipwarmupmanager.js +639 -0
- package/dist_ts/ts/deliverability/classes.senderreputationmonitor.d.ts +300 -0
- package/dist_ts/ts/deliverability/classes.senderreputationmonitor.js +961 -0
- package/dist_ts/ts/deliverability/index.d.ts +2 -0
- package/dist_ts/ts/deliverability/index.js +3 -0
- package/dist_ts/ts/errors/base.errors.d.ts +224 -0
- package/dist_ts/ts/errors/base.errors.js +310 -0
- package/dist_ts/ts/errors/email.errors.d.ts +175 -0
- package/dist_ts/ts/errors/email.errors.js +265 -0
- package/dist_ts/ts/errors/error-handler.d.ts +98 -0
- package/dist_ts/ts/errors/error-handler.js +282 -0
- package/dist_ts/ts/errors/error.codes.d.ts +115 -0
- package/dist_ts/ts/errors/error.codes.js +136 -0
- package/dist_ts/ts/errors/index.d.ts +56 -0
- package/dist_ts/ts/errors/index.js +138 -0
- package/dist_ts/ts/errors/mta.errors.d.ts +259 -0
- package/dist_ts/ts/errors/mta.errors.js +472 -0
- package/dist_ts/ts/errors/reputation.errors.d.ts +183 -0
- package/dist_ts/ts/errors/reputation.errors.js +292 -0
- package/dist_ts/ts/index.d.ts +4 -0
- package/dist_ts/ts/index.js +6 -0
- package/dist_ts/ts/logger.d.ts +17 -0
- package/dist_ts/ts/logger.js +77 -0
- package/dist_ts/ts/mail/core/classes.bouncemanager.d.ts +200 -0
- package/dist_ts/ts/mail/core/classes.bouncemanager.js +778 -0
- package/dist_ts/ts/mail/core/classes.email.d.ts +291 -0
- package/dist_ts/ts/mail/core/classes.email.js +780 -0
- package/dist_ts/ts/mail/core/classes.emailvalidator.d.ts +61 -0
- package/dist_ts/ts/mail/core/classes.emailvalidator.js +182 -0
- package/dist_ts/ts/mail/core/classes.templatemanager.d.ts +95 -0
- package/dist_ts/ts/mail/core/classes.templatemanager.js +239 -0
- package/dist_ts/ts/mail/core/index.d.ts +4 -0
- package/dist_ts/ts/mail/core/index.js +6 -0
- package/dist_ts/ts/mail/delivery/classes.delivery.queue.d.ts +163 -0
- package/dist_ts/ts/mail/delivery/classes.delivery.queue.js +485 -0
- package/dist_ts/ts/mail/delivery/classes.delivery.system.d.ts +186 -0
- package/dist_ts/ts/mail/delivery/classes.delivery.system.js +846 -0
- package/dist_ts/ts/mail/delivery/classes.emailsendjob.d.ts +84 -0
- package/dist_ts/ts/mail/delivery/classes.emailsendjob.js +362 -0
- package/dist_ts/ts/mail/delivery/classes.emailsignjob.d.ts +18 -0
- package/dist_ts/ts/mail/delivery/classes.emailsignjob.js +44 -0
- package/dist_ts/ts/mail/delivery/classes.mta.config.d.ts +22 -0
- package/dist_ts/ts/mail/delivery/classes.mta.config.js +51 -0
- package/dist_ts/ts/mail/delivery/classes.ratelimiter.d.ts +98 -0
- package/dist_ts/ts/mail/delivery/classes.ratelimiter.js +205 -0
- package/dist_ts/ts/mail/delivery/classes.smtp.client.legacy.d.ts +275 -0
- package/dist_ts/ts/mail/delivery/classes.smtp.client.legacy.js +973 -0
- package/dist_ts/ts/mail/delivery/classes.unified.rate.limiter.d.ts +200 -0
- package/dist_ts/ts/mail/delivery/classes.unified.rate.limiter.js +817 -0
- package/dist_ts/ts/mail/delivery/index.d.ts +12 -0
- package/dist_ts/ts/mail/delivery/index.js +18 -0
- package/dist_ts/ts/mail/delivery/interfaces.d.ts +243 -0
- package/dist_ts/ts/mail/delivery/interfaces.js +17 -0
- package/dist_ts/ts/mail/delivery/smtpclient/auth-handler.d.ts +43 -0
- package/dist_ts/ts/mail/delivery/smtpclient/auth-handler.js +188 -0
- package/dist_ts/ts/mail/delivery/smtpclient/command-handler.d.ts +67 -0
- package/dist_ts/ts/mail/delivery/smtpclient/command-handler.js +276 -0
- package/dist_ts/ts/mail/delivery/smtpclient/connection-manager.d.ts +48 -0
- package/dist_ts/ts/mail/delivery/smtpclient/connection-manager.js +238 -0
- package/dist_ts/ts/mail/delivery/smtpclient/constants.d.ts +129 -0
- package/dist_ts/ts/mail/delivery/smtpclient/constants.js +135 -0
- package/dist_ts/ts/mail/delivery/smtpclient/create-client.d.ts +22 -0
- package/dist_ts/ts/mail/delivery/smtpclient/create-client.js +86 -0
- package/dist_ts/ts/mail/delivery/smtpclient/error-handler.d.ts +28 -0
- package/dist_ts/ts/mail/delivery/smtpclient/error-handler.js +110 -0
- package/dist_ts/ts/mail/delivery/smtpclient/index.d.ts +16 -0
- package/dist_ts/ts/mail/delivery/smtpclient/index.js +21 -0
- package/dist_ts/ts/mail/delivery/smtpclient/interfaces.d.ts +183 -0
- package/dist_ts/ts/mail/delivery/smtpclient/interfaces.js +19 -0
- package/dist_ts/ts/mail/delivery/smtpclient/smtp-client.d.ts +58 -0
- package/dist_ts/ts/mail/delivery/smtpclient/smtp-client.js +279 -0
- package/dist_ts/ts/mail/delivery/smtpclient/tls-handler.d.ts +33 -0
- package/dist_ts/ts/mail/delivery/smtpclient/tls-handler.js +202 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/helpers.d.ts +77 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/helpers.js +196 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/logging.d.ts +46 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/logging.js +153 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/validation.d.ts +38 -0
- package/dist_ts/ts/mail/delivery/smtpclient/utils/validation.js +139 -0
- package/dist_ts/ts/mail/delivery/smtpserver/certificate-utils.d.ts +45 -0
- package/dist_ts/ts/mail/delivery/smtpserver/certificate-utils.js +345 -0
- package/dist_ts/ts/mail/delivery/smtpserver/command-handler.d.ts +156 -0
- package/dist_ts/ts/mail/delivery/smtpserver/command-handler.js +1159 -0
- package/dist_ts/ts/mail/delivery/smtpserver/connection-manager.d.ts +159 -0
- package/dist_ts/ts/mail/delivery/smtpserver/connection-manager.js +894 -0
- package/dist_ts/ts/mail/delivery/smtpserver/constants.d.ts +130 -0
- package/dist_ts/ts/mail/delivery/smtpserver/constants.js +162 -0
- package/dist_ts/ts/mail/delivery/smtpserver/create-server.d.ts +14 -0
- package/dist_ts/ts/mail/delivery/smtpserver/create-server.js +28 -0
- package/dist_ts/ts/mail/delivery/smtpserver/data-handler.d.ts +123 -0
- package/dist_ts/ts/mail/delivery/smtpserver/data-handler.js +1148 -0
- package/dist_ts/ts/mail/delivery/smtpserver/index.d.ts +20 -0
- package/dist_ts/ts/mail/delivery/smtpserver/index.js +27 -0
- package/dist_ts/ts/mail/delivery/smtpserver/interfaces.d.ts +530 -0
- package/dist_ts/ts/mail/delivery/smtpserver/interfaces.js +10 -0
- package/dist_ts/ts/mail/delivery/smtpserver/secure-server.d.ts +15 -0
- package/dist_ts/ts/mail/delivery/smtpserver/secure-server.js +79 -0
- package/dist_ts/ts/mail/delivery/smtpserver/security-handler.d.ts +86 -0
- package/dist_ts/ts/mail/delivery/smtpserver/security-handler.js +234 -0
- package/dist_ts/ts/mail/delivery/smtpserver/session-manager.d.ts +140 -0
- package/dist_ts/ts/mail/delivery/smtpserver/session-manager.js +469 -0
- package/dist_ts/ts/mail/delivery/smtpserver/smtp-server.d.ts +137 -0
- package/dist_ts/ts/mail/delivery/smtpserver/smtp-server.js +666 -0
- package/dist_ts/ts/mail/delivery/smtpserver/starttls-handler.d.ts +21 -0
- package/dist_ts/ts/mail/delivery/smtpserver/starttls-handler.js +207 -0
- package/dist_ts/ts/mail/delivery/smtpserver/tls-handler.d.ts +66 -0
- package/dist_ts/ts/mail/delivery/smtpserver/tls-handler.js +261 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/adaptive-logging.d.ts +117 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/adaptive-logging.js +411 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/helpers.d.ts +78 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/helpers.js +208 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/logging.d.ts +106 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/logging.js +181 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/validation.d.ts +69 -0
- package/dist_ts/ts/mail/delivery/smtpserver/utils/validation.js +360 -0
- package/dist_ts/ts/mail/index.d.ts +8 -0
- package/dist_ts/ts/mail/index.js +13 -0
- package/dist_ts/ts/mail/routing/classes.dns.manager.d.ts +65 -0
- package/dist_ts/ts/mail/routing/classes.dns.manager.js +413 -0
- package/dist_ts/ts/mail/routing/classes.dnsmanager.d.ts +165 -0
- package/dist_ts/ts/mail/routing/classes.dnsmanager.js +430 -0
- package/dist_ts/ts/mail/routing/classes.domain.registry.d.ts +54 -0
- package/dist_ts/ts/mail/routing/classes.domain.registry.js +118 -0
- package/dist_ts/ts/mail/routing/classes.email.config.d.ts +64 -0
- package/dist_ts/ts/mail/routing/classes.email.config.js +2 -0
- package/dist_ts/ts/mail/routing/classes.email.router.d.ts +171 -0
- package/dist_ts/ts/mail/routing/classes.email.router.js +491 -0
- package/dist_ts/ts/mail/routing/classes.unified.email.server.d.ts +426 -0
- package/dist_ts/ts/mail/routing/classes.unified.email.server.js +1454 -0
- package/dist_ts/ts/mail/routing/index.d.ts +5 -0
- package/dist_ts/ts/mail/routing/index.js +7 -0
- package/dist_ts/ts/mail/routing/interfaces.d.ts +187 -0
- package/dist_ts/ts/mail/routing/interfaces.js +2 -0
- package/dist_ts/ts/mail/security/classes.dkimcreator.d.ts +68 -0
- package/dist_ts/ts/mail/security/classes.dkimcreator.js +346 -0
- package/dist_ts/ts/mail/security/classes.dkimverifier.d.ts +46 -0
- package/dist_ts/ts/mail/security/classes.dkimverifier.js +317 -0
- package/dist_ts/ts/mail/security/classes.dmarcverifier.d.ts +123 -0
- package/dist_ts/ts/mail/security/classes.dmarcverifier.js +365 -0
- package/dist_ts/ts/mail/security/classes.spfverifier.d.ts +103 -0
- package/dist_ts/ts/mail/security/classes.spfverifier.js +492 -0
- package/dist_ts/ts/mail/security/index.d.ts +4 -0
- package/dist_ts/ts/mail/security/index.js +6 -0
- package/dist_ts/ts/opsserver/classes.opsserver.d.ts +20 -0
- package/dist_ts/ts/opsserver/classes.opsserver.js +44 -0
- package/dist_ts/ts/opsserver/handlers/admin.handler.d.ts +31 -0
- package/dist_ts/ts/opsserver/handlers/admin.handler.js +177 -0
- package/dist_ts/ts/opsserver/handlers/config.handler.d.ts +10 -0
- package/dist_ts/ts/opsserver/handlers/config.handler.js +100 -0
- package/dist_ts/ts/opsserver/handlers/index.d.ts +5 -0
- package/dist_ts/ts/opsserver/handlers/index.js +6 -0
- package/dist_ts/ts/opsserver/handlers/logs.handler.d.ts +10 -0
- package/dist_ts/ts/opsserver/handlers/logs.handler.js +121 -0
- package/dist_ts/ts/opsserver/handlers/security.handler.d.ts +11 -0
- package/dist_ts/ts/opsserver/handlers/security.handler.js +118 -0
- package/dist_ts/ts/opsserver/handlers/stats.handler.d.ts +13 -0
- package/dist_ts/ts/opsserver/handlers/stats.handler.js +233 -0
- package/dist_ts/ts/opsserver/helpers/guards.d.ts +25 -0
- package/dist_ts/ts/opsserver/helpers/guards.js +41 -0
- package/dist_ts/ts/opsserver/index.d.ts +1 -0
- package/dist_ts/ts/opsserver/index.js +2 -0
- package/dist_ts/ts/paths.d.ts +14 -0
- package/dist_ts/ts/paths.js +39 -0
- package/dist_ts/ts/plugins.d.ts +46 -0
- package/dist_ts/ts/plugins.js +53 -0
- package/dist_ts/ts/security/classes.contentscanner.d.ts +160 -0
- package/dist_ts/ts/security/classes.contentscanner.js +634 -0
- package/dist_ts/ts/security/classes.ipreputationchecker.d.ts +150 -0
- package/dist_ts/ts/security/classes.ipreputationchecker.js +508 -0
- package/dist_ts/ts/security/classes.securitylogger.d.ts +140 -0
- package/dist_ts/ts/security/classes.securitylogger.js +232 -0
- package/dist_ts/ts/security/index.d.ts +3 -0
- package/dist_ts/ts/security/index.js +4 -0
- package/dist_ts/ts/sms/classes.smsservice.d.ts +15 -0
- package/dist_ts/ts/sms/classes.smsservice.js +72 -0
- package/dist_ts/ts/sms/config/sms.config.d.ts +93 -0
- package/dist_ts/ts/sms/config/sms.config.js +2 -0
- package/dist_ts/ts/sms/config/sms.schema.d.ts +5 -0
- package/dist_ts/ts/sms/config/sms.schema.js +121 -0
- package/dist_ts/ts/sms/index.d.ts +1 -0
- package/dist_ts/ts/sms/index.js +2 -0
- package/dist_ts/ts/storage/classes.storagemanager.d.ts +82 -0
- package/dist_ts/ts/storage/classes.storagemanager.js +341 -0
- package/dist_ts/ts/storage/index.d.ts +1 -0
- package/dist_ts/ts/storage/index.js +3 -0
- package/dist_ts/ts_interfaces/data/auth.d.ts +8 -0
- package/dist_ts/ts_interfaces/data/auth.js +2 -0
- package/dist_ts/ts_interfaces/data/index.d.ts +2 -0
- package/dist_ts/ts_interfaces/data/index.js +3 -0
- package/dist_ts/ts_interfaces/data/stats.d.ts +93 -0
- package/dist_ts/ts_interfaces/data/stats.js +2 -0
- package/dist_ts/ts_interfaces/index.d.ts +5 -0
- package/dist_ts/ts_interfaces/index.js +8 -0
- package/dist_ts/ts_interfaces/plugins.d.ts +2 -0
- package/dist_ts/ts_interfaces/plugins.js +4 -0
- package/dist_ts/ts_interfaces/requests/admin.d.ts +31 -0
- package/dist_ts/ts_interfaces/requests/admin.js +3 -0
- package/dist_ts/ts_interfaces/requests/config.d.ts +25 -0
- package/dist_ts/ts_interfaces/requests/config.js +3 -0
- package/dist_ts/ts_interfaces/requests/index.d.ts +4 -0
- package/dist_ts/ts_interfaces/requests/index.js +5 -0
- package/dist_ts/ts_interfaces/requests/logs.d.ts +34 -0
- package/dist_ts/ts_interfaces/requests/logs.js +4 -0
- package/dist_ts/ts_interfaces/requests/stats.d.ts +131 -0
- package/dist_ts/ts_interfaces/requests/stats.js +4 -0
- package/html/index.html +121 -0
- package/npmextra.json +45 -0
- package/package.json +83 -0
- package/readme.hints.md +906 -0
- package/readme.md +1253 -0
- package/readme.opsserver.md +351 -0
- package/test/helpers/server.loader.ts +347 -0
- package/test/helpers/smtp.client.ts +209 -0
- package/test/helpers/utils.ts +311 -0
- package/test/readme.md +443 -0
- package/test/suite/smtpclient_commands/test.ccmd-01.ehlo-helo-sending.ts +168 -0
- package/test/suite/smtpclient_commands/test.ccmd-02.mail-from-parameters.ts +277 -0
- package/test/suite/smtpclient_commands/test.ccmd-03.rcpt-to-multiple.ts +283 -0
- package/test/suite/smtpclient_commands/test.ccmd-04.data-transmission.ts +274 -0
- package/test/suite/smtpclient_commands/test.ccmd-05.auth-mechanisms.ts +306 -0
- package/test/suite/smtpclient_commands/test.ccmd-06.command-pipelining.ts +233 -0
- package/test/suite/smtpclient_commands/test.ccmd-07.response-parsing.ts +243 -0
- package/test/suite/smtpclient_commands/test.ccmd-08.rset-command.ts +333 -0
- package/test/suite/smtpclient_commands/test.ccmd-09.noop-command.ts +339 -0
- package/test/suite/smtpclient_commands/test.ccmd-10.vrfy-expn.ts +457 -0
- package/test/suite/smtpclient_commands/test.ccmd-11.help-command.ts +409 -0
- package/test/suite/smtpclient_connection/test.ccm-01.basic-tcp-connection.ts +150 -0
- package/test/suite/smtpclient_connection/test.ccm-02.tls-connection.ts +140 -0
- package/test/suite/smtpclient_connection/test.ccm-03.starttls-upgrade.ts +208 -0
- package/test/suite/smtpclient_connection/test.ccm-04.connection-pooling.ts +250 -0
- package/test/suite/smtpclient_connection/test.ccm-05.connection-reuse.ts +288 -0
- package/test/suite/smtpclient_connection/test.ccm-06.connection-timeout.ts +267 -0
- package/test/suite/smtpclient_connection/test.ccm-07.automatic-reconnection.ts +324 -0
- package/test/suite/smtpclient_connection/test.ccm-08.dns-resolution.ts +139 -0
- package/test/suite/smtpclient_connection/test.ccm-09.ipv6-dual-stack.ts +167 -0
- package/test/suite/smtpclient_connection/test.ccm-10.proxy-support.ts +305 -0
- package/test/suite/smtpclient_connection/test.ccm-11.keepalive.ts +299 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-01.unusual-server-responses.ts +529 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-02.malformed-commands.ts +438 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-03.protocol-violations.ts +446 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-04.resource-constraints.ts +530 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-05.encoding-issues.ts +145 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-06.large-headers.ts +180 -0
- package/test/suite/smtpclient_edge-cases/test.cedge-07.concurrent-operations.ts +204 -0
- package/test/suite/smtpclient_email-composition/test.cep-01.basic-headers.ts +245 -0
- package/test/suite/smtpclient_email-composition/test.cep-02.mime-multipart.ts +321 -0
- package/test/suite/smtpclient_email-composition/test.cep-03.attachment-encoding.ts +334 -0
- package/test/suite/smtpclient_email-composition/test.cep-04.bcc-handling.ts +187 -0
- package/test/suite/smtpclient_email-composition/test.cep-05.reply-to-return-path.ts +277 -0
- package/test/suite/smtpclient_email-composition/test.cep-06.utf8-international.ts +235 -0
- package/test/suite/smtpclient_email-composition/test.cep-07.html-inline-images.ts +489 -0
- package/test/suite/smtpclient_email-composition/test.cep-08.custom-headers.ts +293 -0
- package/test/suite/smtpclient_email-composition/test.cep-09.priority-importance.ts +314 -0
- package/test/suite/smtpclient_email-composition/test.cep-10.receipts-dsn.ts +411 -0
- package/test/suite/smtpclient_error-handling/test.cerr-01.4xx-errors.ts +232 -0
- package/test/suite/smtpclient_error-handling/test.cerr-02.5xx-errors.ts +309 -0
- package/test/suite/smtpclient_error-handling/test.cerr-03.network-failures.ts +299 -0
- package/test/suite/smtpclient_error-handling/test.cerr-04.greylisting-handling.ts +255 -0
- package/test/suite/smtpclient_error-handling/test.cerr-05.quota-exceeded.ts +273 -0
- package/test/suite/smtpclient_error-handling/test.cerr-06.invalid-recipients.ts +320 -0
- package/test/suite/smtpclient_error-handling/test.cerr-07.message-size-limits.ts +320 -0
- package/test/suite/smtpclient_error-handling/test.cerr-08.rate-limiting.ts +261 -0
- package/test/suite/smtpclient_error-handling/test.cerr-09.connection-pool-errors.ts +299 -0
- package/test/suite/smtpclient_error-handling/test.cerr-10.partial-failure.ts +373 -0
- package/test/suite/smtpclient_performance/test.cperf-01.bulk-sending.ts +332 -0
- package/test/suite/smtpclient_performance/test.cperf-02.message-throughput.ts +304 -0
- package/test/suite/smtpclient_performance/test.cperf-03.memory-usage.ts +332 -0
- package/test/suite/smtpclient_performance/test.cperf-04.cpu-utilization.ts +373 -0
- package/test/suite/smtpclient_performance/test.cperf-05.network-efficiency.ts +181 -0
- package/test/suite/smtpclient_performance/test.cperf-06.caching-strategies.ts +190 -0
- package/test/suite/smtpclient_performance/test.cperf-07.queue-management.ts +171 -0
- package/test/suite/smtpclient_performance/test.cperf-08.dns-caching.ts +50 -0
- package/test/suite/smtpclient_reliability/test.crel-01.reconnection-logic.ts +305 -0
- package/test/suite/smtpclient_reliability/test.crel-02.network-interruption.ts +207 -0
- package/test/suite/smtpclient_reliability/test.crel-03.queue-persistence.ts +469 -0
- package/test/suite/smtpclient_reliability/test.crel-04.crash-recovery.ts +520 -0
- package/test/suite/smtpclient_reliability/test.crel-05.memory-leaks.ts +503 -0
- package/test/suite/smtpclient_reliability/test.crel-06.concurrency-safety.ts +558 -0
- package/test/suite/smtpclient_reliability/test.crel-07.resource-cleanup.ts +52 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-01.rfc5321-client.ts +283 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-02.esmtp-compliance.ts +77 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-03.command-syntax.ts +67 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-04.response-codes.ts +54 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-05.state-machine.ts +703 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-06.protocol-negotiation.ts +688 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-07.interoperability.ts +728 -0
- package/test/suite/smtpclient_rfc-compliance/test.crfc-08.smtp-extensions.ts +656 -0
- package/test/suite/smtpclient_security/test.csec-01.tls-verification.ts +88 -0
- package/test/suite/smtpclient_security/test.csec-02.oauth2-authentication.ts +132 -0
- package/test/suite/smtpclient_security/test.csec-03.dkim-signing.ts +138 -0
- package/test/suite/smtpclient_security/test.csec-04.spf-compliance.ts +163 -0
- package/test/suite/smtpclient_security/test.csec-05.dmarc-policy.ts +200 -0
- package/test/suite/smtpclient_security/test.csec-06.certificate-validation.ts +145 -0
- package/test/suite/smtpclient_security/test.csec-07.cipher-suites.ts +153 -0
- package/test/suite/smtpclient_security/test.csec-08.authentication-fallback.ts +154 -0
- package/test/suite/smtpclient_security/test.csec-09.relay-restrictions.ts +166 -0
- package/test/suite/smtpclient_security/test.csec-10.anti-spam-measures.ts +196 -0
- package/test/suite/smtpserver_commands/test.cmd-01.ehlo-command.ts +193 -0
- package/test/suite/smtpserver_commands/test.cmd-02.mail-from.ts +330 -0
- package/test/suite/smtpserver_commands/test.cmd-03.rcpt-to.ts +296 -0
- package/test/suite/smtpserver_commands/test.cmd-04.data-command.ts +395 -0
- package/test/suite/smtpserver_commands/test.cmd-05.noop-command.ts +320 -0
- package/test/suite/smtpserver_commands/test.cmd-06.rset-command.ts +399 -0
- package/test/suite/smtpserver_commands/test.cmd-07.vrfy-command.ts +391 -0
- package/test/suite/smtpserver_commands/test.cmd-08.expn-command.ts +450 -0
- package/test/suite/smtpserver_commands/test.cmd-09.size-extension.ts +465 -0
- package/test/suite/smtpserver_commands/test.cmd-10.help-command.ts +454 -0
- package/test/suite/smtpserver_commands/test.cmd-11.command-pipelining.ts +334 -0
- package/test/suite/smtpserver_commands/test.cmd-12.helo-command.ts +420 -0
- package/test/suite/smtpserver_commands/test.cmd-13.quit-command.ts +384 -0
- package/test/suite/smtpserver_connection/test.cm-01.tls-connection.ts +61 -0
- package/test/suite/smtpserver_connection/test.cm-02.multiple-connections.ts +112 -0
- package/test/suite/smtpserver_connection/test.cm-03.connection-timeout.ts +134 -0
- package/test/suite/smtpserver_connection/test.cm-04.connection-limits.ts +374 -0
- package/test/suite/smtpserver_connection/test.cm-05.connection-rejection.ts +296 -0
- package/test/suite/smtpserver_connection/test.cm-06.starttls-upgrade.ts +468 -0
- package/test/suite/smtpserver_connection/test.cm-07.abrupt-disconnection.ts +321 -0
- package/test/suite/smtpserver_connection/test.cm-08.tls-versions.ts +361 -0
- package/test/suite/smtpserver_connection/test.cm-09.tls-ciphers.ts +556 -0
- package/test/suite/smtpserver_connection/test.cm-10.plain-connection.ts +293 -0
- package/test/suite/smtpserver_connection/test.cm-11.keepalive.ts +382 -0
- package/test/suite/smtpserver_edge-cases/test.edge-01.very-large-email.ts +239 -0
- package/test/suite/smtpserver_edge-cases/test.edge-02.very-small-email.ts +389 -0
- package/test/suite/smtpserver_edge-cases/test.edge-03.invalid-character-handling.ts +479 -0
- package/test/suite/smtpserver_edge-cases/test.edge-04.empty-commands.ts +430 -0
- package/test/suite/smtpserver_edge-cases/test.edge-05.extremely-long-lines.ts +425 -0
- package/test/suite/smtpserver_edge-cases/test.edge-06.extremely-long-headers.ts +404 -0
- package/test/suite/smtpserver_edge-cases/test.edge-07.unusual-mime-types.ts +333 -0
- package/test/suite/smtpserver_edge-cases/test.edge-08.nested-mime-structures.ts +379 -0
- package/test/suite/smtpserver_email-processing/test.ep-01.basic-email-sending.ts +338 -0
- package/test/suite/smtpserver_email-processing/test.ep-02.invalid-email-addresses.ts +315 -0
- package/test/suite/smtpserver_email-processing/test.ep-03.multiple-recipients.ts +493 -0
- package/test/suite/smtpserver_email-processing/test.ep-04.large-email.ts +528 -0
- package/test/suite/smtpserver_email-processing/test.ep-05.mime-handling.ts +515 -0
- package/test/suite/smtpserver_email-processing/test.ep-06.attachment-handling.ts +629 -0
- package/test/suite/smtpserver_email-processing/test.ep-07.special-character-handling.ts +462 -0
- package/test/suite/smtpserver_email-processing/test.ep-08.email-routing.ts +527 -0
- package/test/suite/smtpserver_email-processing/test.ep-09.delivery-status-notifications.ts +486 -0
- package/test/suite/smtpserver_error-handling/test.err-01.syntax-errors.ts +475 -0
- package/test/suite/smtpserver_error-handling/test.err-02.invalid-sequence.ts +450 -0
- package/test/suite/smtpserver_error-handling/test.err-03.temporary-failures.ts +453 -0
- package/test/suite/smtpserver_error-handling/test.err-04.permanent-failures.ts +325 -0
- package/test/suite/smtpserver_error-handling/test.err-05.resource-exhaustion.ts +302 -0
- package/test/suite/smtpserver_error-handling/test.err-06.malformed-mime.ts +374 -0
- package/test/suite/smtpserver_error-handling/test.err-07.exception-handling.ts +333 -0
- package/test/suite/smtpserver_error-handling/test.err-08.error-logging.ts +324 -0
- package/test/suite/smtpserver_performance/test.perf-01.throughput.ts +183 -0
- package/test/suite/smtpserver_performance/test.perf-02.concurrency.ts +388 -0
- package/test/suite/smtpserver_performance/test.perf-03.cpu-utilization.ts +245 -0
- package/test/suite/smtpserver_performance/test.perf-04.memory-usage.ts +238 -0
- package/test/suite/smtpserver_performance/test.perf-05.connection-processing-time.ts +363 -0
- package/test/suite/smtpserver_performance/test.perf-06.message-processing-time.ts +252 -0
- package/test/suite/smtpserver_performance/test.perf-07.resource-cleanup.ts +317 -0
- package/test/suite/smtpserver_reliability/test.rel-01.long-running-operation.ts +344 -0
- package/test/suite/smtpserver_reliability/test.rel-02.restart-recovery.ts +328 -0
- package/test/suite/smtpserver_reliability/test.rel-03.resource-leak-detection.ts +394 -0
- package/test/suite/smtpserver_reliability/test.rel-04.error-recovery.ts +401 -0
- package/test/suite/smtpserver_reliability/test.rel-05.dns-resolution-failure.ts +335 -0
- package/test/suite/smtpserver_reliability/test.rel-06.network-interruption.ts +410 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-01.rfc5321-compliance.ts +382 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-02.rfc5322-compliance.ts +428 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-03.rfc7208-spf-compliance.ts +330 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-04.rfc6376-dkim-compliance.ts +450 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-05.rfc7489-dmarc-compliance.ts +408 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-06.rfc8314-tls-compliance.ts +366 -0
- package/test/suite/smtpserver_rfc-compliance/test.rfc-07.rfc3461-dsn-compliance.ts +399 -0
- package/test/suite/smtpserver_security/test.sec-01.authentication.ts +218 -0
- package/test/suite/smtpserver_security/test.sec-02.authorization.ts +286 -0
- package/test/suite/smtpserver_security/test.sec-03.dkim-processing.ts +414 -0
- package/test/suite/smtpserver_security/test.sec-04.spf-checking.ts +280 -0
- package/test/suite/smtpserver_security/test.sec-05.dmarc-policy.ts +374 -0
- package/test/suite/smtpserver_security/test.sec-06.ip-reputation.ts +303 -0
- package/test/suite/smtpserver_security/test.sec-07.content-scanning.ts +409 -0
- package/test/suite/smtpserver_security/test.sec-08.rate-limiting.ts +324 -0
- package/test/suite/smtpserver_security/test.sec-09.tls-certificate-validation.ts +312 -0
- package/test/suite/smtpserver_security/test.sec-10.header-injection-prevention.ts +332 -0
- package/test/suite/smtpserver_security/test.sec-11.bounce-management.ts +363 -0
- package/test/test.base.ts +65 -0
- package/test/test.bouncemanager.ts +196 -0
- package/test/test.config.md +175 -0
- package/test/test.contentscanner.ts +265 -0
- package/test/test.dcrouter.email.ts +201 -0
- package/test/test.deliverability.ts +55 -0
- package/test/test.dns-manager-creation.ts +141 -0
- package/test/test.dns-mode-switching.ts +257 -0
- package/test/test.dns-server-config.ts +140 -0
- package/test/test.dns-socket-handler.ts +169 -0
- package/test/test.dns-validation.ts +283 -0
- package/test/test.email-socket-handler.ts +228 -0
- package/test/test.email.integration.ts +377 -0
- package/test/test.email.router.ts +283 -0
- package/test/test.emailauth.ts +195 -0
- package/test/test.errors.ts +408 -0
- package/test/test.integration.storage.ts +313 -0
- package/test/test.integration.ts +75 -0
- package/test/test.ipreputationchecker.ts +179 -0
- package/test/test.ipwarmupmanager.ts +323 -0
- package/test/test.jwt-auth.ts +130 -0
- package/test/test.minimal.ts +66 -0
- package/test/test.opsserver-api.ts +83 -0
- package/test/test.protected-endpoint.ts +115 -0
- package/test/test.rate-limiting-integration.ts +236 -0
- package/test/test.ratelimiter.ts +141 -0
- package/test/test.reputationmonitor.ts +262 -0
- package/test/test.smartmail.ts +248 -0
- package/test/test.smtp.client.compatibility.ts +154 -0
- package/test/test.smtp.client.ts +191 -0
- package/test/test.smtp.server.ts +180 -0
- package/test/test.socket-handler-integration.ts +240 -0
- package/test/test.socket-handler-unit.ts +198 -0
- package/test/test.storagemanager.ts +289 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/classes.dcrouter.ts +1310 -0
- package/ts/config/index.ts +2 -0
- package/ts/config/validator.ts +266 -0
- package/ts/deliverability/classes.ipwarmupmanager.ts +896 -0
- package/ts/deliverability/classes.senderreputationmonitor.ts +1244 -0
- package/ts/deliverability/index.ts +13 -0
- package/ts/errors/base.errors.ts +525 -0
- package/ts/errors/email.errors.ts +383 -0
- package/ts/errors/error-handler.ts +412 -0
- package/ts/errors/error.codes.ts +165 -0
- package/ts/errors/index.ts +195 -0
- package/ts/errors/mta.errors.ts +681 -0
- package/ts/errors/reputation.errors.ts +422 -0
- package/ts/index.ts +7 -0
- package/ts/logger.ts +91 -0
- package/ts/mail/core/classes.bouncemanager.ts +965 -0
- package/ts/mail/core/classes.email.ts +941 -0
- package/ts/mail/core/classes.emailvalidator.ts +239 -0
- package/ts/mail/core/classes.templatemanager.ts +320 -0
- package/ts/mail/core/index.ts +5 -0
- package/ts/mail/delivery/classes.delivery.queue.ts +645 -0
- package/ts/mail/delivery/classes.delivery.system.ts +1089 -0
- package/ts/mail/delivery/classes.emailsendjob.ts +447 -0
- package/ts/mail/delivery/classes.emailsendjob.ts.backup +691 -0
- package/ts/mail/delivery/classes.emailsignjob.ts +67 -0
- package/ts/mail/delivery/classes.mta.config.ts +73 -0
- package/ts/mail/delivery/classes.ratelimiter.ts +281 -0
- package/ts/mail/delivery/classes.smtp.client.legacy.ts +1422 -0
- package/ts/mail/delivery/classes.unified.rate.limiter.ts +1053 -0
- package/ts/mail/delivery/index.ts +24 -0
- package/ts/mail/delivery/interfaces.ts +291 -0
- package/ts/mail/delivery/smtpclient/auth-handler.ts +232 -0
- package/ts/mail/delivery/smtpclient/command-handler.ts +343 -0
- package/ts/mail/delivery/smtpclient/connection-manager.ts +289 -0
- package/ts/mail/delivery/smtpclient/constants.ts +145 -0
- package/ts/mail/delivery/smtpclient/create-client.ts +94 -0
- package/ts/mail/delivery/smtpclient/error-handler.ts +141 -0
- package/ts/mail/delivery/smtpclient/index.ts +24 -0
- package/ts/mail/delivery/smtpclient/interfaces.ts +242 -0
- package/ts/mail/delivery/smtpclient/smtp-client.ts +357 -0
- package/ts/mail/delivery/smtpclient/tls-handler.ts +254 -0
- package/ts/mail/delivery/smtpclient/utils/helpers.ts +224 -0
- package/ts/mail/delivery/smtpclient/utils/logging.ts +212 -0
- package/ts/mail/delivery/smtpclient/utils/validation.ts +170 -0
- package/ts/mail/delivery/smtpserver/certificate-utils.ts +398 -0
- package/ts/mail/delivery/smtpserver/command-handler.ts +1340 -0
- package/ts/mail/delivery/smtpserver/connection-manager.ts +1045 -0
- package/ts/mail/delivery/smtpserver/constants.ts +181 -0
- package/ts/mail/delivery/smtpserver/create-server.ts +31 -0
- package/ts/mail/delivery/smtpserver/data-handler.ts +1283 -0
- package/ts/mail/delivery/smtpserver/index.ts +32 -0
- package/ts/mail/delivery/smtpserver/interfaces.ts +655 -0
- package/ts/mail/delivery/smtpserver/secure-server.ts +97 -0
- package/ts/mail/delivery/smtpserver/security-handler.ts +345 -0
- package/ts/mail/delivery/smtpserver/session-manager.ts +557 -0
- package/ts/mail/delivery/smtpserver/smtp-server.ts +804 -0
- package/ts/mail/delivery/smtpserver/starttls-handler.ts +262 -0
- package/ts/mail/delivery/smtpserver/tls-handler.ts +346 -0
- package/ts/mail/delivery/smtpserver/utils/adaptive-logging.ts +514 -0
- package/ts/mail/delivery/smtpserver/utils/helpers.ts +246 -0
- package/ts/mail/delivery/smtpserver/utils/logging.ts +246 -0
- package/ts/mail/delivery/smtpserver/utils/validation.ts +436 -0
- package/ts/mail/index.ts +19 -0
- package/ts/mail/routing/classes.dns.manager.ts +563 -0
- package/ts/mail/routing/classes.dnsmanager.ts +559 -0
- package/ts/mail/routing/classes.domain.registry.ts +139 -0
- package/ts/mail/routing/classes.email.config.ts +82 -0
- package/ts/mail/routing/classes.email.router.ts +575 -0
- package/ts/mail/routing/classes.unified.email.server.ts +1873 -0
- package/ts/mail/routing/index.ts +6 -0
- package/ts/mail/routing/interfaces.ts +202 -0
- package/ts/mail/security/classes.dkimcreator.ts +431 -0
- package/ts/mail/security/classes.dkimverifier.ts +382 -0
- package/ts/mail/security/classes.dmarcverifier.ts +478 -0
- package/ts/mail/security/classes.spfverifier.ts +606 -0
- package/ts/mail/security/index.ts +5 -0
- package/ts/opsserver/classes.opsserver.ts +65 -0
- package/ts/opsserver/handlers/admin.handler.ts +240 -0
- package/ts/opsserver/handlers/config.handler.ts +150 -0
- package/ts/opsserver/handlers/index.ts +5 -0
- package/ts/opsserver/handlers/logs.handler.ts +195 -0
- package/ts/opsserver/handlers/security.handler.ts +208 -0
- package/ts/opsserver/handlers/stats.handler.ts +344 -0
- package/ts/opsserver/helpers/guards.ts +56 -0
- package/ts/opsserver/index.ts +1 -0
- package/ts/paths.ts +48 -0
- package/ts/plugins.ts +94 -0
- package/ts/security/classes.contentscanner.ts +739 -0
- package/ts/security/classes.ipreputationchecker.ts +592 -0
- package/ts/security/classes.securitylogger.ts +299 -0
- package/ts/security/index.ts +21 -0
- package/ts/sms/classes.smsservice.ts +98 -0
- package/ts/sms/config/sms.config.ts +109 -0
- package/ts/sms/config/sms.schema.ts +122 -0
- package/ts/sms/index.ts +1 -0
- package/ts/storage/classes.storagemanager.ts +400 -0
- package/ts/storage/index.ts +2 -0
- package/ts/tspublish.json +3 -0
- package/ts_interfaces/data/auth.ts +8 -0
- package/ts_interfaces/data/index.ts +2 -0
- package/ts_interfaces/data/stats.ts +101 -0
- package/ts_interfaces/index.ts +9 -0
- package/ts_interfaces/plugins.ts +6 -0
- package/ts_interfaces/requests/admin.ts +46 -0
- package/ts_interfaces/requests/config.ts +35 -0
- package/ts_interfaces/requests/index.ts +4 -0
- package/ts_interfaces/requests/logs.ts +44 -0
- package/ts_interfaces/requests/stats.ts +162 -0
- package/ts_interfaces/tspublish.json +3 -0
- package/ts_web/00_commitinfo_data.ts +8 -0
- package/ts_web/appstate.ts +361 -0
- package/ts_web/elements/index.ts +7 -0
- package/ts_web/elements/ops-dashboard.ts +165 -0
- package/ts_web/elements/ops-view-config.ts +268 -0
- package/ts_web/elements/ops-view-logs.ts +207 -0
- package/ts_web/elements/ops-view-overview.ts +222 -0
- package/ts_web/elements/ops-view-security.ts +471 -0
- package/ts_web/elements/ops-view-stats.ts +299 -0
- package/ts_web/elements/shared/css.ts +10 -0
- package/ts_web/elements/shared/index.ts +2 -0
- package/ts_web/elements/shared/ops-sectionheading.ts +42 -0
- package/ts_web/index.ts +9 -0
- package/ts_web/plugins.ts +11 -0
- package/ts_web/tspublish.json +3 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,894 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMTP Connection Manager
|
|
3
|
+
* Responsible for managing socket connections to the SMTP server
|
|
4
|
+
*/
|
|
5
|
+
import * as plugins from '../../../plugins.js';
|
|
6
|
+
import { SmtpResponseCode, SMTP_DEFAULTS, SmtpState } from './constants.js';
|
|
7
|
+
import { SmtpLogger } from './utils/logging.js';
|
|
8
|
+
import { adaptiveLogger } from './utils/adaptive-logging.js';
|
|
9
|
+
import { getSocketDetails, formatMultilineResponse } from './utils/helpers.js';
|
|
10
|
+
/**
|
|
11
|
+
* Manager for SMTP connections
|
|
12
|
+
* Handles connection setup, event listeners, and lifecycle management
|
|
13
|
+
* Provides resource management, connection tracking, and monitoring
|
|
14
|
+
*/
|
|
15
|
+
export class ConnectionManager {
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new connection manager with enhanced resource management
|
|
18
|
+
* @param smtpServer - SMTP server instance
|
|
19
|
+
*/
|
|
20
|
+
constructor(smtpServer) {
|
|
21
|
+
/**
|
|
22
|
+
* Set of active socket connections
|
|
23
|
+
*/
|
|
24
|
+
this.activeConnections = new Set();
|
|
25
|
+
/**
|
|
26
|
+
* Connection tracking for resource management
|
|
27
|
+
*/
|
|
28
|
+
this.connectionStats = {
|
|
29
|
+
totalConnections: 0,
|
|
30
|
+
activeConnections: 0,
|
|
31
|
+
peakConnections: 0,
|
|
32
|
+
rejectedConnections: 0,
|
|
33
|
+
closedConnections: 0,
|
|
34
|
+
erroredConnections: 0,
|
|
35
|
+
timedOutConnections: 0
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Per-IP connection tracking for rate limiting
|
|
39
|
+
*/
|
|
40
|
+
this.ipConnections = new Map();
|
|
41
|
+
/**
|
|
42
|
+
* Resource monitoring interval
|
|
43
|
+
*/
|
|
44
|
+
this.resourceCheckInterval = null;
|
|
45
|
+
/**
|
|
46
|
+
* Track cleanup timers so we can clear them
|
|
47
|
+
*/
|
|
48
|
+
this.cleanupTimers = new Set();
|
|
49
|
+
this.smtpServer = smtpServer;
|
|
50
|
+
// Get options from server
|
|
51
|
+
const serverOptions = this.smtpServer.getOptions();
|
|
52
|
+
// Default values for resource management - adjusted for production scalability
|
|
53
|
+
const DEFAULT_MAX_CONNECTIONS_PER_IP = 50; // Increased to support high-concurrency scenarios
|
|
54
|
+
const DEFAULT_CONNECTION_RATE_LIMIT = 200; // Increased for production load handling
|
|
55
|
+
const DEFAULT_CONNECTION_RATE_WINDOW = 60 * 1000; // 60 seconds window
|
|
56
|
+
const DEFAULT_BUFFER_SIZE_LIMIT = 10 * 1024 * 1024; // 10 MB
|
|
57
|
+
const DEFAULT_RESOURCE_CHECK_INTERVAL = 30 * 1000; // 30 seconds
|
|
58
|
+
this.options = {
|
|
59
|
+
hostname: serverOptions.hostname || SMTP_DEFAULTS.HOSTNAME,
|
|
60
|
+
maxConnections: serverOptions.maxConnections || SMTP_DEFAULTS.MAX_CONNECTIONS,
|
|
61
|
+
socketTimeout: serverOptions.socketTimeout || SMTP_DEFAULTS.SOCKET_TIMEOUT,
|
|
62
|
+
maxConnectionsPerIP: DEFAULT_MAX_CONNECTIONS_PER_IP,
|
|
63
|
+
connectionRateLimit: DEFAULT_CONNECTION_RATE_LIMIT,
|
|
64
|
+
connectionRateWindow: DEFAULT_CONNECTION_RATE_WINDOW,
|
|
65
|
+
bufferSizeLimit: DEFAULT_BUFFER_SIZE_LIMIT,
|
|
66
|
+
resourceCheckInterval: DEFAULT_RESOURCE_CHECK_INTERVAL
|
|
67
|
+
};
|
|
68
|
+
// Start resource monitoring
|
|
69
|
+
this.startResourceMonitoring();
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Start resource monitoring interval to check resource usage
|
|
73
|
+
*/
|
|
74
|
+
startResourceMonitoring() {
|
|
75
|
+
// Clear any existing interval
|
|
76
|
+
if (this.resourceCheckInterval) {
|
|
77
|
+
clearInterval(this.resourceCheckInterval);
|
|
78
|
+
}
|
|
79
|
+
// Set up new interval
|
|
80
|
+
this.resourceCheckInterval = setInterval(() => {
|
|
81
|
+
this.monitorResourceUsage();
|
|
82
|
+
}, this.options.resourceCheckInterval);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Monitor resource usage and log statistics
|
|
86
|
+
*/
|
|
87
|
+
monitorResourceUsage() {
|
|
88
|
+
// Calculate memory usage
|
|
89
|
+
const memoryUsage = process.memoryUsage();
|
|
90
|
+
const memoryUsageMB = {
|
|
91
|
+
rss: Math.round(memoryUsage.rss / 1024 / 1024),
|
|
92
|
+
heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024),
|
|
93
|
+
heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024),
|
|
94
|
+
external: Math.round(memoryUsage.external / 1024 / 1024)
|
|
95
|
+
};
|
|
96
|
+
// Calculate connection rate metrics
|
|
97
|
+
const activeIPs = Array.from(this.ipConnections.entries())
|
|
98
|
+
.filter(([_, data]) => data.count > 0).length;
|
|
99
|
+
const highVolumeIPs = Array.from(this.ipConnections.entries())
|
|
100
|
+
.filter(([_, data]) => data.count > this.options.connectionRateLimit / 2).length;
|
|
101
|
+
// Log resource usage with more detailed metrics
|
|
102
|
+
SmtpLogger.info('Resource usage stats', {
|
|
103
|
+
connections: {
|
|
104
|
+
active: this.activeConnections.size,
|
|
105
|
+
total: this.connectionStats.totalConnections,
|
|
106
|
+
peak: this.connectionStats.peakConnections,
|
|
107
|
+
rejected: this.connectionStats.rejectedConnections,
|
|
108
|
+
closed: this.connectionStats.closedConnections,
|
|
109
|
+
errored: this.connectionStats.erroredConnections,
|
|
110
|
+
timedOut: this.connectionStats.timedOutConnections
|
|
111
|
+
},
|
|
112
|
+
memory: memoryUsageMB,
|
|
113
|
+
ipTracking: {
|
|
114
|
+
uniqueIPs: this.ipConnections.size,
|
|
115
|
+
activeIPs: activeIPs,
|
|
116
|
+
highVolumeIPs: highVolumeIPs
|
|
117
|
+
},
|
|
118
|
+
resourceLimits: {
|
|
119
|
+
maxConnections: this.options.maxConnections,
|
|
120
|
+
maxConnectionsPerIP: this.options.maxConnectionsPerIP,
|
|
121
|
+
connectionRateLimit: this.options.connectionRateLimit,
|
|
122
|
+
bufferSizeLimit: Math.round(this.options.bufferSizeLimit / 1024 / 1024) + 'MB'
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
// Check for potential DoS conditions
|
|
126
|
+
if (highVolumeIPs > 3) {
|
|
127
|
+
SmtpLogger.warn(`Potential DoS detected: ${highVolumeIPs} IPs with high connection rates`);
|
|
128
|
+
}
|
|
129
|
+
// Assess memory usage trends
|
|
130
|
+
if (memoryUsageMB.heapUsed > 500) { // Over 500MB heap used
|
|
131
|
+
SmtpLogger.warn(`High memory usage detected: ${memoryUsageMB.heapUsed}MB heap used`);
|
|
132
|
+
}
|
|
133
|
+
// Clean up expired IP rate limits and validate resource tracking
|
|
134
|
+
this.cleanupIpRateLimits();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Clean up expired IP rate limits and perform additional resource monitoring
|
|
138
|
+
*/
|
|
139
|
+
cleanupIpRateLimits() {
|
|
140
|
+
const now = Date.now();
|
|
141
|
+
const windowThreshold = now - this.options.connectionRateWindow;
|
|
142
|
+
let activeIps = 0;
|
|
143
|
+
let removedEntries = 0;
|
|
144
|
+
// Iterate through IP connections and manage entries
|
|
145
|
+
for (const [ip, data] of this.ipConnections.entries()) {
|
|
146
|
+
// If the last connection was before the window threshold + one extra window, remove the entry
|
|
147
|
+
if (data.lastConnection < windowThreshold - this.options.connectionRateWindow) {
|
|
148
|
+
// Remove stale entries to prevent memory growth
|
|
149
|
+
this.ipConnections.delete(ip);
|
|
150
|
+
removedEntries++;
|
|
151
|
+
}
|
|
152
|
+
// If last connection was before the window threshold, reset the count
|
|
153
|
+
else if (data.lastConnection < windowThreshold) {
|
|
154
|
+
if (data.count > 0) {
|
|
155
|
+
// Reset but keep the IP in the map with a zero count
|
|
156
|
+
this.ipConnections.set(ip, {
|
|
157
|
+
count: 0,
|
|
158
|
+
firstConnection: now,
|
|
159
|
+
lastConnection: now
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// This IP is still active within the current window
|
|
165
|
+
activeIps++;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Log cleanup activity if significant changes occurred
|
|
169
|
+
if (removedEntries > 0) {
|
|
170
|
+
SmtpLogger.debug(`IP rate limit cleanup: removed ${removedEntries} stale entries, ${this.ipConnections.size} remaining, ${activeIps} active in current window`);
|
|
171
|
+
}
|
|
172
|
+
// Check for memory leaks in connection tracking
|
|
173
|
+
if (this.activeConnections.size > 0 && this.connectionStats.activeConnections !== this.activeConnections.size) {
|
|
174
|
+
SmtpLogger.warn(`Connection tracking inconsistency detected: stats.active=${this.connectionStats.activeConnections}, actual=${this.activeConnections.size}`);
|
|
175
|
+
// Fix the inconsistency
|
|
176
|
+
this.connectionStats.activeConnections = this.activeConnections.size;
|
|
177
|
+
}
|
|
178
|
+
// Validate and clean leaked resources if needed
|
|
179
|
+
this.validateResourceTracking();
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Validate and repair resource tracking to prevent leaks
|
|
183
|
+
*/
|
|
184
|
+
validateResourceTracking() {
|
|
185
|
+
// Prepare a detailed report if inconsistencies are found
|
|
186
|
+
const inconsistenciesFound = [];
|
|
187
|
+
// 1. Check active connections count matches activeConnections set size
|
|
188
|
+
if (this.connectionStats.activeConnections !== this.activeConnections.size) {
|
|
189
|
+
inconsistenciesFound.push({
|
|
190
|
+
issue: 'Active connection count mismatch',
|
|
191
|
+
stats: this.connectionStats.activeConnections,
|
|
192
|
+
actual: this.activeConnections.size,
|
|
193
|
+
action: 'Auto-corrected'
|
|
194
|
+
});
|
|
195
|
+
this.connectionStats.activeConnections = this.activeConnections.size;
|
|
196
|
+
}
|
|
197
|
+
// 2. Check for destroyed sockets in active connections
|
|
198
|
+
let destroyedSocketsCount = 0;
|
|
199
|
+
for (const socket of this.activeConnections) {
|
|
200
|
+
if (socket.destroyed) {
|
|
201
|
+
destroyedSocketsCount++;
|
|
202
|
+
// This should not happen - remove destroyed sockets from tracking
|
|
203
|
+
this.activeConnections.delete(socket);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (destroyedSocketsCount > 0) {
|
|
207
|
+
inconsistenciesFound.push({
|
|
208
|
+
issue: 'Destroyed sockets in active list',
|
|
209
|
+
count: destroyedSocketsCount,
|
|
210
|
+
action: 'Removed from tracking'
|
|
211
|
+
});
|
|
212
|
+
// Update active connections count after cleanup
|
|
213
|
+
this.connectionStats.activeConnections = this.activeConnections.size;
|
|
214
|
+
}
|
|
215
|
+
// 3. Check for sessions without corresponding active connections
|
|
216
|
+
const sessionCount = this.smtpServer.getSessionManager().getSessionCount();
|
|
217
|
+
if (sessionCount > this.activeConnections.size) {
|
|
218
|
+
inconsistenciesFound.push({
|
|
219
|
+
issue: 'Orphaned sessions',
|
|
220
|
+
sessions: sessionCount,
|
|
221
|
+
connections: this.activeConnections.size,
|
|
222
|
+
action: 'Session cleanup recommended'
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
// If any inconsistencies found, log a detailed report
|
|
226
|
+
if (inconsistenciesFound.length > 0) {
|
|
227
|
+
SmtpLogger.warn('Resource tracking inconsistencies detected and repaired', { inconsistencies: inconsistenciesFound });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Handle a new connection with resource management
|
|
232
|
+
* @param socket - Client socket
|
|
233
|
+
*/
|
|
234
|
+
async handleNewConnection(socket) {
|
|
235
|
+
// Update connection stats
|
|
236
|
+
this.connectionStats.totalConnections++;
|
|
237
|
+
this.connectionStats.activeConnections = this.activeConnections.size + 1;
|
|
238
|
+
if (this.connectionStats.activeConnections > this.connectionStats.peakConnections) {
|
|
239
|
+
this.connectionStats.peakConnections = this.connectionStats.activeConnections;
|
|
240
|
+
}
|
|
241
|
+
// Get client IP
|
|
242
|
+
const remoteAddress = socket.remoteAddress || '0.0.0.0';
|
|
243
|
+
// Use UnifiedRateLimiter for connection rate limiting
|
|
244
|
+
const emailServer = this.smtpServer.getEmailServer();
|
|
245
|
+
const rateLimiter = emailServer.getRateLimiter();
|
|
246
|
+
// Check connection limit with UnifiedRateLimiter
|
|
247
|
+
const connectionResult = rateLimiter.recordConnection(remoteAddress);
|
|
248
|
+
if (!connectionResult.allowed) {
|
|
249
|
+
this.rejectConnection(socket, connectionResult.reason || 'Rate limit exceeded');
|
|
250
|
+
this.connectionStats.rejectedConnections++;
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
// Still track IP connections locally for cleanup purposes
|
|
254
|
+
this.trackIPConnection(remoteAddress);
|
|
255
|
+
// Check if maximum global connections reached
|
|
256
|
+
if (this.hasReachedMaxConnections()) {
|
|
257
|
+
this.rejectConnection(socket, 'Too many connections');
|
|
258
|
+
this.connectionStats.rejectedConnections++;
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
// Add socket to active connections
|
|
262
|
+
this.activeConnections.add(socket);
|
|
263
|
+
// Set up socket options
|
|
264
|
+
socket.setKeepAlive(true);
|
|
265
|
+
socket.setTimeout(this.options.socketTimeout);
|
|
266
|
+
// Explicitly set socket buffer sizes to prevent memory issues
|
|
267
|
+
socket.setNoDelay(true); // Disable Nagle's algorithm for better responsiveness
|
|
268
|
+
// Set limits on socket buffer size if supported by Node.js version
|
|
269
|
+
try {
|
|
270
|
+
// Here we set reasonable buffer limits to prevent memory exhaustion attacks
|
|
271
|
+
const highWaterMark = 64 * 1024; // 64 KB
|
|
272
|
+
// Note: Socket high water mark methods can't be set directly in newer Node.js versions
|
|
273
|
+
// These would need to be set during socket creation or with a different API
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
// Ignore errors from older Node.js versions that don't support these methods
|
|
277
|
+
SmtpLogger.debug(`Could not set socket buffer limits: ${error instanceof Error ? error.message : String(error)}`);
|
|
278
|
+
}
|
|
279
|
+
// Track this IP connection
|
|
280
|
+
this.trackIPConnection(remoteAddress);
|
|
281
|
+
// Set up event handlers
|
|
282
|
+
this.setupSocketEventHandlers(socket);
|
|
283
|
+
// Create a session for this connection
|
|
284
|
+
this.smtpServer.getSessionManager().createSession(socket, false);
|
|
285
|
+
// Log the new connection using adaptive logger
|
|
286
|
+
const socketDetails = getSocketDetails(socket);
|
|
287
|
+
adaptiveLogger.logConnection(socket, 'connect');
|
|
288
|
+
// Update adaptive logger with current connection count
|
|
289
|
+
adaptiveLogger.updateConnectionCount(this.connectionStats.activeConnections);
|
|
290
|
+
// Send greeting
|
|
291
|
+
this.sendGreeting(socket);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Check if an IP has exceeded the rate limit
|
|
295
|
+
* @param ip - Client IP address
|
|
296
|
+
* @returns True if rate limited
|
|
297
|
+
*/
|
|
298
|
+
isIPRateLimited(ip) {
|
|
299
|
+
const now = Date.now();
|
|
300
|
+
const ipData = this.ipConnections.get(ip);
|
|
301
|
+
if (!ipData) {
|
|
302
|
+
return false; // No previous connections
|
|
303
|
+
}
|
|
304
|
+
// Check if we're within the rate window
|
|
305
|
+
const isWithinWindow = now - ipData.firstConnection <= this.options.connectionRateWindow;
|
|
306
|
+
// If within window and count exceeds limit, rate limit is applied
|
|
307
|
+
if (isWithinWindow && ipData.count >= this.options.connectionRateLimit) {
|
|
308
|
+
SmtpLogger.warn(`Rate limit exceeded for IP ${ip}: ${ipData.count} connections in ${Math.round((now - ipData.firstConnection) / 1000)}s`);
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Track a new connection from an IP
|
|
315
|
+
* @param ip - Client IP address
|
|
316
|
+
*/
|
|
317
|
+
trackIPConnection(ip) {
|
|
318
|
+
const now = Date.now();
|
|
319
|
+
const ipData = this.ipConnections.get(ip);
|
|
320
|
+
if (!ipData) {
|
|
321
|
+
// First connection from this IP
|
|
322
|
+
this.ipConnections.set(ip, {
|
|
323
|
+
count: 1,
|
|
324
|
+
firstConnection: now,
|
|
325
|
+
lastConnection: now
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
// Check if we need to reset the window
|
|
330
|
+
if (now - ipData.lastConnection > this.options.connectionRateWindow) {
|
|
331
|
+
// Reset the window
|
|
332
|
+
this.ipConnections.set(ip, {
|
|
333
|
+
count: 1,
|
|
334
|
+
firstConnection: now,
|
|
335
|
+
lastConnection: now
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
// Increment within the current window
|
|
340
|
+
this.ipConnections.set(ip, {
|
|
341
|
+
count: ipData.count + 1,
|
|
342
|
+
firstConnection: ipData.firstConnection,
|
|
343
|
+
lastConnection: now
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Check if an IP has reached its connection limit
|
|
350
|
+
* @param ip - Client IP address
|
|
351
|
+
* @returns True if limit reached
|
|
352
|
+
*/
|
|
353
|
+
hasReachedIPConnectionLimit(ip) {
|
|
354
|
+
let ipConnectionCount = 0;
|
|
355
|
+
// Count active connections from this IP
|
|
356
|
+
for (const socket of this.activeConnections) {
|
|
357
|
+
if (socket.remoteAddress === ip) {
|
|
358
|
+
ipConnectionCount++;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return ipConnectionCount >= this.options.maxConnectionsPerIP;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Handle a new secure TLS connection with resource management
|
|
365
|
+
* @param socket - Client TLS socket
|
|
366
|
+
*/
|
|
367
|
+
async handleNewSecureConnection(socket) {
|
|
368
|
+
// Update connection stats
|
|
369
|
+
this.connectionStats.totalConnections++;
|
|
370
|
+
this.connectionStats.activeConnections = this.activeConnections.size + 1;
|
|
371
|
+
if (this.connectionStats.activeConnections > this.connectionStats.peakConnections) {
|
|
372
|
+
this.connectionStats.peakConnections = this.connectionStats.activeConnections;
|
|
373
|
+
}
|
|
374
|
+
// Get client IP
|
|
375
|
+
const remoteAddress = socket.remoteAddress || '0.0.0.0';
|
|
376
|
+
// Use UnifiedRateLimiter for connection rate limiting
|
|
377
|
+
const emailServer = this.smtpServer.getEmailServer();
|
|
378
|
+
const rateLimiter = emailServer.getRateLimiter();
|
|
379
|
+
// Check connection limit with UnifiedRateLimiter
|
|
380
|
+
const connectionResult = rateLimiter.recordConnection(remoteAddress);
|
|
381
|
+
if (!connectionResult.allowed) {
|
|
382
|
+
this.rejectConnection(socket, connectionResult.reason || 'Rate limit exceeded');
|
|
383
|
+
this.connectionStats.rejectedConnections++;
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
// Still track IP connections locally for cleanup purposes
|
|
387
|
+
this.trackIPConnection(remoteAddress);
|
|
388
|
+
// Check if maximum global connections reached
|
|
389
|
+
if (this.hasReachedMaxConnections()) {
|
|
390
|
+
this.rejectConnection(socket, 'Too many connections');
|
|
391
|
+
this.connectionStats.rejectedConnections++;
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
// Add socket to active connections
|
|
395
|
+
this.activeConnections.add(socket);
|
|
396
|
+
// Set up socket options
|
|
397
|
+
socket.setKeepAlive(true);
|
|
398
|
+
socket.setTimeout(this.options.socketTimeout);
|
|
399
|
+
// Explicitly set socket buffer sizes to prevent memory issues
|
|
400
|
+
socket.setNoDelay(true); // Disable Nagle's algorithm for better responsiveness
|
|
401
|
+
// Set limits on socket buffer size if supported by Node.js version
|
|
402
|
+
try {
|
|
403
|
+
// Here we set reasonable buffer limits to prevent memory exhaustion attacks
|
|
404
|
+
const highWaterMark = 64 * 1024; // 64 KB
|
|
405
|
+
// Note: Socket high water mark methods can't be set directly in newer Node.js versions
|
|
406
|
+
// These would need to be set during socket creation or with a different API
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
// Ignore errors from older Node.js versions that don't support these methods
|
|
410
|
+
SmtpLogger.debug(`Could not set socket buffer limits: ${error instanceof Error ? error.message : String(error)}`);
|
|
411
|
+
}
|
|
412
|
+
// Track this IP connection
|
|
413
|
+
this.trackIPConnection(remoteAddress);
|
|
414
|
+
// Set up event handlers
|
|
415
|
+
this.setupSocketEventHandlers(socket);
|
|
416
|
+
// Create a session for this connection
|
|
417
|
+
this.smtpServer.getSessionManager().createSession(socket, true);
|
|
418
|
+
// Log the new secure connection using adaptive logger
|
|
419
|
+
adaptiveLogger.logConnection(socket, 'connect');
|
|
420
|
+
// Update adaptive logger with current connection count
|
|
421
|
+
adaptiveLogger.updateConnectionCount(this.connectionStats.activeConnections);
|
|
422
|
+
// Send greeting
|
|
423
|
+
this.sendGreeting(socket);
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Set up event handlers for a socket with enhanced resource management
|
|
427
|
+
* @param socket - Client socket
|
|
428
|
+
*/
|
|
429
|
+
setupSocketEventHandlers(socket) {
|
|
430
|
+
// Store existing socket event handlers before adding new ones
|
|
431
|
+
const existingDataHandler = socket.listeners('data')[0];
|
|
432
|
+
const existingCloseHandler = socket.listeners('close')[0];
|
|
433
|
+
const existingErrorHandler = socket.listeners('error')[0];
|
|
434
|
+
const existingTimeoutHandler = socket.listeners('timeout')[0];
|
|
435
|
+
// Remove existing event handlers if they exist
|
|
436
|
+
if (existingDataHandler)
|
|
437
|
+
socket.removeListener('data', existingDataHandler);
|
|
438
|
+
if (existingCloseHandler)
|
|
439
|
+
socket.removeListener('close', existingCloseHandler);
|
|
440
|
+
if (existingErrorHandler)
|
|
441
|
+
socket.removeListener('error', existingErrorHandler);
|
|
442
|
+
if (existingTimeoutHandler)
|
|
443
|
+
socket.removeListener('timeout', existingTimeoutHandler);
|
|
444
|
+
// Data event - process incoming data from the client with resource limits
|
|
445
|
+
let buffer = '';
|
|
446
|
+
let totalBytesReceived = 0;
|
|
447
|
+
socket.on('data', async (data) => {
|
|
448
|
+
try {
|
|
449
|
+
// Get current session and update activity timestamp
|
|
450
|
+
const session = this.smtpServer.getSessionManager().getSession(socket);
|
|
451
|
+
if (session) {
|
|
452
|
+
this.smtpServer.getSessionManager().updateSessionActivity(session);
|
|
453
|
+
}
|
|
454
|
+
// Check if we're in DATA receiving mode - handle differently
|
|
455
|
+
if (session && session.state === SmtpState.DATA_RECEIVING) {
|
|
456
|
+
// In DATA mode, pass raw chunks directly to command handler with special marker
|
|
457
|
+
// Don't line-buffer large email content
|
|
458
|
+
try {
|
|
459
|
+
const dataString = data.toString('utf8');
|
|
460
|
+
// Use a special prefix to indicate this is raw data, not a command line
|
|
461
|
+
// CRITICAL FIX: Must await to prevent async pile-up
|
|
462
|
+
await this.smtpServer.getCommandHandler().processCommand(socket, `__RAW_DATA__${dataString}`);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
catch (dataError) {
|
|
466
|
+
SmtpLogger.error(`Data handler error during DATA mode: ${dataError instanceof Error ? dataError.message : String(dataError)}`);
|
|
467
|
+
socket.destroy();
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
// For command mode, continue with line-buffered processing
|
|
472
|
+
// Check buffer size limits to prevent memory attacks
|
|
473
|
+
totalBytesReceived += data.length;
|
|
474
|
+
if (buffer.length > this.options.bufferSizeLimit) {
|
|
475
|
+
// Buffer is too large, reject the connection
|
|
476
|
+
SmtpLogger.warn(`Buffer size limit exceeded: ${buffer.length} bytes for ${socket.remoteAddress}`);
|
|
477
|
+
this.sendResponse(socket, `${SmtpResponseCode.EXCEEDED_STORAGE} Message too large, disconnecting`);
|
|
478
|
+
socket.destroy();
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
// Impose a total transfer limit to prevent DoS
|
|
482
|
+
if (totalBytesReceived > this.options.bufferSizeLimit * 2) {
|
|
483
|
+
SmtpLogger.warn(`Total transfer limit exceeded: ${totalBytesReceived} bytes for ${socket.remoteAddress}`);
|
|
484
|
+
this.sendResponse(socket, `${SmtpResponseCode.EXCEEDED_STORAGE} Transfer limit exceeded, disconnecting`);
|
|
485
|
+
socket.destroy();
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
// Convert buffer to string safely with explicit encoding
|
|
489
|
+
const dataString = data.toString('utf8');
|
|
490
|
+
// Buffer incoming data
|
|
491
|
+
buffer += dataString;
|
|
492
|
+
// Process complete lines
|
|
493
|
+
let lineEndPos;
|
|
494
|
+
while ((lineEndPos = buffer.indexOf(SMTP_DEFAULTS.CRLF)) !== -1) {
|
|
495
|
+
// Extract a complete line
|
|
496
|
+
const line = buffer.substring(0, lineEndPos);
|
|
497
|
+
buffer = buffer.substring(lineEndPos + 2); // +2 to skip CRLF
|
|
498
|
+
// Check line length to prevent extremely long lines
|
|
499
|
+
if (line.length > 4096) { // 4KB line limit is reasonable for SMTP
|
|
500
|
+
SmtpLogger.warn(`Line length limit exceeded: ${line.length} bytes for ${socket.remoteAddress}`);
|
|
501
|
+
this.sendResponse(socket, `${SmtpResponseCode.SYNTAX_ERROR} Line too long, disconnecting`);
|
|
502
|
+
socket.destroy();
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
// Process non-empty lines
|
|
506
|
+
if (line.length > 0) {
|
|
507
|
+
try {
|
|
508
|
+
// CRITICAL FIX: Must await processCommand to prevent async pile-up
|
|
509
|
+
// This was causing the busy loop with high CPU usage when many empty lines were processed
|
|
510
|
+
await this.smtpServer.getCommandHandler().processCommand(socket, line);
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
// Handle any errors in command processing
|
|
514
|
+
SmtpLogger.error(`Command handler error: ${error instanceof Error ? error.message : String(error)}`);
|
|
515
|
+
this.sendResponse(socket, `${SmtpResponseCode.LOCAL_ERROR} Internal server error`);
|
|
516
|
+
// If there's a severe error, close the connection
|
|
517
|
+
if (error instanceof Error &&
|
|
518
|
+
(error.message.includes('fatal') || error.message.includes('critical'))) {
|
|
519
|
+
socket.destroy();
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// If buffer is getting too large without CRLF, it might be a DoS attempt
|
|
526
|
+
if (buffer.length > 10240) { // 10KB is a reasonable limit for a line without CRLF
|
|
527
|
+
SmtpLogger.warn(`Incomplete line too large: ${buffer.length} bytes for ${socket.remoteAddress}`);
|
|
528
|
+
this.sendResponse(socket, `${SmtpResponseCode.SYNTAX_ERROR} Incomplete line too large, disconnecting`);
|
|
529
|
+
socket.destroy();
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
catch (error) {
|
|
533
|
+
// Handle any unexpected errors during data processing
|
|
534
|
+
SmtpLogger.error(`Data handler error: ${error instanceof Error ? error.message : String(error)}`);
|
|
535
|
+
socket.destroy();
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
// Add drain event handler to manage flow control
|
|
539
|
+
socket.on('drain', () => {
|
|
540
|
+
// Socket buffer has been emptied, resume data flow if needed
|
|
541
|
+
if (socket.isPaused()) {
|
|
542
|
+
socket.resume();
|
|
543
|
+
SmtpLogger.debug(`Resumed socket for ${socket.remoteAddress} after drain`);
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
// Close event - clean up when connection is closed
|
|
547
|
+
socket.on('close', (hadError) => {
|
|
548
|
+
this.handleSocketClose(socket, hadError);
|
|
549
|
+
});
|
|
550
|
+
// Error event - handle socket errors
|
|
551
|
+
socket.on('error', (err) => {
|
|
552
|
+
this.handleSocketError(socket, err);
|
|
553
|
+
});
|
|
554
|
+
// Timeout event - handle socket timeouts
|
|
555
|
+
socket.on('timeout', () => {
|
|
556
|
+
this.handleSocketTimeout(socket);
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Get the current connection count
|
|
561
|
+
* @returns Number of active connections
|
|
562
|
+
*/
|
|
563
|
+
getConnectionCount() {
|
|
564
|
+
return this.activeConnections.size;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Check if the server has reached the maximum number of connections
|
|
568
|
+
* @returns True if max connections reached
|
|
569
|
+
*/
|
|
570
|
+
hasReachedMaxConnections() {
|
|
571
|
+
return this.activeConnections.size >= this.options.maxConnections;
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Close all active connections
|
|
575
|
+
*/
|
|
576
|
+
closeAllConnections() {
|
|
577
|
+
const connectionCount = this.activeConnections.size;
|
|
578
|
+
if (connectionCount === 0) {
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
SmtpLogger.info(`Closing all connections (count: ${connectionCount})`);
|
|
582
|
+
for (const socket of this.activeConnections) {
|
|
583
|
+
try {
|
|
584
|
+
// Send service closing notification
|
|
585
|
+
this.sendServiceClosing(socket);
|
|
586
|
+
// End the socket gracefully
|
|
587
|
+
socket.end();
|
|
588
|
+
// Force destroy after a short delay if not already destroyed
|
|
589
|
+
const destroyTimer = setTimeout(() => {
|
|
590
|
+
if (!socket.destroyed) {
|
|
591
|
+
socket.destroy();
|
|
592
|
+
}
|
|
593
|
+
this.cleanupTimers.delete(destroyTimer);
|
|
594
|
+
}, 100);
|
|
595
|
+
this.cleanupTimers.add(destroyTimer);
|
|
596
|
+
}
|
|
597
|
+
catch (error) {
|
|
598
|
+
SmtpLogger.error(`Error closing connection: ${error instanceof Error ? error.message : String(error)}`);
|
|
599
|
+
// Force destroy on error
|
|
600
|
+
try {
|
|
601
|
+
socket.destroy();
|
|
602
|
+
}
|
|
603
|
+
catch (e) {
|
|
604
|
+
// Ignore destroy errors
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
// Clear active connections
|
|
609
|
+
this.activeConnections.clear();
|
|
610
|
+
// Stop resource monitoring to prevent hanging timers
|
|
611
|
+
if (this.resourceCheckInterval) {
|
|
612
|
+
clearInterval(this.resourceCheckInterval);
|
|
613
|
+
this.resourceCheckInterval = null;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Handle socket close event
|
|
618
|
+
* @param socket - Client socket
|
|
619
|
+
* @param hadError - Whether the socket was closed due to error
|
|
620
|
+
*/
|
|
621
|
+
handleSocketClose(socket, hadError) {
|
|
622
|
+
try {
|
|
623
|
+
// Update connection statistics
|
|
624
|
+
this.connectionStats.closedConnections++;
|
|
625
|
+
this.connectionStats.activeConnections = this.activeConnections.size - 1;
|
|
626
|
+
// Get socket details for logging
|
|
627
|
+
const socketDetails = getSocketDetails(socket);
|
|
628
|
+
const socketId = `${socketDetails.remoteAddress}:${socketDetails.remotePort}`;
|
|
629
|
+
// Log with appropriate level based on whether there was an error
|
|
630
|
+
if (hadError) {
|
|
631
|
+
SmtpLogger.warn(`Socket closed with error: ${socketId}`);
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
SmtpLogger.debug(`Socket closed normally: ${socketId}`);
|
|
635
|
+
}
|
|
636
|
+
// Get the session before removing it
|
|
637
|
+
const session = this.smtpServer.getSessionManager().getSession(socket);
|
|
638
|
+
// Remove from active connections
|
|
639
|
+
this.activeConnections.delete(socket);
|
|
640
|
+
// Remove from session manager
|
|
641
|
+
this.smtpServer.getSessionManager().removeSession(socket);
|
|
642
|
+
// Cancel any timeout ID stored in the session
|
|
643
|
+
if (session?.dataTimeoutId) {
|
|
644
|
+
clearTimeout(session.dataTimeoutId);
|
|
645
|
+
}
|
|
646
|
+
// Log connection close with session details if available
|
|
647
|
+
adaptiveLogger.logConnection(socket, 'close', session);
|
|
648
|
+
// Update adaptive logger with new connection count
|
|
649
|
+
adaptiveLogger.updateConnectionCount(this.connectionStats.activeConnections);
|
|
650
|
+
}
|
|
651
|
+
catch (error) {
|
|
652
|
+
// Handle any unexpected errors during cleanup
|
|
653
|
+
SmtpLogger.error(`Error in handleSocketClose: ${error instanceof Error ? error.message : String(error)}`);
|
|
654
|
+
// Ensure socket is removed from active connections even if an error occurs
|
|
655
|
+
this.activeConnections.delete(socket);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Handle socket error event
|
|
660
|
+
* @param socket - Client socket
|
|
661
|
+
* @param error - Error object
|
|
662
|
+
*/
|
|
663
|
+
handleSocketError(socket, error) {
|
|
664
|
+
try {
|
|
665
|
+
// Update connection statistics
|
|
666
|
+
this.connectionStats.erroredConnections++;
|
|
667
|
+
// Get socket details for context
|
|
668
|
+
const socketDetails = getSocketDetails(socket);
|
|
669
|
+
const socketId = `${socketDetails.remoteAddress}:${socketDetails.remotePort}`;
|
|
670
|
+
// Get the session
|
|
671
|
+
const session = this.smtpServer.getSessionManager().getSession(socket);
|
|
672
|
+
// Detailed error logging with context information
|
|
673
|
+
SmtpLogger.error(`Socket error for ${socketId}: ${error.message}`, {
|
|
674
|
+
errorCode: error.code,
|
|
675
|
+
errorStack: error.stack,
|
|
676
|
+
sessionId: session?.id,
|
|
677
|
+
sessionState: session?.state,
|
|
678
|
+
remoteAddress: socketDetails.remoteAddress,
|
|
679
|
+
remotePort: socketDetails.remotePort
|
|
680
|
+
});
|
|
681
|
+
// Log the error for connection tracking using adaptive logger
|
|
682
|
+
adaptiveLogger.logConnection(socket, 'error', session, error);
|
|
683
|
+
// Cancel any timeout ID stored in the session
|
|
684
|
+
if (session?.dataTimeoutId) {
|
|
685
|
+
clearTimeout(session.dataTimeoutId);
|
|
686
|
+
}
|
|
687
|
+
// Close the socket if not already closed
|
|
688
|
+
if (!socket.destroyed) {
|
|
689
|
+
socket.destroy();
|
|
690
|
+
}
|
|
691
|
+
// Remove from active connections (cleanup after error)
|
|
692
|
+
this.activeConnections.delete(socket);
|
|
693
|
+
// Remove from session manager
|
|
694
|
+
this.smtpServer.getSessionManager().removeSession(socket);
|
|
695
|
+
}
|
|
696
|
+
catch (handlerError) {
|
|
697
|
+
// Meta-error handling (errors in the error handler)
|
|
698
|
+
SmtpLogger.error(`Error in handleSocketError: ${handlerError instanceof Error ? handlerError.message : String(handlerError)}`);
|
|
699
|
+
// Ensure socket is destroyed and removed from active connections
|
|
700
|
+
if (!socket.destroyed) {
|
|
701
|
+
socket.destroy();
|
|
702
|
+
}
|
|
703
|
+
this.activeConnections.delete(socket);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Handle socket timeout event
|
|
708
|
+
* @param socket - Client socket
|
|
709
|
+
*/
|
|
710
|
+
handleSocketTimeout(socket) {
|
|
711
|
+
try {
|
|
712
|
+
// Update connection statistics
|
|
713
|
+
this.connectionStats.timedOutConnections++;
|
|
714
|
+
// Get socket details for context
|
|
715
|
+
const socketDetails = getSocketDetails(socket);
|
|
716
|
+
const socketId = `${socketDetails.remoteAddress}:${socketDetails.remotePort}`;
|
|
717
|
+
// Get the session
|
|
718
|
+
const session = this.smtpServer.getSessionManager().getSession(socket);
|
|
719
|
+
// Get timing information for better debugging
|
|
720
|
+
const now = Date.now();
|
|
721
|
+
const idleTime = session?.lastActivity ? now - session.lastActivity : 'unknown';
|
|
722
|
+
if (session) {
|
|
723
|
+
// Log the timeout with extended details
|
|
724
|
+
SmtpLogger.warn(`Socket timeout from ${session.remoteAddress}`, {
|
|
725
|
+
sessionId: session.id,
|
|
726
|
+
remoteAddress: session.remoteAddress,
|
|
727
|
+
state: session.state,
|
|
728
|
+
timeout: this.options.socketTimeout,
|
|
729
|
+
idleTime: idleTime,
|
|
730
|
+
emailState: session.envelope?.mailFrom ? 'has-sender' : 'no-sender',
|
|
731
|
+
recipientCount: session.envelope?.rcptTo?.length || 0
|
|
732
|
+
});
|
|
733
|
+
// Cancel any timeout ID stored in the session
|
|
734
|
+
if (session.dataTimeoutId) {
|
|
735
|
+
clearTimeout(session.dataTimeoutId);
|
|
736
|
+
}
|
|
737
|
+
// Send timeout notification to client
|
|
738
|
+
this.sendResponse(socket, `${SmtpResponseCode.SERVICE_NOT_AVAILABLE} Connection timeout - closing connection`);
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
// Log timeout without session context
|
|
742
|
+
SmtpLogger.warn(`Socket timeout without session from ${socketId}`);
|
|
743
|
+
}
|
|
744
|
+
// Close the socket gracefully
|
|
745
|
+
try {
|
|
746
|
+
socket.end();
|
|
747
|
+
// Set a forced close timeout in case socket.end() doesn't close the connection
|
|
748
|
+
const timeoutDestroyTimer = setTimeout(() => {
|
|
749
|
+
if (!socket.destroyed) {
|
|
750
|
+
SmtpLogger.warn(`Forcing destroy of timed out socket: ${socketId}`);
|
|
751
|
+
socket.destroy();
|
|
752
|
+
}
|
|
753
|
+
this.cleanupTimers.delete(timeoutDestroyTimer);
|
|
754
|
+
}, 5000); // 5 second grace period for socket to end properly
|
|
755
|
+
this.cleanupTimers.add(timeoutDestroyTimer);
|
|
756
|
+
}
|
|
757
|
+
catch (error) {
|
|
758
|
+
SmtpLogger.error(`Error ending timed out socket: ${error instanceof Error ? error.message : String(error)}`);
|
|
759
|
+
// Ensure socket is destroyed even if end() fails
|
|
760
|
+
if (!socket.destroyed) {
|
|
761
|
+
socket.destroy();
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
// Clean up resources
|
|
765
|
+
this.activeConnections.delete(socket);
|
|
766
|
+
this.smtpServer.getSessionManager().removeSession(socket);
|
|
767
|
+
}
|
|
768
|
+
catch (handlerError) {
|
|
769
|
+
// Handle any unexpected errors during timeout handling
|
|
770
|
+
SmtpLogger.error(`Error in handleSocketTimeout: ${handlerError instanceof Error ? handlerError.message : String(handlerError)}`);
|
|
771
|
+
// Ensure socket is destroyed and removed from tracking
|
|
772
|
+
if (!socket.destroyed) {
|
|
773
|
+
socket.destroy();
|
|
774
|
+
}
|
|
775
|
+
this.activeConnections.delete(socket);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Reject a connection
|
|
780
|
+
* @param socket - Client socket
|
|
781
|
+
* @param reason - Reason for rejection
|
|
782
|
+
*/
|
|
783
|
+
rejectConnection(socket, reason) {
|
|
784
|
+
// Log the rejection
|
|
785
|
+
const socketDetails = getSocketDetails(socket);
|
|
786
|
+
SmtpLogger.warn(`Connection rejected from ${socketDetails.remoteAddress}:${socketDetails.remotePort}: ${reason}`);
|
|
787
|
+
// Send rejection message
|
|
788
|
+
this.sendResponse(socket, `${SmtpResponseCode.SERVICE_NOT_AVAILABLE} ${this.options.hostname} Service temporarily unavailable - ${reason}`);
|
|
789
|
+
// Close the socket
|
|
790
|
+
try {
|
|
791
|
+
socket.end();
|
|
792
|
+
}
|
|
793
|
+
catch (error) {
|
|
794
|
+
SmtpLogger.error(`Error ending rejected socket: ${error instanceof Error ? error.message : String(error)}`);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Send greeting message
|
|
799
|
+
* @param socket - Client socket
|
|
800
|
+
*/
|
|
801
|
+
sendGreeting(socket) {
|
|
802
|
+
const greeting = `${SmtpResponseCode.SERVICE_READY} ${this.options.hostname} ESMTP service ready`;
|
|
803
|
+
this.sendResponse(socket, greeting);
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Send service closing notification
|
|
807
|
+
* @param socket - Client socket
|
|
808
|
+
*/
|
|
809
|
+
sendServiceClosing(socket) {
|
|
810
|
+
const message = `${SmtpResponseCode.SERVICE_CLOSING} ${this.options.hostname} Service closing transmission channel`;
|
|
811
|
+
this.sendResponse(socket, message);
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Send response to client
|
|
815
|
+
* @param socket - Client socket
|
|
816
|
+
* @param response - Response to send
|
|
817
|
+
*/
|
|
818
|
+
sendResponse(socket, response) {
|
|
819
|
+
// Check if socket is still writable before attempting to write
|
|
820
|
+
if (socket.destroyed || socket.readyState !== 'open' || !socket.writable) {
|
|
821
|
+
SmtpLogger.debug(`Skipping response to closed/destroyed socket: ${response}`, {
|
|
822
|
+
remoteAddress: socket.remoteAddress,
|
|
823
|
+
remotePort: socket.remotePort,
|
|
824
|
+
destroyed: socket.destroyed,
|
|
825
|
+
readyState: socket.readyState,
|
|
826
|
+
writable: socket.writable
|
|
827
|
+
});
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
try {
|
|
831
|
+
socket.write(`${response}${SMTP_DEFAULTS.CRLF}`);
|
|
832
|
+
adaptiveLogger.logResponse(response, socket);
|
|
833
|
+
}
|
|
834
|
+
catch (error) {
|
|
835
|
+
// Log error and destroy socket
|
|
836
|
+
SmtpLogger.error(`Error sending response: ${error instanceof Error ? error.message : String(error)}`, {
|
|
837
|
+
response,
|
|
838
|
+
remoteAddress: socket.remoteAddress,
|
|
839
|
+
remotePort: socket.remotePort,
|
|
840
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
841
|
+
});
|
|
842
|
+
socket.destroy();
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Handle a new connection (interface requirement)
|
|
847
|
+
*/
|
|
848
|
+
async handleConnection(socket, secure) {
|
|
849
|
+
if (secure) {
|
|
850
|
+
this.handleNewSecureConnection(socket);
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
this.handleNewConnection(socket);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Check if accepting new connections (interface requirement)
|
|
858
|
+
*/
|
|
859
|
+
canAcceptConnection() {
|
|
860
|
+
return !this.hasReachedMaxConnections();
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* Clean up resources
|
|
864
|
+
*/
|
|
865
|
+
destroy() {
|
|
866
|
+
// Clear resource monitoring interval
|
|
867
|
+
if (this.resourceCheckInterval) {
|
|
868
|
+
clearInterval(this.resourceCheckInterval);
|
|
869
|
+
this.resourceCheckInterval = null;
|
|
870
|
+
}
|
|
871
|
+
// Clear all cleanup timers
|
|
872
|
+
for (const timer of this.cleanupTimers) {
|
|
873
|
+
clearTimeout(timer);
|
|
874
|
+
}
|
|
875
|
+
this.cleanupTimers.clear();
|
|
876
|
+
// Close all active connections
|
|
877
|
+
this.closeAllConnections();
|
|
878
|
+
// Clear maps
|
|
879
|
+
this.activeConnections.clear();
|
|
880
|
+
this.ipConnections.clear();
|
|
881
|
+
// Reset connection stats
|
|
882
|
+
this.connectionStats = {
|
|
883
|
+
totalConnections: 0,
|
|
884
|
+
activeConnections: 0,
|
|
885
|
+
peakConnections: 0,
|
|
886
|
+
rejectedConnections: 0,
|
|
887
|
+
closedConnections: 0,
|
|
888
|
+
erroredConnections: 0,
|
|
889
|
+
timedOutConnections: 0
|
|
890
|
+
};
|
|
891
|
+
SmtpLogger.debug('ConnectionManager destroyed');
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ubmVjdGlvbi1tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvbWFpbC9kZWxpdmVyeS9zbXRwc2VydmVyL2Nvbm5lY3Rpb24tbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxPQUFPLEtBQUssT0FBTyxNQUFNLHFCQUFxQixDQUFDO0FBRS9DLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDNUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUM3RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUUvRTs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLGlCQUFpQjtJQXlENUI7OztPQUdHO0lBQ0gsWUFBWSxVQUF1QjtRQXZEbkM7O1dBRUc7UUFDSyxzQkFBaUIsR0FBb0QsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUV2Rjs7V0FFRztRQUNLLG9CQUFlLEdBQUc7WUFDeEIsZ0JBQWdCLEVBQUUsQ0FBQztZQUNuQixpQkFBaUIsRUFBRSxDQUFDO1lBQ3BCLGVBQWUsRUFBRSxDQUFDO1lBQ2xCLG1CQUFtQixFQUFFLENBQUM7WUFDdEIsaUJBQWlCLEVBQUUsQ0FBQztZQUNwQixrQkFBa0IsRUFBRSxDQUFDO1lBQ3JCLG1CQUFtQixFQUFFLENBQUM7U0FDdkIsQ0FBQztRQUVGOztXQUVHO1FBQ0ssa0JBQWEsR0FJaEIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUVmOztXQUVHO1FBQ0ssMEJBQXFCLEdBQTBCLElBQUksQ0FBQztRQUU1RDs7V0FFRztRQUNLLGtCQUFhLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7UUFxQnJELElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxD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
|