mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-11 00:14:50 +03:00
Revamp NetClient (SMTP, IMAP, Sieve) login for rfc7628 OAuth plugin support
This commit is contained in:
parent
dff2415762
commit
617d700a5d
11 changed files with 194 additions and 178 deletions
|
|
@ -29,48 +29,38 @@ $Plugin->addHook('hook.name', 'functionName');
|
|||
|
||||
## IMAP
|
||||
|
||||
### imap.credentials
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
array &$aCredentials
|
||||
|
||||
### imap.before-connect
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
\MailSo\Mail\MailClient $oMailClient
|
||||
array $aCredentials
|
||||
\MailSo\Imap\ImapClient $oImapClient
|
||||
array &$aCredentials
|
||||
|
||||
### imap.after-connect
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
\MailSo\Mail\MailClient $oMailClient
|
||||
\MailSo\Imap\ImapClient $oImapClient
|
||||
array $aCredentials
|
||||
|
||||
### imap.before-login
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
\MailSo\Mail\MailClient $oMailClient
|
||||
array $aCredentials
|
||||
\MailSo\Imap\ImapClient $oImapClient
|
||||
array &$aCredentials
|
||||
|
||||
### imap.after-login
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
\MailSo\Mail\MailClient $oMailClient
|
||||
\MailSo\Imap\ImapClient $oImapClient
|
||||
bool $bSuccess
|
||||
array $aCredentials
|
||||
|
||||
## Sieve
|
||||
|
||||
### sieve.credentials
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
array &$aCredentials
|
||||
|
||||
### sieve.before-connect
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
\MailSo\Sieve\ManageSieveClient $oSieveClient
|
||||
array $aCredentials
|
||||
array &$aCredentials
|
||||
|
||||
### sieve.after-connect
|
||||
params:
|
||||
|
|
@ -82,27 +72,22 @@ $Plugin->addHook('hook.name', 'functionName');
|
|||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
\MailSo\Sieve\ManageSieveClient $oSieveClient
|
||||
bool $bSuccess
|
||||
array $aCredentials
|
||||
array &$aCredentials
|
||||
|
||||
### sieve.after-login
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
\MailSo\Sieve\ManageSieveClient $oSieveClient
|
||||
bool $bSuccess
|
||||
array $aCredentials
|
||||
|
||||
## SMTP
|
||||
|
||||
### smtp.credentials
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
array &$aCredentials
|
||||
|
||||
### smtp.before-connect
|
||||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
\MailSo\Smtp\SmtpClient $oSmtpClient
|
||||
array $aCredentials
|
||||
array &$aCredentials
|
||||
|
||||
### smtp.after-connect
|
||||
params:
|
||||
|
|
@ -114,7 +99,7 @@ $Plugin->addHook('hook.name', 'functionName');
|
|||
params:
|
||||
\RainLoop\Model\Account $oAccount
|
||||
\MailSo\Smtp\SmtpClient $oSmtpClient
|
||||
array $aCredentials
|
||||
array &$aCredentials
|
||||
|
||||
### smtp.after-login
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -130,18 +130,24 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
* @throws \MailSo\Net\Exceptions\Exception
|
||||
* @throws \MailSo\Imap\Exceptions\Exception
|
||||
*/
|
||||
public function Login(string $sLogin, string $sPassword, string $sProxyAuthUser = '',
|
||||
bool $bUseAuthPlainIfSupported = true, bool $bUseAuthCramMd5IfSupported = true) : self
|
||||
public function Login(array $aCredentials) : self
|
||||
{
|
||||
if (!\strlen(\trim($sLogin)) || !\strlen(\trim($sPassword)))
|
||||
if (!empty($aCredentials['ProxyAuthUser']) && !empty($aCredentials['ProxyAuthPassword'])) {
|
||||
$sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($aCredentials['ProxyAuthUser']));
|
||||
$sPassword = $aCredentials['ProxyAuthPassword'];
|
||||
$sProxyAuthUser = $aCredentials['Login'];
|
||||
} else {
|
||||
$sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($aCredentials['Login']));
|
||||
$sPassword = $aCredentials['Password'];
|
||||
}
|
||||
|
||||
if (!\strlen($sLogin) || !\strlen($sPassword))
|
||||
{
|
||||
$this->writeLogException(
|
||||
new \MailSo\Base\Exceptions\InvalidArgumentException,
|
||||
\MailSo\Log\Enumerations\Type::ERROR, true);
|
||||
}
|
||||
|
||||
$sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin));
|
||||
|
||||
$this->sLogginedUser = $sLogin;
|
||||
|
||||
// $encrypted = !empty(\stream_get_meta_data($this->ConnectionResource())['crypto']);
|
||||
|
|
@ -149,9 +155,11 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$types = [
|
||||
// 'SCRAM-SHA-256' => 1, // !$encrypted
|
||||
// 'SCRAM-SHA-1' => 1, // !$encrypted
|
||||
'CRAM-MD5' => $bUseAuthCramMd5IfSupported,
|
||||
'PLAIN' => $bUseAuthPlainIfSupported,
|
||||
'LOGIN' => 1,
|
||||
'CRAM-MD5' => $aCredentials['UseAuthCramMd5IfSupported'],
|
||||
'PLAIN' => $aCredentials['UseAuthPlainIfSupported'],
|
||||
'OAUTHBEARER' => $aCredentials['UseAuthOAuth2IfSupported'],
|
||||
'XOAUTH2' => $aCredentials['UseAuthOAuth2IfSupported'],
|
||||
'LOGIN' => 1
|
||||
];
|
||||
foreach ($types as $sasl_type => $active) {
|
||||
if ($active && $this->IsSupported("AUTH={$sasl_type}") && \SnappyMail\SASL::isSupported($sasl_type)) {
|
||||
|
|
@ -188,7 +196,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$this->sendRaw($sAuth, true, '*******');
|
||||
$this->getResponse();
|
||||
}
|
||||
else if ('PLAIN' === $type)
|
||||
else if ('PLAIN' === $type || 'OAUTHBEARER' === $type)
|
||||
{
|
||||
$sAuth = $SASL->authenticate($sLogin, $sPassword);
|
||||
if ($this->oLogger) {
|
||||
|
|
@ -202,6 +210,23 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$this->getResponse();
|
||||
}
|
||||
}
|
||||
else if ('XOAUTH2' === $type)
|
||||
{
|
||||
$sAuth = $SASL->authenticate($sLogin, $sPassword);
|
||||
$this->SendRequest('AUTHENTICATE', array($type, $sAuth));
|
||||
$aR = $this->parseResponseWithValidation();
|
||||
if (\is_array($aR) && \count($aR) && isset($aR[\count($aR) - 1])) {
|
||||
$oR = $aR[\count($aR) - 1];
|
||||
if (\MailSo\Imap\Enumerations\ResponseType::CONTINUATION === $oR->ResponseType) {
|
||||
if (!empty($oR->ResponseList[1]) && preg_match('/^[a-zA-Z0-9=+\/]+$/', $oR->ResponseList[1])) {
|
||||
$this->Logger()->Write(\base64_decode($oR->ResponseList[1]),
|
||||
\MailSo\Log\Enumerations\Type::WARNING);
|
||||
}
|
||||
$this->sendRaw('');
|
||||
$this->parseResponseWithValidation();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($this->IsSupported('LOGINDISABLED'))
|
||||
{
|
||||
$sB64 = $this->getResponseValue($this->SendRequestGetResponse('AUTHENTICATE', array($type)), Enumerations\ResponseType::CONTINUATION);
|
||||
|
|
@ -227,7 +252,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
));
|
||||
}
|
||||
|
||||
if (0 < \strlen($sProxyAuthUser))
|
||||
if (\strlen($sProxyAuthUser))
|
||||
{
|
||||
$this->SendRequestGetResponse('PROXYAUTH', array($this->EscapeString($sProxyAuthUser)));
|
||||
}
|
||||
|
|
@ -578,7 +603,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$aFetchItems = Enumerations\FetchType::ChangeFetchItemsBefourRequest($aInputFetchItems);
|
||||
foreach ($aFetchItems as $sName => $mItem)
|
||||
{
|
||||
if (0 < \strlen($sName) && '' !== $mItem)
|
||||
if (\strlen($sName) && '' !== $mItem)
|
||||
{
|
||||
$this->aFetchCallbacks[$sName] = $mItem;
|
||||
}
|
||||
|
|
@ -704,7 +729,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
}
|
||||
else
|
||||
{
|
||||
if (0 < \strlen($sCharset))
|
||||
if (\strlen($sCharset))
|
||||
{
|
||||
$aRequest[] = 'CHARSET';
|
||||
$aRequest[] = \strtoupper($sCharset);
|
||||
|
|
@ -716,7 +741,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
|
||||
$aRequest[] = $sSearchCriterias;
|
||||
|
||||
if (0 < \strlen($sLimit))
|
||||
if (\strlen($sLimit))
|
||||
{
|
||||
$aRequest[] = $sLimit;
|
||||
}
|
||||
|
|
@ -755,7 +780,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$sCommandPrefix = ($bReturnUid) ? 'UID ' : '';
|
||||
|
||||
$aRequest = array();
|
||||
if (0 < \strlen($sCharset))
|
||||
if (\strlen($sCharset))
|
||||
{
|
||||
$aRequest[] = 'CHARSET';
|
||||
$aRequest[] = \strtoupper($sCharset);
|
||||
|
|
@ -890,7 +915,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$sCmd = 'EXPUNGE';
|
||||
$aArguments = array();
|
||||
|
||||
if (!$bExpungeAll && $bForceUidExpunge && 0 < \strlen($sUidRangeIfSupported) && $this->IsSupported('UIDPLUS'))
|
||||
if (!$bExpungeAll && $bForceUidExpunge && \strlen($sUidRangeIfSupported) && $this->IsSupported('UIDPLUS'))
|
||||
{
|
||||
$sCmd = 'UID '.$sCmd;
|
||||
$aArguments = array($sUidRangeIfSupported);
|
||||
|
|
@ -950,8 +975,8 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
$oLast = $this->GetLastResponse()->getLast();
|
||||
if ($oLast && Enumerations\ResponseType::TAGGED === $oLast->ResponseType && \is_array($oLast->OptionalResponse))
|
||||
{
|
||||
if (0 < \strlen($oLast->OptionalResponse[0]) &&
|
||||
0 < \strlen($oLast->OptionalResponse[2]) &&
|
||||
if (\strlen($oLast->OptionalResponse[0]) &&
|
||||
\strlen($oLast->OptionalResponse[2]) &&
|
||||
'APPENDUID' === strtoupper($oLast->OptionalResponse[0]) &&
|
||||
\is_numeric($oLast->OptionalResponse[2])
|
||||
)
|
||||
|
|
@ -1603,11 +1628,11 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
}
|
||||
|
||||
$sFetchKey = '';
|
||||
if (0 < \strlen($sLiteralAtomUpperCasePeek) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCasePeek]))
|
||||
if (\strlen($sLiteralAtomUpperCasePeek) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCasePeek]))
|
||||
{
|
||||
$sFetchKey = $sLiteralAtomUpperCasePeek;
|
||||
}
|
||||
else if (0 < \strlen($sLiteralAtomUpperCase) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCase]))
|
||||
else if (\strlen($sLiteralAtomUpperCase) && isset($this->aFetchCallbacks[$sLiteralAtomUpperCase]))
|
||||
{
|
||||
$sFetchKey = $sLiteralAtomUpperCase;
|
||||
}
|
||||
|
|
@ -1726,7 +1751,7 @@ class ImapClient extends \MailSo\Net\NetClient
|
|||
return '"' . \addcslashes($sStringForEscape, '\\"') . '"';
|
||||
}
|
||||
|
||||
protected function getLogName() : string
|
||||
public function getLogName() : string
|
||||
{
|
||||
return 'IMAP';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,31 +40,6 @@ class MailClient
|
|||
return $this->oImapClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
|
||||
* @throws \MailSo\Net\Exceptions\Exception
|
||||
* @throws \MailSo\Imap\Exceptions\Exception
|
||||
*/
|
||||
public function Connect(string $sServerName, int $iPort = 143,
|
||||
int $iSecurityType = \MailSo\Net\Enumerations\ConnectionSecurityType::AUTO_DETECT, bool $bVerifySsl = false,
|
||||
bool $bAllowSelfSigned = false, string $sClientCert = '') : self
|
||||
{
|
||||
$this->oImapClient->Connect($sServerName, $iPort, $iSecurityType, $bVerifySsl, $bAllowSelfSigned, $sClientCert);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
|
||||
* @throws \MailSo\Net\Exceptions\Exception
|
||||
* @throws \MailSo\Imap\Exceptions\LoginException
|
||||
*/
|
||||
public function Login(string $sLogin, string $sPassword, string $sProxyAuthUser = '',
|
||||
bool $bUseAuthPlainIfSupported = true, bool $bUseAuthCramMd5IfSupported = true) : self
|
||||
{
|
||||
$this->oImapClient->Login($sLogin, $sPassword, $sProxyAuthUser, $bUseAuthPlainIfSupported, $bUseAuthCramMd5IfSupported);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \MailSo\Net\Exceptions\Exception
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -433,10 +433,7 @@ abstract class NetClient
|
|||
}
|
||||
}
|
||||
|
||||
protected function getLogName() : string
|
||||
{
|
||||
return 'NET';
|
||||
}
|
||||
abstract function getLogName() : string;
|
||||
|
||||
protected function writeLog(string $sDesc, int $iDescType = \MailSo\Log\Enumerations\Type::INFO, bool $bDiplayCrLf = false) : void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,11 +37,6 @@ class ManageSieveClient extends \MailSo\Net\NetClient
|
|||
*/
|
||||
private $aModules = array();
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $__USE_INITIAL_AUTH_PLAIN_COMMAND = true;
|
||||
|
||||
public function IsSupported(string $sCapa) : bool
|
||||
{
|
||||
return isset($this->aCapa[\strtoupper($sCapa)]);
|
||||
|
|
@ -100,9 +95,12 @@ class ManageSieveClient extends \MailSo\Net\NetClient
|
|||
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
|
||||
* @throws \MailSo\Sieve\Exceptions\LoginException
|
||||
*/
|
||||
public function Login(string $sLogin, string $sPassword, string $sLoginAuthKey = '') : self
|
||||
public function Login(array $aCredentials) : self
|
||||
{
|
||||
if (!\strlen(\trim($sLogin)) || !\strlen(\trim($sPassword)))
|
||||
$sLogin = $aCredentials['Login'];
|
||||
$sPassword = $aCredentials['Password'];
|
||||
$sLoginAuthKey = '';
|
||||
if (!\strlen($sLogin) || !\strlen($sPassword))
|
||||
{
|
||||
$this->writeLogException(
|
||||
new \MailSo\Base\Exceptions\InvalidArgumentException,
|
||||
|
|
@ -137,7 +135,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient
|
|||
{
|
||||
$sAuth = $SASL->authenticate($sLogin, $sPassword, $sLoginAuthKey);
|
||||
|
||||
if ($this->__USE_INITIAL_AUTH_PLAIN_COMMAND)
|
||||
if ($aCredentials['InitialAuthPlain'])
|
||||
{
|
||||
$this->sendRequest('AUTHENTICATE "PLAIN" "'.$sAuth.'"');
|
||||
}
|
||||
|
|
@ -530,7 +528,7 @@ class ManageSieveClient extends \MailSo\Net\NetClient
|
|||
}
|
||||
}
|
||||
|
||||
protected function getLogName() : string
|
||||
public function getLogName() : string
|
||||
{
|
||||
return 'SIEVE';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,18 +117,21 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
* @throws \MailSo\Net\Exceptions\Exception
|
||||
* @throws \MailSo\Smtp\Exceptions\Exception
|
||||
*/
|
||||
public function Login(string $sLogin, string $sPassword, bool $bUseAuthPlainIfSupported = true, bool $bUseAuthCramMd5IfSupported = true) : self
|
||||
public function Login(array $aCredentials) : self
|
||||
{
|
||||
$sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($sLogin));
|
||||
$sLogin = \MailSo\Base\Utils::IdnToAscii(\MailSo\Base\Utils::Trim($aCredentials['Login']));
|
||||
$sPassword = $aCredentials['Password'];
|
||||
|
||||
// $encrypted = !empty(\stream_get_meta_data($this->ConnectionResource())['crypto']);
|
||||
$type = '';
|
||||
$types = [
|
||||
'SCRAM-SHA-256' => 1, // !$encrypted
|
||||
'SCRAM-SHA-1' => 1, // !$encrypted
|
||||
'CRAM-MD5' => $bUseAuthCramMd5IfSupported,
|
||||
'PLAIN' => $bUseAuthPlainIfSupported,
|
||||
'LOGIN' => 1 // $encrypted
|
||||
'CRAM-MD5' => $aCredentials['UseAuthCramMd5IfSupported'],
|
||||
'PLAIN' => $aCredentials['UseAuthPlainIfSupported'],
|
||||
'OAUTHBEARER' => $aCredentials['UseAuthOAuth2IfSupported'],
|
||||
'XOAUTH2' => $aCredentials['UseAuthOAuth2IfSupported'],
|
||||
'LOGIN' => 1, // $encrypted
|
||||
];
|
||||
foreach ($types as $sasl_type => $active) {
|
||||
if ($active && $this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) {
|
||||
|
|
@ -166,6 +169,8 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
{
|
||||
// RFC 4616
|
||||
case 'PLAIN':
|
||||
case 'XOAUTH2':
|
||||
case 'OAUTHBEARER':
|
||||
$this->sendRequestWithCheck($SASL->authenticate($sLogin, $sPassword), 235, '', true);
|
||||
break;
|
||||
|
||||
|
|
@ -192,14 +197,6 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
$sResult = $this->sendRequestWithCheck($SASL->challenge($sResult), 235, '', true);
|
||||
$SASL->verify($sResult);
|
||||
break;
|
||||
|
||||
/*
|
||||
// https://developers.google.com/gmail/imap/xoauth2-protocol
|
||||
case 'XOAUTH2':
|
||||
throw new \Exception('Please use app passphrases: https://support.google.com/mail/answer/185833');
|
||||
break;
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
catch (\MailSo\Smtp\Exceptions\NegativeResponseException $oException)
|
||||
|
|
@ -603,7 +600,7 @@ class SmtpClient extends \MailSo\Net\NetClient
|
|||
while ('-' === \substr($aParts[1], 0, 1));
|
||||
}
|
||||
|
||||
protected function getLogName() : string
|
||||
public function getLogName() : string
|
||||
{
|
||||
return 'SMTP';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -430,7 +430,6 @@ trait Admin
|
|||
$oSieveClient = new \MailSo\Sieve\ManageSieveClient();
|
||||
$oSieveClient->SetLogger($this->Logger());
|
||||
$oSieveClient->SetTimeOuts($iConnectionTimeout);
|
||||
$oSieveClient->__USE_INITIAL_AUTH_PLAIN_COMMAND = !!$this->Config()->Get('labs', 'sieve_auth_plain_initial', true);
|
||||
|
||||
$iTime = \microtime(true);
|
||||
$oSieveClient->Connect($oDomain->SieveHost(), $oDomain->SievePort(), $oDomain->SieveSecure(),
|
||||
|
|
|
|||
|
|
@ -716,7 +716,7 @@ trait Messages
|
|||
$oSmtpClient->SetTimeOuts(10, (int) \RainLoop\Api::Config()->Get('labs', 'smtp_timeout', 60));
|
||||
|
||||
$oAccount->OutConnectAndLoginHelper(
|
||||
$this->Plugins(), $oSmtpClient, $this->Config(), null, $bUsePhpMail
|
||||
$this->Plugins(), $oSmtpClient, $this->Config(), $bUsePhpMail
|
||||
);
|
||||
|
||||
if ($bUsePhpMail)
|
||||
|
|
|
|||
|
|
@ -85,12 +85,12 @@ class Account
|
|||
|
||||
public function ParentEmailHelper() : string
|
||||
{
|
||||
return 0 < \strlen($this->sParentEmail) ? $this->sParentEmail : $this->sEmail;
|
||||
return \strlen($this->sParentEmail) ? $this->sParentEmail : $this->sEmail;
|
||||
}
|
||||
|
||||
public function IsAdditionalAccount() : string
|
||||
{
|
||||
return 0 < \strlen($this->sParentEmail);
|
||||
return \strlen($this->sParentEmail);
|
||||
}
|
||||
|
||||
public function IncLogin() : string
|
||||
|
|
@ -137,7 +137,7 @@ class Account
|
|||
|
||||
public function SignMe() : bool
|
||||
{
|
||||
return 0 < \strlen($this->sSignMeToken);
|
||||
return \strlen($this->sSignMeToken);
|
||||
}
|
||||
|
||||
public function SignMeToken() : string
|
||||
|
|
@ -262,9 +262,9 @@ class Account
|
|||
));
|
||||
}
|
||||
|
||||
public function IncConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Mail\MailClient $oMailClient, \RainLoop\Config\Application $oConfig, ?callable $refreshTokenCallback = null) : bool
|
||||
public function IncConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Mail\MailClient $oMailClient, \RainLoop\Config\Application $oConfig) : bool
|
||||
{
|
||||
$bLogin = false;
|
||||
$oImapClient = $oMailClient->ImapClient();
|
||||
|
||||
$aImapCredentials = array(
|
||||
'UseConnect' => true,
|
||||
|
|
@ -273,54 +273,25 @@ class Account
|
|||
'Port' => $this->DomainIncPort(),
|
||||
'Secure' => $this->DomainIncSecure(),
|
||||
'Login' => $this->IncLogin(),
|
||||
'Password' => $this->Password(),
|
||||
'ProxyAuthUser' => $this->ProxyAuthUser(),
|
||||
'ProxyAuthPassword' => $this->ProxyAuthPassword(),
|
||||
'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false),
|
||||
'ClientCert' => $this->ClientCert(),
|
||||
'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true),
|
||||
'UseAuthPlainIfSupported' => !!$oConfig->Get('labs', 'imap_use_auth_plain', true),
|
||||
'UseAuthCramMd5IfSupported' => !!$oConfig->Get('labs', 'imap_use_auth_cram_md5', true)
|
||||
'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true)
|
||||
);
|
||||
|
||||
$oPlugins->RunHook('filter.imap-credentials', array($this, &$aImapCredentials));
|
||||
|
||||
$oPlugins->RunHook('imap.before-connect', array($this, $oMailClient, $aImapCredentials));
|
||||
$oPlugins->RunHook('imap.before-connect', array($this, $oImapClient, &$aImapCredentials));
|
||||
if ($aImapCredentials['UseConnect']) {
|
||||
$oMailClient
|
||||
->Connect($aImapCredentials['Host'], $aImapCredentials['Port'],
|
||||
$oImapClient->Connect($aImapCredentials['Host'], $aImapCredentials['Port'],
|
||||
$aImapCredentials['Secure'], $aImapCredentials['VerifySsl'],
|
||||
$aImapCredentials['AllowSelfSigned'], $aImapCredentials['ClientCert']);
|
||||
|
||||
}
|
||||
$oPlugins->RunHook('imap.after-connect', array($this, $oMailClient, $aImapCredentials));
|
||||
$oPlugins->RunHook('imap.after-connect', array($this, $oImapClient, $aImapCredentials));
|
||||
|
||||
$oPlugins->RunHook('imap.before-login', array($this, $oMailClient, $aImapCredentials));
|
||||
if ($aImapCredentials['UseAuth']) {
|
||||
if (0 < \strlen($aImapCredentials['ProxyAuthUser']) &&
|
||||
0 < \strlen($aImapCredentials['ProxyAuthPassword']))
|
||||
{
|
||||
$oMailClient
|
||||
->Login($aImapCredentials['ProxyAuthUser'], $aImapCredentials['ProxyAuthPassword'],
|
||||
$aImapCredentials['Login'], $aImapCredentials['UseAuthPlainIfSupported'], $aImapCredentials['UseAuthCramMd5IfSupported']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oMailClient->Login($aImapCredentials['Login'], $aImapCredentials['Password'], '',
|
||||
$aImapCredentials['UseAuthPlainIfSupported'], $aImapCredentials['UseAuthCramMd5IfSupported']);
|
||||
}
|
||||
|
||||
$bLogin = true;
|
||||
}
|
||||
$oPlugins->RunHook('imap.after-login', array($this, $oMailClient, $bLogin, $aImapCredentials));
|
||||
|
||||
return $bLogin;
|
||||
return $this->netClientLogin($oImapClient, $oConfig, $oPlugins, $aImapCredentials);
|
||||
}
|
||||
|
||||
public function OutConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Smtp\SmtpClient $oSmtpClient, \RainLoop\Config\Application $oConfig, ?callable $refreshTokenCallback = null, bool &$bUsePhpMail = false) : bool
|
||||
public function OutConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Smtp\SmtpClient $oSmtpClient, \RainLoop\Config\Application $oConfig, bool &$bUsePhpMail = false) : bool
|
||||
{
|
||||
$bLogin = false;
|
||||
|
||||
$aSmtpCredentials = array(
|
||||
'UseConnect' => !$bUsePhpMail,
|
||||
'UseAuth' => $this->DomainOutAuth(),
|
||||
|
|
@ -330,21 +301,14 @@ class Account
|
|||
'Port' => $this->DomainOutPort(),
|
||||
'Secure' => $this->DomainOutSecure(),
|
||||
'Login' => $this->OutLogin(),
|
||||
'Password' => $this->Password(),
|
||||
'ProxyAuthUser' => $this->ProxyAuthUser(),
|
||||
'ProxyAuthPassword' => $this->ProxyAuthPassword(),
|
||||
'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false),
|
||||
'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true),
|
||||
'UseAuthPlainIfSupported' => !!$oConfig->Get('labs', 'smtp_use_auth_plain', true),
|
||||
'UseAuthCramMd5IfSupported' => !!$oConfig->Get('labs', 'smtp_use_auth_cram_md5', true)
|
||||
'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true)
|
||||
);
|
||||
|
||||
$oPlugins->RunHook('smtp.credentials', array($this, &$aSmtpCredentials));
|
||||
|
||||
$oPlugins->RunHook('smtp.before-connect', array($this, $oSmtpClient, &$aSmtpCredentials));
|
||||
$bUsePhpMail = $aSmtpCredentials['UsePhpMail'];
|
||||
|
||||
$oPlugins->RunHook('smtp.before-connect', array($this, $oSmtpClient, $aSmtpCredentials));
|
||||
if ($aSmtpCredentials['UseConnect']) {
|
||||
$aSmtpCredentials['UseAuth'] = $aSmtpCredentials['UseAuth'] && !$aSmtpCredentials['UsePhpMail'];
|
||||
if ($aSmtpCredentials['UseConnect'] && !$aSmtpCredentials['UsePhpMail']) {
|
||||
$oSmtpClient->Connect($aSmtpCredentials['Host'], $aSmtpCredentials['Port'],
|
||||
$aSmtpCredentials['Secure'], $aSmtpCredentials['VerifySsl'], $aSmtpCredentials['AllowSelfSigned'],
|
||||
'', $aSmtpCredentials['Ehlo']
|
||||
|
|
@ -352,23 +316,11 @@ class Account
|
|||
}
|
||||
$oPlugins->RunHook('smtp.after-connect', array($this, $oSmtpClient, $aSmtpCredentials));
|
||||
|
||||
$oPlugins->RunHook('smtp.before-login', array($this, $oSmtpClient, $aSmtpCredentials));
|
||||
if ($aSmtpCredentials['UseAuth'] && !$aSmtpCredentials['UsePhpMail'] && $oSmtpClient)
|
||||
{
|
||||
$oSmtpClient->Login($aSmtpCredentials['Login'], $aSmtpCredentials['Password'],
|
||||
$aSmtpCredentials['UseAuthPlainIfSupported'], $aSmtpCredentials['UseAuthCramMd5IfSupported']);
|
||||
|
||||
$bLogin = true;
|
||||
}
|
||||
$oPlugins->RunHook('smtp.after-login', array($this, $oSmtpClient, $bLogin, $aSmtpCredentials));
|
||||
|
||||
return $bLogin;
|
||||
return $this->netClientLogin($oSmtpClient, $oConfig, $oPlugins, $aSmtpCredentials);
|
||||
}
|
||||
|
||||
public function SieveConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Sieve\ManageSieveClient $oSieveClient, \RainLoop\Config\Application $oConfig)
|
||||
{
|
||||
$bLogin = false;
|
||||
|
||||
$aSieveCredentials = array(
|
||||
'UseConnect' => true,
|
||||
'UseAuth' => true,
|
||||
|
|
@ -376,17 +328,12 @@ class Account
|
|||
'Port' => $this->DomainSievePort(),
|
||||
'Secure' => $this->DomainSieveSecure(),
|
||||
'Login' => $this->IncLogin(),
|
||||
'Password' => $this->Password(),
|
||||
'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false),
|
||||
'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true),
|
||||
'InitialAuthPlain' => !!$oConfig->Get('ssl', 'sieve_auth_plain_initial', true)
|
||||
);
|
||||
|
||||
$oPlugins->RunHook('sieve.credentials', array($this, &$aSieveCredentials));
|
||||
|
||||
$oSieveClient->__USE_INITIAL_AUTH_PLAIN_COMMAND = $aSieveCredentials['InitialAuthPlain'];
|
||||
|
||||
$oPlugins->RunHook('sieve.before-connect', array($this, $oSieveClient, $aSieveCredentials));
|
||||
$oPlugins->RunHook('sieve.before-connect', array($this, $oSieveClient, &$aSieveCredentials));
|
||||
if ($aSieveCredentials['UseConnect']) {
|
||||
$oSieveClient->Connect($aSieveCredentials['Host'], $aSieveCredentials['Port'],
|
||||
$aSieveCredentials['Secure'], $aSieveCredentials['VerifySsl'], $aSieveCredentials['AllowSelfSigned']
|
||||
|
|
@ -394,13 +341,82 @@ class Account
|
|||
}
|
||||
$oPlugins->RunHook('sieve.after-connect', array($this, $oSieveClient, $aSieveCredentials));
|
||||
|
||||
$oPlugins->RunHook('event.sieve-pre-login', array($this, $oSieveClient, $aSieveCredentials));
|
||||
if ($aSieveCredentials['UseAuth']) {
|
||||
$oSieveClient->Login($aSieveCredentials['Login'], $aSieveCredentials['Password']);
|
||||
$bLogin = true;
|
||||
}
|
||||
$oPlugins->RunHook('sieve.after-login', array($this, $oSieveClient, $bLogin, $aSieveCredentials));
|
||||
|
||||
return $bLogin;
|
||||
return $this->netClientLogin($oSieveClient, $oConfig, $oPlugins, $aSieveCredentials);
|
||||
}
|
||||
|
||||
private function netClientLogin(\MailSo\Net\NetClient $oClient, \RainLoop\Config\Application $oConfig, \RainLoop\Plugins\Manager $oPlugins, array $aCredentials) : bool
|
||||
{
|
||||
$aCredentials = \array_merge(
|
||||
$aCredentials,
|
||||
array(
|
||||
'Password' => $this->Password(),
|
||||
'ProxyAuthUser' => $this->ProxyAuthUser(),
|
||||
'ProxyAuthPassword' => $this->ProxyAuthPassword(),
|
||||
'UseAuthPlainIfSupported' => !!$oConfig->Get('labs', 'imap_use_auth_plain', true),
|
||||
'UseAuthCramMd5IfSupported' => !!$oConfig->Get('labs', 'imap_use_auth_cram_md5', true),
|
||||
'UseAuthOAuth2IfSupported' => false
|
||||
)
|
||||
);
|
||||
|
||||
$client_name = \strtolower($oClient->getLogName());
|
||||
|
||||
$oPlugins->RunHook("{$client_name}.before-login", array($this, $oClient, &$aCredentials));
|
||||
$bResult = $aCredentials['UseAuth'] && $oClient->Login($aCredentials);
|
||||
$oPlugins->RunHook("{$client_name}.after-login", array($this, $oClient, $bResult, $aCredentials));
|
||||
return $bResult;
|
||||
|
||||
/*
|
||||
// $encrypted = !empty(\stream_get_meta_data($oClient->ConnectionResource())['crypto']);
|
||||
$type = $oClient->IsSupported('LOGINDISABLED') ? '' : 'LOGIN'; // RFC3501 6.2.3
|
||||
$types = [
|
||||
// 'SCRAM-SHA-256' => 1, // !$encrypted
|
||||
// 'SCRAM-SHA-1' => 1, // !$encrypted
|
||||
'CRAM-MD5' => $aSmtpCredentials['UseAuthCramMd5IfSupported'],
|
||||
'PLAIN' => $aSmtpCredentials['UseAuthPlainIfSupported'],
|
||||
'OAUTHBEARER' => $aSmtpCredentials['UseAuthOAuth2IfSupported'],
|
||||
'XOAUTH2' => $aSmtpCredentials['UseAuthOAuth2IfSupported'],
|
||||
'LOGIN' => 1,
|
||||
];
|
||||
foreach ($types as $sasl_type => $active) {
|
||||
if ($active && $oClient->IsSupported("AUTH={$sasl_type}") && \SnappyMail\SASL::isSupported($sasl_type)) {
|
||||
$type = $sasl_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$SASL = \SnappyMail\SASL::factory($type);
|
||||
$SASL->base64 = true;
|
||||
|
||||
// $oClient->Login($SASL);
|
||||
*/
|
||||
/*
|
||||
// $encrypted = !empty(\stream_get_meta_data($oClient->ConnectionResource())['crypto']);
|
||||
$type = '';
|
||||
$types = [
|
||||
'SCRAM-SHA-256' => 1, // !$encrypted
|
||||
'SCRAM-SHA-1' => 1, // !$encrypted
|
||||
'CRAM-MD5' => $bUseAuthCramMd5IfSupported,
|
||||
'PLAIN' => $bUseAuthPlainIfSupported,
|
||||
'LOGIN' => 1, // $encrypted
|
||||
'XOAUTH2' => 0
|
||||
];
|
||||
foreach ($types as $sasl_type => $active) {
|
||||
if ($active && $oClient->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) {
|
||||
$type = $sasl_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$type) {
|
||||
\trigger_error("SMTP {$oClient->GetConnectedHost()} no supported AUTH options. Disable login" . ($oClient->IsSupported('STARTTLS') ? ' or try with STARTTLS' : ''));
|
||||
$oClient->writeLogException(
|
||||
new \MailSo\Smtp\Exceptions\LoginBadMethodException,
|
||||
\MailSo\Log\Enumerations\Type::NOTICE, true);
|
||||
}
|
||||
|
||||
$SASL = \SnappyMail\SASL::factory($type);
|
||||
$SASL->base64 = true;
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ abstract class SASL
|
|||
public static function isSupported(string $type) : bool
|
||||
{
|
||||
if (\preg_match('/^([A-Z2]+)(?:-(.+))?$/Di', $type, $m)) {
|
||||
if ('XOAUTH2' === $m[1] || 'OAUTHBEARER' === $m[1]) {
|
||||
$m[1] = 'OAUTH';
|
||||
}
|
||||
$class = __CLASS__ . "\\{$m[1]}";
|
||||
return \class_exists($class) && $class::isSupported($m[2] ?? '');
|
||||
}
|
||||
|
|
|
|||
21
snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauth.php
Normal file
21
snappymail/v/0.0.0/app/libraries/snappymail/sasl/oauth.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
/**
|
||||
* https://datatracker.ietf.org/doc/html/rfc7628
|
||||
* https://developers.google.com/gmail/imap/xoauth2-protocol
|
||||
*/
|
||||
|
||||
|
||||
namespace SnappyMail\SASL;
|
||||
|
||||
class OAuth extends \SnappyMail\SASL
|
||||
{
|
||||
public function authenticate(string $username, string $passphrase, ?string $authzid = null) : string
|
||||
{
|
||||
return $this->encode("user={$username}\x01auth=Bearer {$passphrase}\x01\x01");
|
||||
}
|
||||
|
||||
public static function isSupported(string $param) : bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue