Extend handling login credentials by allowing to modify SMTP username

This commit is contained in:
the-djmaze 2024-04-17 01:09:07 +02:00
parent 3a6a5a6925
commit e554bcc27e
12 changed files with 220 additions and 183 deletions

View file

@ -132,8 +132,9 @@ $Plugin->addHook('hook.name', 'functionName');
### login.credentials
params:
string &$sEmail
string &$sLogin
string &$sImapUser
string &$sPassword
string &$sSmtpUser
### login.success
params:

View file

@ -56,11 +56,11 @@ class LoginRemotePlugin extends \RainLoop\Plugins\AbstractPlugin
return true;
}
public function FilterLoginCredentials(&$sEmail, &$sLogin, &$sPassword)
public function FilterLoginCredentials(&$sEmail, &$sImapUser, &$sPassword, &$sSmtpUser)
{
// cPanel https://github.com/the-djmaze/snappymail/issues/697
// && !empty($_ENV['CPANEL'])
if (static::$login/* && $sLogin == $_ENV['REMOTE_USER']*/) {
if (static::$login/* && $sImapUser == $_ENV['REMOTE_USER']*/) {
if (empty($_ENV['REMOTE_TEMP_USER'])) {
$iPos = \strpos($sPassword, '[::cpses::]');
if ($iPos) {
@ -68,7 +68,8 @@ class LoginRemotePlugin extends \RainLoop\Plugins\AbstractPlugin
}
}
if (!empty($_ENV['REMOTE_TEMP_USER'])) {
$sLogin = $_ENV['REMOTE_USER'] . '/' . $_ENV['REMOTE_TEMP_USER'];
$sImapUser = $_ENV['REMOTE_USER'] . '/' . $_ENV['REMOTE_TEMP_USER'];
$sSmtpUser = $_ENV['REMOTE_USER'] . '/' . $_ENV['REMOTE_TEMP_USER'];
}
}
}

View file

@ -11,6 +11,8 @@
namespace MailSo\Mime;
use MailSo\Base\Utils;
/**
* @category MailSo
* @package Mime
@ -38,9 +40,9 @@ class Email implements \JsonSerializable
throw new \ValueError;
}
$this->sEmail = \SnappyMail\IDN::emailToAscii(\MailSo\Base\Utils::Trim($sEmail));
$this->sEmail = \SnappyMail\IDN::emailToAscii(Utils::Trim($sEmail));
$this->sDisplayName = \MailSo\Base\Utils::Trim($sDisplayName);
$this->sDisplayName = Utils::Trim($sDisplayName);
}
/**
@ -48,8 +50,7 @@ class Email implements \JsonSerializable
*/
public static function Parse(string $sEmailAddress) : self
{
$sEmailAddress = \MailSo\Base\Utils::DecodeHeaderValue($sEmailAddress);
$sEmailAddress = \MailSo\Base\Utils::Trim($sEmailAddress);
$sEmailAddress = Utils::Trim(Utils::DecodeHeaderValue($sEmailAddress));
if (!\strlen(\trim($sEmailAddress))) {
throw new \ValueError;
}
@ -63,7 +64,6 @@ class Email implements \JsonSerializable
$bInComment = false;
$iStartIndex = 0;
$iEndIndex = 0;
$iCurrentIndex = 0;
while ($iCurrentIndex < \strlen($sEmailAddress)) {
@ -76,10 +76,8 @@ class Email implements \JsonSerializable
$bInName = true;
$iStartIndex = $iCurrentIndex;
} else if (!$bInAddress && !$bInComment) {
$iEndIndex = $iCurrentIndex;
$sName = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
$sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
$iEndIndex = 0;
$sName = \substr($sEmailAddress, $iStartIndex + 1, $iCurrentIndex - $iStartIndex - 1);
$sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iCurrentIndex - $iStartIndex + 1);
$iCurrentIndex = 0;
$iStartIndex = 0;
$bInName = false;
@ -97,10 +95,8 @@ class Email implements \JsonSerializable
break;
case '>':
if ($bInAddress) {
$iEndIndex = $iCurrentIndex;
$sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
$sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
$iEndIndex = 0;
$sEmail = \substr($sEmailAddress, $iStartIndex + 1, $iCurrentIndex - $iStartIndex - 1);
$sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iCurrentIndex - $iStartIndex + 1);
$iCurrentIndex = 0;
$iStartIndex = 0;
$bInAddress = false;
@ -114,10 +110,8 @@ class Email implements \JsonSerializable
break;
case ')':
if ($bInComment) {
$iEndIndex = $iCurrentIndex;
$sComment = \substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
$sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
$iEndIndex = 0;
$sComment = \substr($sEmailAddress, $iStartIndex + 1, $iCurrentIndex - $iStartIndex - 1);
$sEmailAddress = \substr_replace($sEmailAddress, '', $iStartIndex, $iCurrentIndex - $iStartIndex + 1);
$iCurrentIndex = 0;
$iStartIndex = 0;
$bInComment = false;
@ -159,9 +153,9 @@ class Email implements \JsonSerializable
return new self($sEmail, $sName);
}
public function GetEmail(bool $bIdn = false) : string
public function GetEmail(bool $bUtf8 = false) : string
{
return $bIdn ? \SnappyMail\IDN::emailToUtf8($this->sEmail) : $this->sEmail;
return $bUtf8 ? \SnappyMail\IDN::emailToUtf8($this->sEmail) : $this->sEmail;
}
public function GetDisplayName() : string
@ -171,12 +165,12 @@ class Email implements \JsonSerializable
public function getLocalPart() : string
{
return \MailSo\Base\Utils::getEmailAddressLocalPart($this->sEmail);
return Utils::getEmailAddressLocalPart($this->sEmail);
}
public function GetDomain(bool $bIdn = false) : string
{
return \MailSo\Base\Utils::getEmailAddressDomain($this->GetEmail($bIdn));
return Utils::getEmailAddressDomain($this->GetEmail($bIdn));
}
public function SetDkimStatus(string $sDkimStatus)
@ -184,24 +178,21 @@ class Email implements \JsonSerializable
$this->sDkimStatus = Enumerations\DkimStatus::normalizeValue($sDkimStatus);
}
public function ToString(bool $bConvertSpecialsName = false, bool $bIdn = false) : string
public function ToString(bool $bConvertSpecialsName = false, bool $bUtf8 = false) : string
{
$sReturn = '';
$sDisplayName = \str_replace('"', '\"', $this->sDisplayName);
if ($bConvertSpecialsName) {
$sDisplayName = \strlen($sDisplayName) ? \MailSo\Base\Utils::EncodeHeaderValue($sDisplayName) : '';
}
$sDisplayName = \strlen($sDisplayName) ? '"'.$sDisplayName.'"' : '';
if (\strlen($this->sEmail)) {
$sReturn = $this->GetEmail($bIdn);
$sReturn = $this->GetEmail($bUtf8);
$sDisplayName = $this->sDisplayName;
if (\strlen($sDisplayName)) {
$sReturn = $sDisplayName.' <'.$sReturn.'>';
$sDisplayName = \str_replace('"', '\"', $sDisplayName);
if ($bConvertSpecialsName) {
$sDisplayName = Utils::EncodeHeaderValue($sDisplayName);
}
$sReturn = '"'.$sDisplayName.'" <'.$sReturn.'>';
}
}
return \trim($sReturn);
return $sReturn;
}
public function __toString() : string
@ -214,8 +205,8 @@ class Email implements \JsonSerializable
{
return array(
'@Object' => 'Object/Email',
'name' => \MailSo\Base\Utils::Utf8Clear($this->GetDisplayName()),
'email' => \MailSo\Base\Utils::Utf8Clear($this->GetEmail(true)),
'name' => Utils::Utf8Clear($this->sDisplayName),
'email' => Utils::Utf8Clear($this->GetEmail(true)),
'dkimStatus' => $this->sDkimStatus
);
}

View file

@ -79,7 +79,7 @@ class ConnectSettings implements \JsonSerializable
$this->passphrase = \is_string($value) ? new SensitiveString($value) : $value;
}
if ('username' === $name || 'login' === $name) {
$this->username = $this->fixUsername($value);
$this->username = $value;
}
}

View file

@ -73,35 +73,35 @@ trait Accounts
*/
public function DoAccountSetup(): array
{
$oMainAccount = $this->getMainAccountFromToken();
if (!$this->GetCapa(Capa::ADDITIONAL_ACCOUNTS)) {
return $this->FalseResponse();
}
$oMainAccount = $this->getMainAccountFromToken();
$aAccounts = $this->GetAccounts($oMainAccount);
$sEmail = \trim($this->GetActionParam('email', ''));
$oPassword = new \SnappyMail\SensitiveString($this->GetActionParam('password', ''));
$sName = \trim($this->GetActionParam('name', ''));
$bNew = !empty($this->GetActionParam('new', 1));
$sEmail = IDN::emailToAscii($sEmail);
if ($bNew && ($oMainAccount->Email() === $sEmail || isset($aAccounts[$sEmail]))) {
throw new ClientException(Notifications::AccountAlreadyExists);
} else if (!$bNew && !isset($aAccounts[$sEmail])) {
throw new ClientException(Notifications::AccountDoesNotExist);
}
if ($bNew || \strlen($oPassword)) {
$oNewAccount = $this->LoginProcess($sEmail, $oPassword, false);
$sEmail = $oNewAccount->Email();
$aAccounts[$sEmail] = $oNewAccount->asTokenArray($oMainAccount);
} else {
$aAccounts[$sEmail] = \RainLoop\Model\AdditionalAccount::convertArray($aAccounts[$sEmail]);
}
if ($bNew) {
if ($oMainAccount->Email() === $sEmail || isset($aAccounts[$sEmail])) {
throw new ClientException(Notifications::AccountAlreadyExists);
}
} else if (!isset($aAccounts[$sEmail])) {
throw new ClientException(Notifications::AccountDoesNotExist);
}
if ($aAccounts[$sEmail]) {
$aAccounts[$sEmail]['name'] = $sName;
$aAccounts[$sEmail]['name'] = \trim($this->GetActionParam('name', ''));
$this->SetAccounts($oMainAccount, $aAccounts);
}

View file

@ -63,18 +63,15 @@ trait AdminDomains
public function DoAdminDomainMatch() : array
{
$sEmail = $this->GetActionParam('username');
$oPassword = new \SnappyMail\SensitiveString('********');
$sLogin = '';
$this->resolveLoginCredentials($sEmail, $oPassword, $sLogin);
$oDomain = \str_contains($sEmail, '@')
? $this->DomainProvider()->Load(\MailSo\Base\Utils::getEmailAddressDomain($sEmail), true)
: null;
$sCredentials = $this->resolveLoginCredentials(
$this->GetActionParam('username'),
new \SnappyMail\SensitiveString('********')
);
return $this->DefaultResponse(array(
'email' => $sEmail,
'login' => $sLogin,
'domain' => $oDomain,
'whitelist' => $oDomain ? $oDomain->ValidateWhiteList($sEmail, $sLogin) : null
'email' => $sCredentials['email'],
'login' => $sCredentials['imapUser'],
'domain' => $sCredentials['domain'],
'whitelist' => $sCredentials['domain'] ? $sCredentials['domain']->ValidateWhiteList($sEmail) : null
));
}

View file

@ -35,11 +35,11 @@ trait User
*/
public function DoLogin() : array
{
$sEmail = \MailSo\Base\Utils::Trim($this->GetActionParam('Email', ''));
$oPassword = new \SnappyMail\SensitiveString($this->GetActionParam('Password', ''));
try {
$oAccount = $this->LoginProcess($sEmail, $oPassword);
$oAccount = $this->LoginProcess(
\MailSo\Base\Utils::Trim($this->GetActionParam('Email', '')),
new \SnappyMail\SensitiveString($this->GetActionParam('Password', ''))
);
} catch (\Throwable $oException) {
$this->loginErrorDelay();
throw $oException;

View file

@ -11,6 +11,7 @@ use RainLoop\Model\AdditionalAccount;
use RainLoop\Providers\Storage\Enumerations\StorageType;
use RainLoop\Exceptions\ClientException;
use SnappyMail\Cookies;
use SnappyMail\SensitiveString;
trait UserAuth
{
@ -24,7 +25,7 @@ trait UserAuth
{
return $this->DefaultResponse(
$this->getMainAccountFromToken()->resealCryptKey(
new \SnappyMail\SensitiveString($this->GetActionParam('passphrase', ''))
new SensitiveString($this->GetActionParam('passphrase', ''))
)
);
}
@ -32,7 +33,7 @@ trait UserAuth
/**
* @throws \RainLoop\Exceptions\ClientException
*/
public function resolveLoginCredentials(string &$sEmail, \SnappyMail\SensitiveString $oPassword, string &$sLogin): void
protected function resolveLoginCredentials(string $sEmail, SensitiveString $oPassword): array
{
$sEmail = \SnappyMail\IDN::emailToAscii(\MailSo\Base\Utils::Trim($sEmail));
@ -40,28 +41,31 @@ trait UserAuth
$oDomain = null;
$oDomainProvider = $this->DomainProvider();
// When email address is missing the domain, try to add it
if (!\str_contains($sEmail, '@')) {
$this->logWrite("The email address '{$sEmail}' is incomplete", \LOG_INFO, 'LOGIN');
if ($this->Config()->Get('login', 'determine_user_domain', false)) {
// $sUserHost = \SnappyMail\IDN::toAscii($this->Http()->GetHost(false, true));
$sUserHost = \strtolower(\idn_to_ascii($this->Http()->GetHost(false, true)));
$sUserHost = \SnappyMail\IDN::toAscii($this->Http()->GetHost(false, true));
$this->logWrite("Determined user domain: {$sUserHost}", \LOG_INFO, 'LOGIN');
// Determine without wildcard
$aDomainParts = \explode('.', $sUserHost);
$iLimit = \min(\count($aDomainParts), 14);
while (0 < $iLimit--) {
$sLine = \implode('.', $aDomainParts);
$oDomain = $oDomainProvider->Load($sLine, false);
$sDomain = \implode('.', $aDomainParts);
$oDomain = $oDomainProvider->Load($sDomain, false);
if ($oDomain) {
$sEmail .= '@' . $sLine;
$this->logWrite("Check '{$sLine}': OK", \LOG_INFO, 'LOGIN');
$sEmail .= '@' . $sDomain;
$this->logWrite("Check '{$sDomain}': OK", \LOG_INFO, 'LOGIN');
break;
} else {
$this->logWrite("Check '{$sLine}': NO", \LOG_INFO, 'LOGIN');
$this->logWrite("Check '{$sDomain}': NO", \LOG_INFO, 'LOGIN');
}
\array_shift($aDomainParts);
}
// Else determine with wildcard
if (!$oDomain) {
$oDomain = $oDomainProvider->Load($sUserHost, true);
if ($oDomain) {
@ -77,6 +81,7 @@ trait UserAuth
}
}
// Else try default domain
if (!$oDomain) {
$sDefDomain = \trim($this->Config()->Get('login', 'default_domain', ''));
if (\strlen($sDefDomain)) {
@ -97,43 +102,57 @@ trait UserAuth
$this->Plugins()->RunHook('login.credentials.step-2', array(&$sEmail, &$sPassword));
$this->logMask($sPassword);
$sLogin = $sEmail;
$sImapUser = $sEmail;
$sSmtpUser = $sEmail;
if (\str_contains($sEmail, '@')
&& ($oDomain || ($oDomain = $oDomainProvider->Load(\MailSo\Base\Utils::getEmailAddressDomain($sEmail))))
&& ($oDomain || ($oDomain = $oDomainProvider->Load(\MailSo\Base\Utils::getEmailAddressDomain($sEmail), true)))
) {
$sEmail = $oDomain->ImapSettings()->fixUsername($sEmail, false);
$sLogin = $oDomain->ImapSettings()->fixUsername($sLogin);
$sImapUser = $oDomain->ImapSettings()->fixUsername($sImapUser);
$sSmtpUser = $oDomain->SmtpSettings()->fixUsername($sSmtpUser);
}
$this->Plugins()->RunHook('login.credentials', array(&$sEmail, &$sLogin, &$sPassword));
$this->Plugins()->RunHook('login.credentials', array(&$sEmail, &$sImapUser, &$sPassword, &$sSmtpUser));
$oPassword->setValue($sPassword);
return [
'email' => $sEmail,
'domain' => $oDomain,
'imapUser' => $sImapUser,
'smtpUser' => $sSmtpUser,
'pass' => $oPassword
];
}
/**
* @throws \RainLoop\Exceptions\ClientException
*/
public function LoginProcess(string &$sEmail, \SnappyMail\SensitiveString $oPassword, bool $bMainAccount = true): Account
public function LoginProcess(string $sEmail, SensitiveString $oPassword, bool $bMainAccount = true): Account
{
$sInputEmail = $sEmail;
$sCredentials = $this->resolveLoginCredentials($sEmail, $oPassword);
$sLogin = '';
$this->resolveLoginCredentials($sEmail, $oPassword, $sLogin);
if (!\str_contains($sEmail, '@') || !\strlen($oPassword)) {
if (!\str_contains($sCredentials['email'], '@') || !\strlen($oPassword)) {
throw new ClientException(Notifications::InvalidInputArgument);
}
$oAccount = null;
try {
$oAccount = $bMainAccount
? MainAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $oPassword, true)
: AdditionalAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $oPassword, true);
$oAccount = $bMainAccount ? new MainAccount : new AdditionalAccount;
$oAccount->setCredentials(
$sCredentials['domain'],
$sCredentials['email'],
$sCredentials['imapUser'],
$oPassword,
$sCredentials['smtpUser']
// ,new SensitiveString($oPassword)
);
$this->Plugins()->RunHook('filter.account', array($oAccount));
if (!$oAccount) {
throw new ClientException(Notifications::AuthError);
throw new ClientException(Notifications::AccountFilterError);
}
} catch (\Throwable $oException) {
$this->LoggerAuthHelper($oAccount, $sInputEmail);
$this->LoggerAuthHelper($oAccount, $sEmail);
throw $oException;
}

View file

@ -15,7 +15,7 @@ abstract class Account implements \JsonSerializable
private string $sImapUser = '';
private ?SensitiveString $oPassword = null;
private ?SensitiveString $oImapPass = null;
private string $sSmtpUser = '';
@ -33,29 +33,20 @@ abstract class Account implements \JsonSerializable
return $this->sName;
}
public function IncLogin() : string
{
return $this->ImapUser();
}
public function ImapUser() : string
{
// return $this->oDomain->ImapSettings()->fixUsername($this->sImapUser);
return $this->sImapUser;
}
public function IncPassword() : string
public function ImapPass() : string
{
return $this->oPassword ? $this->oPassword->getValue() : '';
return $this->oImapPass ? $this->oImapPass->getValue() : '';
}
public function OutLogin() : string
{
return $this->SmtpUser();
}
public function SmtpUser() : string
{
// return $this->oDomain->SmtpSettings()->fixUsername($this->sSmtpUser ?: $this->sEmail);
return $this->sSmtpUser ?: $this->sEmail;
return $this->sSmtpUser ?: $this->oDomain->SmtpSettings()->fixUsername($this->sEmail);
// return $this->sSmtpUser ?: $this->sEmail ?: $this->sImapUser;
}
public function Domain() : Domain
@ -69,16 +60,26 @@ abstract class Account implements \JsonSerializable
$this->sEmail,
$this->sImapUser,
// \json_encode($this->Domain()),
// $this->oPassword
// $this->oImapPass
]));
}
public function SetPassword(SensitiveString $oPassword) : void
public function setImapUser(string $sImapUser) : void
{
$this->oPassword = $oPassword;
$this->sImapUser = $sImapUser;
}
public function SetSmtpPassword(SensitiveString $oPassword) : void
public function setImapPass(SensitiveString $oPassword) : void
{
$this->oImapPass = $oPassword;
}
public function setSmtpUser(string $sSmtpUser) : void
{
$this->sSmtpUser = $sSmtpUser;
}
public function setSmtpPass(SensitiveString $oPassword) : void
{
$this->oSmtpPass = $oPassword;
}
@ -89,49 +90,33 @@ abstract class Account implements \JsonSerializable
$result = [
'email' => $this->sEmail,
'login' => $this->sImapUser,
'pass' => $this->IncPassword(),
'name' => $this->sName
];
if ($this->sSmtpUser && $this->oSmtpPass) {
$result['smtp'] = [
'user' => $this->sSmtpUser,
'pass' => $this->oSmtpPass->getValue()
'pass' => $this->ImapPass(),
'name' => $this->sName,
'smtp' => []
];
if ($this->sSmtpUser) {
$result['smtp']['user'] = $this->sSmtpUser;
}
if ($this->oSmtpPass) {
$result['smtp']['pass'] = $this->oSmtpPass->getValue();
}
return $result;
}
public static function NewInstanceFromCredentials(\RainLoop\Actions $oActions,
string $sEmail, string $sLogin,
SensitiveString $oPassword,
bool $bThrowException = false): ?self
{
$oAccount = null;
if ($sEmail && $sLogin && \strlen($oPassword)) {
$oDomain = $oActions->DomainProvider()->Load(\MailSo\Base\Utils::getEmailAddressDomain($sEmail), true);
if ($oDomain) {
if ($oDomain->ValidateWhiteList($sEmail, $sLogin)) {
$oAccount = new static;
$oAccount->sEmail = \SnappyMail\IDN::emailToAscii($sEmail);
$oAccount->sImapUser = \SnappyMail\IDN::emailToAscii($sLogin);
$oAccount->SetPassword($oPassword);
$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 function setCredentials(
Domain $oDomain,
string $sEmail,
string $sImapUser,
SensitiveString $oImapPass,
string $sSmtpUser = '',
?SensitiveString $oSmtpPass = null
) {
$this->sEmail = $sEmail;
$this->oDomain = $oDomain;
$this->sImapUser = $sImapUser;
$this->oImapPass = $oImapPass;
$this->sSmtpUser = $sSmtpUser;
$this->oSmtpPass = $oSmtpPass;
}
/**
@ -159,22 +144,37 @@ abstract class Account implements \JsonSerializable
{
$oAccount = null;
$aAccountHash = static::convertArray($aAccountHash);
if (!empty($aAccountHash['email']) && 3 <= \count($aAccountHash)) {
$oAccount = static::NewInstanceFromCredentials(
$oActions,
$aAccountHash['email'],
$aAccountHash['login'],
new SensitiveString($aAccountHash['pass']),
$bThrowExceptionOnFalse
);
if (!empty($aAccountHash['email']) && !empty($aAccountHash['login']) && !empty($aAccountHash['pass'])) {
try {
$oDomain = $oActions->DomainProvider()->getByEmailAddress($aAccountHash['email']);
if ($oDomain) {
// $aAccountHash['email'] = $oDomain->ImapSettings()->fixUsername($aAccountHash['email'], false);
// $aAccountHash['login'] = $oDomain->ImapSettings()->fixUsername($aAccountHash['login']);
$oAccount = new static;
$oAccount->sEmail = \SnappyMail\IDN::emailToAscii($aAccountHash['email']);
$oAccount->sImapUser = \SnappyMail\IDN::emailToAscii($aAccountHash['login']);
$oAccount->setImapPass(new SensitiveString($aAccountHash['pass']));
$oAccount->oDomain = $oDomain;
$oActions->Plugins()->RunHook('filter.account', array($oAccount));
if ($bThrowExceptionOnFalse && !$oAccount) {
throw new ClientException(Notifications::AccountFilterError);
}
}
} catch (\Throwable $e) {
if ($bThrowExceptionOnFalse) {
throw $e;
}
}
if ($oAccount) {
if (isset($aAccountHash['name'])) {
$oAccount->sName = $aAccountHash['name'];
}
// init smtp user/password
if (isset($aAccountHash['smtp'])) {
if (isset($aAccountHash['smtp']['user'])) {
$oAccount->sSmtpUser = $aAccountHash['smtp']['user'];
$oAccount->SetSmtpPassword(new SensitiveString($aAccountHash['smtp']['pass']));
}
if (isset($aAccountHash['smtp']['pass'])) {
$oAccount->setSmtpPass(new SensitiveString($aAccountHash['smtp']['pass']));
}
}
}
@ -202,7 +202,7 @@ abstract class Account implements \JsonSerializable
$oImapClient->Connect($oSettings);
$oPlugins->RunHook('imap.after-connect', array($this, $oImapClient, $oSettings));
$oSettings->passphrase = $this->oPassword;
$oSettings->passphrase = $this->oImapPass;
return $this->netClientLogin($oImapClient, $oPlugins);
}
@ -226,7 +226,7 @@ abstract class Account implements \JsonSerializable
throw new RequireCredentialsException
}
*/
$oSettings->passphrase = $this->oSmtpPass ?: $this->oPassword;
$oSettings->passphrase = $this->oSmtpPass ?: $this->oImapPass;
return $this->netClientLogin($oSmtpClient, $oPlugins);
}
@ -241,7 +241,7 @@ abstract class Account implements \JsonSerializable
$oSieveClient->Connect($oSettings);
$oPlugins->RunHook('sieve.after-connect', array($this, $oSieveClient, $oSettings));
$oSettings->passphrase = $this->oPassword;
$oSettings->passphrase = $this->oImapPass;
return $this->netClientLogin($oSieveClient, $oPlugins);
}
@ -273,4 +273,24 @@ abstract class Account implements \JsonSerializable
return \RainLoop\Api::Actions()->SettingsProvider(true)->Load($this);
}
*/
/**
* @deprecated
*/
public function IncLogin() : string
{
return $this->ImapUser();
}
public function IncPassword() : string
{
return $this->ImapPass();
}
public function OutLogin() : string
{
return $this->SmtpUser();
}
public function SetPassword(SensitiveString $oPassword) : void
{
$this->oImapPass = $oPassword;
}
}

View file

@ -104,28 +104,26 @@ class Domain implements \JsonSerializable
$this->aliasName = \strtolower(\idn_to_ascii($sAliasName));
}
public function ValidateWhiteList(string $sEmail, string $sLogin) : bool
public function ValidateWhiteList(string $sEmail) : bool
{
$sW = \trim($this->whiteList);
if ($sW) {
$sEmail = $this->IMAP->fixUsername($sEmail, false);
$sLogin = $this->IMAP->fixUsername($sLogin);
$sUserPart = \MailSo\Base\Utils::getEmailAddressLocalPart($sLogin ?: $sEmail);
$sUserDomain = \MailSo\Base\Utils::getEmailAddressDomain($sEmail);
if (!$sW) {
return true;
}
$sEmail = \SnappyMail\IDN::emailToAscii(\mb_strtolower($sEmail));
$iPos = \strrpos($sEmail, '@');
$sUserPart = \substr($sEmail, 0, $iPos);
$sUserDomain = \substr($sEmail, $iPos);
$sItem = \strtok($sW, " ;,\n");
while (false !== $sItem) {
$sItem = $this->IMAP->fixUsername(\trim($sItem), false);
if ($sLogin === $sItem || $sEmail === $sItem
|| $sUserPart === $sItem || "@{$sUserDomain}" === $sItem
) {
$sItem = \SnappyMail\IDN::emailToAscii(\mb_strtolower(\trim($sItem)));
if ($sItem === $sEmail || $sItem === $sUserPart || $sItem === $sUserDomain) {
return true;
}
$sItem = \strtok(" ;,\n");
}
return false;
}
return true;
}
public function ImapSettings() : \MailSo\Imap\Settings
{

View file

@ -79,4 +79,16 @@ class Domain extends AbstractProvider
{
return $this->oDriver instanceof Domain\DomainInterface;
}
public function getByEmailAddress(string $sEmail) : \RainLoop\Model\Domain
{
$oDomain = $this->Load(\MailSo\Base\Utils::getEmailAddressDomain($sEmail), true);
if (!$oDomain) {
throw new ClientException(Notifications::DomainNotAllowed);
}
if (!$oDomain->ValidateWhiteList($sEmail)) {
throw new ClientException(Notifications::AccountNotAllowed);
}
return $oDomain;
}
}

View file

@ -552,16 +552,14 @@ class ServiceActions
if (\is_array($aData) && !empty($aData['Email']) && isset($aData['Password'], $aData['Time']) &&
(0 === $aData['Time'] || \time() - 10 < $aData['Time']))
{
$sEmail = \trim($aData['Email']);
$oPassword = new \SnappyMail\SensitiveString($aData['Password']);
$aAdditionalOptions = (isset($aData['AdditionalOptions']) && \is_array($aData['AdditionalOptions']))
? $aData['AdditionalOptions'] : [];
try
{
$oAccount = $this->oActions->LoginProcess($sEmail, $oPassword);
$oAccount = $this->oActions->LoginProcess(
\trim($aData['Email']),
new \SnappyMail\SensitiveString($aData['Password'])
);
if ($aAdditionalOptions) {
$bSaveSettings = false;