diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Config.php b/snappymail/v/0.0.0/app/libraries/MailSo/Config.php index 5a8c23f71..8d6fe7dc3 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Config.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Config.php @@ -56,11 +56,6 @@ class Config */ public static $CheckNewMessages = true; - /** - * @var bool - */ - public static $PreferStartTlsIfAutoDetect = true; - /** * @var string */ diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php index 97775ecb3..0a46ec57b 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/ImapClient.php @@ -11,6 +11,8 @@ namespace MailSo\Imap; +use MailSo\Net\Enumerations\ConnectionSecurityType; + /** * @category MailSo * @package Imap @@ -93,15 +95,19 @@ class ImapClient extends \MailSo\Net\NetClient $this->setCapabilities($this->getResponse('*')); - if ($this->IsSupported('STARTTLS') && \MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS($this->iSecurityType)) - { + if (ConnectionSecurityType::STARTTLS === $this->iSecurityType + || (ConnectionSecurityType::AUTO_DETECT === $this->iSecurityType && $this->IsSupported('STARTTLS'))) { + $this->StartTLS(); + } + } + + private function StartTLS() : void + { + if ($this->IsSupported('STARTTLS')) { $this->SendRequestGetResponse('STARTTLS'); $this->EnableCrypto(); - $this->aCapabilityItems = null; - } - else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) - { + } else { $this->writeLogException( new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), \LOG_ERR, true); @@ -143,6 +149,10 @@ class ImapClient extends \MailSo\Net\NetClient } } if (!$type) { + if (!$this->Encrypted() && $this->IsSupported('STARTTLS')) { + $this->StartTLS(); + return $this->Login($aCredentials); + } throw new \MailSo\RuntimeException('No supported SASL mechanism found, remote server wants: ' . \implode(', ', \array_filter($this->Capability() ?: [], function($var){ return \str_starts_with($var, 'AUTH='); diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php b/snappymail/v/0.0.0/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php index a9c080e31..687a3b966 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Net/Enumerations/ConnectionSecurityType.php @@ -46,12 +46,4 @@ abstract class ConnectionSecurityType return self::SSL === $iResult; } - - public static function UseStartTLS(int $iSecurityType, bool $bHasSupportedAuth = true) : bool - { - return - (self::STARTTLS === $iSecurityType - || (self::AUTO_DETECT === $iSecurityType && (!$bHasSupportedAuth || \MailSo\Config::$PreferStartTlsIfAutoDetect))) - && \defined('STREAM_CRYPTO_METHOD_TLS_CLIENT') && \MailSo\Base\Utils::FunctionCallable('stream_socket_enable_crypto'); - } } diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php index a61800e3a..0c0beb928 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Net/NetClient.php @@ -209,6 +209,11 @@ abstract class NetClient } } + public function Encrypted() : bool + { + return $this->rConnect && !empty(\stream_get_meta_data($this->rConnect)['crypto']); + } + public function EnableCrypto(bool $insecure = false) { $bError = true; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php index bf5a4bc5c..7f9bbf0fc 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Sieve/ManageSieveClient.php @@ -11,6 +11,8 @@ namespace MailSo\Sieve; +use MailSo\Net\Enumerations\ConnectionSecurityType; + /** * @category MailSo * @package Sieve @@ -71,17 +73,21 @@ class ManageSieveClient extends \MailSo\Net\NetClient $this->validateResponse($aResponse); $this->parseStartupResponse($aResponse); - if ($this->IsSupported('STARTTLS') && \MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS($this->iSecurityType)) - { + if (ConnectionSecurityType::STARTTLS === $this->iSecurityType + || (ConnectionSecurityType::AUTO_DETECT === $this->iSecurityType && $this->IsSupported('STARTTLS'))) { + $this->StartTLS(); + } + } + + private function StartTLS() : void + { + if ($this->IsSupported('STARTTLS')) { $this->sendRequestWithCheck('STARTTLS'); $this->EnableCrypto(); - $aResponse = $this->parseResponse(); $this->validateResponse($aResponse); $this->parseStartupResponse($aResponse); - } - else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) - { + } else { $this->writeLogException( new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), \LOG_ERR, true); @@ -106,95 +112,96 @@ class ManageSieveClient extends \MailSo\Net\NetClient \LOG_ERR, true); } - if ($this->IsSupported('SASL')) - { - $type = ''; - \array_push($aCredentials['SASLMechanisms'], 'PLAIN', 'LOGIN'); - foreach ($aCredentials['SASLMechanisms'] as $sasl_type) { - if ($this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) { - $type = $sasl_type; - break; - } - } - - $SASL = \SnappyMail\SASL::factory($type); - $SASL->base64 = true; - - $bAuth = false; - try - { - if (0 === \strpos($type, 'SCRAM-')) - { -/* - $sAuthzid = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), \MailSo\Imap\Enumerations\ResponseType::CONTINUATION); - $this->sendRaw($SASL->authenticate($sLogin, $sPassword/*, $sAuthzid* /), true); - $sChallenge = $SASL->challenge($this->getResponseValue($this->getResponse(), \MailSo\Imap\Enumerations\ResponseType::CONTINUATION)); - if ($this->oLogger) { - $this->oLogger->AddSecret($sChallenge); - } - $this->sendRaw($sChallenge, true, '*******'); - $oResponse = $this->getResponse(); - $SASL->verify($this->getResponseValue($oResponse)); -*/ - } - else if ('PLAIN' === $type || 'OAUTHBEARER' === $type || 'XOAUTH2' === $type) - { - $sAuth = $SASL->authenticate($sLogin, $sPassword, $sLoginAuthKey); - - if ($aCredentials['InitialAuthPlain']) - { - $this->sendRaw("AUTHENTICATE \"{$type}\" \"{$sAuth}\""); - } - else - { - $this->sendRaw("AUTHENTICATE \"{$type}\" {".\strlen($sAuth).'+}'); - $this->sendRaw($sAuth); - } - - $aResponse = $this->parseResponse(); - $this->validateResponse($aResponse); - $this->parseStartupResponse($aResponse); - $bAuth = true; - } - else if ('LOGIN' === $type) - { - $sLogin = $SASL->authenticate($sLogin, $sPassword); - $sPassword = $SASL->challenge(''); - - $this->sendRaw('AUTHENTICATE "LOGIN"'); - $this->sendRaw('{'.\strlen($sLogin).'+}'); - $this->sendRaw($sLogin); - $this->sendRaw('{'.\strlen($sPassword).'+}'); - $this->sendRaw($sPassword); - - $aResponse = $this->parseResponse(); - $this->validateResponse($aResponse); - $this->parseStartupResponse($aResponse); - $bAuth = true; - } - } - catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException) - { - $this->writeLogException( - new \MailSo\Sieve\Exceptions\LoginBadCredentialsException( - $oException->GetResponses(), '', 0, $oException), - \LOG_ERR, true); - } - - if (!$bAuth) - { - $this->writeLogException( - new \MailSo\Sieve\Exceptions\LoginBadMethodException, - \LOG_ERR, true); + $type = ''; + \array_push($aCredentials['SASLMechanisms'], 'PLAIN', 'LOGIN'); + foreach ($aCredentials['SASLMechanisms'] as $sasl_type) { + if ($this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) { + $type = $sasl_type; + break; } } - else - { + + if (!$type) { + if (!$this->Encrypted() && $this->IsSupported('STARTTLS')) { + $this->StartTLS(); + return $this->Login($aCredentials); + } $this->writeLogException( new \MailSo\Sieve\Exceptions\LoginException, \LOG_ERR, true); } + $SASL = \SnappyMail\SASL::factory($type); + $SASL->base64 = true; + + $bAuth = false; + try + { + if (0 === \strpos($type, 'SCRAM-')) + { +/* + $sAuthzid = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), \MailSo\Imap\Enumerations\ResponseType::CONTINUATION); + $this->sendRaw($SASL->authenticate($sLogin, $sPassword/*, $sAuthzid* /), true); + $sChallenge = $SASL->challenge($this->getResponseValue($this->getResponse(), \MailSo\Imap\Enumerations\ResponseType::CONTINUATION)); + if ($this->oLogger) { + $this->oLogger->AddSecret($sChallenge); + } + $this->sendRaw($sChallenge, true, '*******'); + $oResponse = $this->getResponse(); + $SASL->verify($this->getResponseValue($oResponse)); +*/ + } + else if ('PLAIN' === $type || 'OAUTHBEARER' === $type || 'XOAUTH2' === $type) + { + $sAuth = $SASL->authenticate($sLogin, $sPassword, $sLoginAuthKey); + + if ($aCredentials['InitialAuthPlain']) + { + $this->sendRaw("AUTHENTICATE \"{$type}\" \"{$sAuth}\""); + } + else + { + $this->sendRaw("AUTHENTICATE \"{$type}\" {".\strlen($sAuth).'+}'); + $this->sendRaw($sAuth); + } + + $aResponse = $this->parseResponse(); + $this->validateResponse($aResponse); + $this->parseStartupResponse($aResponse); + $bAuth = true; + } + else if ('LOGIN' === $type) + { + $sLogin = $SASL->authenticate($sLogin, $sPassword); + $sPassword = $SASL->challenge(''); + + $this->sendRaw('AUTHENTICATE "LOGIN"'); + $this->sendRaw('{'.\strlen($sLogin).'+}'); + $this->sendRaw($sLogin); + $this->sendRaw('{'.\strlen($sPassword).'+}'); + $this->sendRaw($sPassword); + + $aResponse = $this->parseResponse(); + $this->validateResponse($aResponse); + $this->parseStartupResponse($aResponse); + $bAuth = true; + } + } + catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException) + { + $this->writeLogException( + new \MailSo\Sieve\Exceptions\LoginBadCredentialsException( + $oException->GetResponses(), '', 0, $oException), + \LOG_ERR, true); + } + + if (!$bAuth) + { + $this->writeLogException( + new \MailSo\Sieve\Exceptions\LoginBadMethodException, + \LOG_ERR, true); + } + $this->bIsLoggined = true; return $this; diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php index dc45ac21d..6a87de233 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php @@ -11,6 +11,8 @@ namespace MailSo\Smtp; +use MailSo\Net\Enumerations\ConnectionSecurityType; + /** * @category MailSo * @package Smtp @@ -18,9 +20,9 @@ namespace MailSo\Smtp; class SmtpClient extends \MailSo\Net\NetClient { /** - * @var bool + * @var string */ - private $bHelo = false; + private $sEhlo = ''; /** * @var bool @@ -107,7 +109,26 @@ class SmtpClient extends \MailSo\Net\NetClient $this->validateResponse(220); - $this->preLoginStartTLSAndEhloProcess($sEhloHost); + $this->ehloOrHelo($sEhloHost); + $this->sEhlo = $sEhloHost; + + if (ConnectionSecurityType::STARTTLS === $this->iSecurityType + || (ConnectionSecurityType::AUTO_DETECT === $this->iSecurityType && $this->IsSupported('STARTTLS'))) { + $this->StartTLS(); + } + } + + private function StartTLS() : void + { + if ($this->IsSupported('STARTTLS')) { + $this->sendRequestWithCheck('STARTTLS', 220); + $this->EnableCrypto(); + $this->ehloOrHelo($this->sEhlo); + } else { + $this->writeLogException( + new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), + \LOG_ERR, true); + } } /** @@ -133,7 +154,11 @@ class SmtpClient extends \MailSo\Net\NetClient } if (!$type) { - \trigger_error("SMTP {$this->GetConnectedHost()} no supported AUTH options. Disable login" . ($this->IsSupported('STARTTLS') ? ' or try with STARTTLS' : '')); + if (!$this->Encrypted() && $this->IsSupported('STARTTLS')) { + $this->StartTLS(); + return $this->Login($aCredentials); + } + \trigger_error("SMTP {$this->GetConnectedHost()} no supported AUTH options. Disable login"); $this->writeLogException( new \MailSo\Smtp\Exceptions\LoginBadMethodException, \LOG_NOTICE, true); @@ -410,40 +435,11 @@ class SmtpClient extends \MailSo\Net\NetClient $this->sendRequestWithCheck('QUIT', 221); } - $this->bHelo = false; $this->bMail = false; $this->bRcpt = false; $this->bData = false; } - private function preLoginStartTLSAndEhloProcess(string $sEhloHost) : void - { - if ($this->bHelo) - { - $this->writeLogException( - new \MailSo\RuntimeException('Cannot issue EHLO/HELO to existing session'), - \LOG_ERR, true); - } - - $this->ehloOrHelo($sEhloHost); - - if ($this->IsSupported('STARTTLS') && \MailSo\Net\Enumerations\ConnectionSecurityType::UseStartTLS($this->iSecurityType, $this->HasSupportedAuth())) - { - $this->sendRequestWithCheck('STARTTLS', 220); - $this->EnableCrypto(); - - $this->ehloOrHelo($sEhloHost); - } - else if (\MailSo\Net\Enumerations\ConnectionSecurityType::STARTTLS === $this->iSecurityType) - { - $this->writeLogException( - new \MailSo\Net\Exceptions\SocketUnsuppoterdSecureConnectionException('STARTTLS is not supported'), - \LOG_ERR, true); - } - - $this->bHelo = true; - } - /** * @throws \InvalidArgumentException * @throws \MailSo\RuntimeException