mirror of
https://github.com/the-djmaze/snappymail.git
synced 2024-09-20 07:35:55 +08:00
Extend handling login credentials by allowing to modify SMTP username
This commit is contained in:
parent
3a6a5a6925
commit
e554bcc27e
|
@ -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:
|
||||
|
|
|
@ -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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue