snappymail/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php
the-djmaze a5caae8991 Rename OutConnectAndLoginHelper to SmtpConnectAndLoginHelper
Rename IncConnectAndLoginHelper to ImapConnectAndLoginHelper
2022-07-21 18:37:37 +02:00

336 lines
9.9 KiB
PHP

<?php
namespace RainLoop\Model;
use RainLoop\Utils;
use RainLoop\Notifications;
use RainLoop\Exceptions\ClientException;
abstract class Account implements \JsonSerializable
{
/**
* @var string
*/
private $sEmail;
/**
* @var string
*/
private $sLogin;
/**
* @var string
*/
private $sPassword;
/**
* @var string
*/
private $sProxyAuthUser = '';
/**
* @var string
*/
private $sProxyAuthPassword = '';
/**
* @var \RainLoop\Model\Domain
*/
private $oDomain;
public function Email() : string
{
return $this->sEmail;
}
public function ProxyAuthUser() : string
{
return $this->sProxyAuthUser;
}
public function ProxyAuthPassword() : string
{
return $this->sProxyAuthPassword;
}
public function IncLogin() : string
{
$sLogin = $this->sLogin;
if ($this->oDomain->IncShortLogin())
{
$sLogin = \MailSo\Base\Utils::GetAccountNameFromEmail($this->sLogin);
}
return $sLogin;
}
public function IncPassword() : string
{
return $this->sPassword;
}
public function OutLogin() : string
{
$sLogin = $this->sLogin;
if ($this->oDomain->OutShortLogin())
{
$sLogin = \MailSo\Base\Utils::GetAccountNameFromEmail($this->sLogin);
}
return $sLogin;
}
public function Login() : string
{
return $this->IncLogin();
}
public function Password() : string
{
return $this->IncPassword();
}
public function Domain() : Domain
{
return $this->oDomain;
}
public function Hash() : string
{
return \sha1(\implode(APP_SALT, [
$this->sEmail,
$this->Domain()->IncHost(),
$this->Domain()->IncPort(),
$this->sPassword
]));
}
public function SetPassword(string $sPassword) : void
{
$this->sPassword = $sPassword;
}
public function SetProxyAuthUser(string $sProxyAuthUser) : void
{
$this->sProxyAuthUser = $sProxyAuthUser;
}
public function SetProxyAuthPassword(string $sProxyAuthPassword) : void
{
$this->sProxyAuthPassword = $sProxyAuthPassword;
}
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return array(
'account', // 0
$this->sEmail, // 1
$this->sLogin, // 2
$this->sPassword, // 3
'', // 4 sClientCert
$this->sProxyAuthUser, // 5
$this->sProxyAuthPassword // 6
);
}
public static function NewInstanceFromCredentials(\RainLoop\Actions $oActions,
string $sEmail, string $sLogin, string $sPassword, bool $bThrowException = false): ?self
{
$oAccount = null;
if ($sEmail && $sLogin && $sPassword) {
$oDomain = $oActions->DomainProvider()->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail), true);
if ($oDomain) {
if ($oDomain->ValidateWhiteList($sEmail, $sLogin)) {
$oAccount = new static;
$oAccount->sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true);
$oAccount->sLogin = \MailSo\Base\Utils::IdnToAscii($sLogin);
$oAccount->sPassword = $sPassword;
$oAccount->oDomain = $oDomain;
$oActions->Plugins()->RunHook('filter.account', array($oAccount));
if ($bThrowException && !$oAccount) {
throw new ClientException(Notifications::AccountFilterError);
}
} else if ($bThrowException) {
throw new ClientException(Notifications::AccountNotAllowed);
}
} else if ($bThrowException) {
throw new ClientException(Notifications::DomainNotAllowed);
}
}
return $oAccount;
}
public static function NewInstanceFromTokenArray(
\RainLoop\Actions $oActions,
array $aAccountHash,
bool $bThrowExceptionOnFalse = false): ?self
{
if (!empty($aAccountHash[0]) && 'account' === $aAccountHash[0] && 7 <= \count($aAccountHash)) {
$oAccount = static::NewInstanceFromCredentials(
$oActions,
$aAccountHash[1] ?: '',
$aAccountHash[2] ?: '',
$aAccountHash[3] ?: '',
$bThrowExceptionOnFalse
);
if ($oAccount) {
// init proxy user/password
if (!empty($aAccountHash[5]) && !empty($aAccountHash[6])) {
$oAccount->SetProxyAuthUser($aAccountHash[5]);
$oAccount->SetProxyAuthPassword($aAccountHash[6]);
}
$oActions->Logger()->AddSecret($oAccount->Password());
$oActions->Logger()->AddSecret($oAccount->ProxyAuthPassword());
return $oAccount;
}
}
return null;
}
public function ImapConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Mail\MailClient $oMailClient, \RainLoop\Config\Application $oConfig) : bool
{
$oImapClient = $oMailClient->ImapClient();
$oImapClient->__FORCE_SELECT_ON_EXAMINE__ = !!$oConfig->Get('labs', 'use_imap_force_selection');
$oImapClient->__DISABLE_METADATA = !!$oConfig->Get('labs', 'imap_disable_metadata');
$aCredentials = \array_merge(
$this->Domain()->ImapSettings(),
array(
'Login' => $this->IncLogin(),
'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false),
'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true),
'ClientCert' => \trim($oConfig->Get('ssl', 'client_cert', ''))
)
);
$oPlugins->RunHook('imap.before-connect', array($this, $oImapClient, &$aCredentials));
if ($aCredentials['UseConnect']) {
$oSettings = new \MailSo\Net\ConnectSettings;
$oSettings->host = $aCredentials['Host'];
$oSettings->port = $aCredentials['Port'];
$oSettings->type = $aCredentials['Secure'];
$oSettings->ssl['verify_peer'] = !!$aCredentials['VerifySsl'];
$oSettings->ssl['verify_peer_name'] = !!$aCredentials['VerifySsl'];
$oSettings->ssl['allow_self_signed'] = !!$aCredentials['AllowSelfSigned'];
if ($aCredentials['ClientCert']) {
$oSettings->ssl['local_cert'] = $aCredentials['ClientCert'];
}
$oImapClient->Connect($oSettings);
}
$oPlugins->RunHook('imap.after-connect', array($this, $oImapClient, $aCredentials));
return $this->netClientLogin($oImapClient, $oConfig, $oPlugins, $aCredentials);
}
public function SmtpConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Smtp\SmtpClient $oSmtpClient, \RainLoop\Config\Application $oConfig, bool &$bUsePhpMail = false) : bool
{
$aCredentials = \array_merge(
$this->Domain()->SmtpSettings(),
array(
'UseConnect' => !$bUsePhpMail,
'UsePhpMail' => $bUsePhpMail,
'Login' => $this->OutLogin(),
'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false),
'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true)
)
);
$oPlugins->RunHook('smtp.before-connect', array($this, $oSmtpClient, &$aCredentials));
$bUsePhpMail = $aCredentials['UsePhpMail'];
$aCredentials['UseAuth'] = $aCredentials['UseAuth'] && !$aCredentials['UsePhpMail'];
if ($aCredentials['UseConnect'] && !$aCredentials['UsePhpMail']) {
$oSettings = new \MailSo\Net\ConnectSettings;
$oSettings->host = $aCredentials['Host'];
$oSettings->port = $aCredentials['Port'];
$oSettings->type = $aCredentials['Secure'];
$oSettings->ssl['verify_peer'] = !!$aCredentials['VerifySsl'];
$oSettings->ssl['verify_peer_name'] = !!$aCredentials['VerifySsl'];
$oSettings->ssl['allow_self_signed'] = !!$aCredentials['AllowSelfSigned'];
$oSmtpClient->Connect($oSettings, $aCredentials['Ehlo']);
}
$oPlugins->RunHook('smtp.after-connect', array($this, $oSmtpClient, $aCredentials));
return $this->netClientLogin($oSmtpClient, $oConfig, $oPlugins, $aCredentials);
}
public function SieveConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Sieve\ManageSieveClient $oSieveClient, \RainLoop\Config\Application $oConfig)
{
$aCredentials = \array_merge(
$this->Domain()->SieveSettings(),
array(
'Login' => $this->IncLogin(),
'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false),
'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true),
'InitialAuthPlain' => !!$oConfig->Get('labs', 'sieve_auth_plain_initial', true)
)
);
$oPlugins->RunHook('sieve.before-connect', array($this, $oSieveClient, &$aCredentials));
if ($aCredentials['UseConnect']) {
$oSettings = new \MailSo\Net\ConnectSettings;
$oSettings->host = $aCredentials['Host'];
$oSettings->port = $aCredentials['Port'];
$oSettings->type = $aCredentials['Secure'];
$oSettings->ssl['verify_peer'] = !!$aCredentials['VerifySsl'];
$oSettings->ssl['verify_peer_name'] = !!$aCredentials['VerifySsl'];
$oSettings->ssl['allow_self_signed'] = !!$aCredentials['AllowSelfSigned'];
$oSieveClient->Connect($oSettings);
}
$oPlugins->RunHook('sieve.after-connect', array($this, $oSieveClient, $aCredentials));
return $this->netClientLogin($oSieveClient, $oConfig, $oPlugins, $aCredentials);
}
private function netClientLogin(\MailSo\Net\NetClient $oClient, \RainLoop\Config\Application $oConfig, \RainLoop\Plugins\Manager $oPlugins, array $aCredentials) : bool
{
/*
$encrypted = !empty(\stream_get_meta_data($oClient->ConnectionResource())['crypto']);
[crypto] => Array(
[protocol] => TLSv1.3
[cipher_name] => TLS_AES_256_GCM_SHA384
[cipher_bits] => 256
[cipher_version] => TLSv1.3
)
*/
/**
* TODO: move these to Admin -> Domains -> per Domain management?
*/
$aSASLMechanisms = [];
if ($oConfig->Get('labs', 'sasl_allow_scram_sha', false)) {
// https://github.com/the-djmaze/snappymail/issues/182
\array_push($aSASLMechanisms, 'SCRAM-SHA3-512', 'SCRAM-SHA-512', 'SCRAM-SHA-256', 'SCRAM-SHA-1');
}
if ($oConfig->Get('labs', 'sasl_allow_cram_md5', false)) {
$aSASLMechanisms[] = 'CRAM-MD5';
}
if ($oConfig->Get('labs', 'sasl_allow_plain', true)) {
$aSASLMechanisms[] = 'PLAIN';
}
$aCredentials = \array_merge(
$aCredentials,
array(
'Password' => $this->Password(),
'ProxyAuthUser' => $this->ProxyAuthUser(),
'ProxyAuthPassword' => $this->ProxyAuthPassword(),
'SASLMechanisms' => $aSASLMechanisms
)
);
$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;
}
}