From 8ca043b6e4d3e4b369adfe4b91aa6569d029ea69 Mon Sep 17 00:00:00 2001 From: djmaze Date: Wed, 10 Nov 2021 00:57:09 +0100 Subject: [PATCH] Improved user authentication system by supporting OpenSSL aes-256-cbc-hmac-sha1 encryption --- .../0.0.0/app/libraries/MailSo/Base/Crypt.php | 12 +- .../0.0.0/app/libraries/RainLoop/Actions.php | 33 +-- .../libraries/RainLoop/Actions/Accounts.php | 4 +- .../libraries/RainLoop/Actions/Messages.php | 7 +- .../app/libraries/RainLoop/Actions/User.php | 27 +- .../libraries/RainLoop/Actions/UserAuth.php | 273 +++++++----------- .../app/libraries/RainLoop/Model/Account.php | 265 ++++++++--------- .../app/libraries/RainLoop/Model/Domain.php | 107 ++++--- .../libraries/RainLoop/Providers/Storage.php | 30 +- .../Providers/Storage/FileStorage.php | 24 +- .../RainLoop/Providers/Storage/IStorage.php | 12 +- .../0.0.0/app/libraries/RainLoop/Service.php | 2 - .../app/libraries/RainLoop/ServiceActions.php | 10 +- .../v/0.0.0/app/libraries/RainLoop/Utils.php | 11 +- .../0.0.0/app/libraries/snappymail/crypt.php | 100 +++++++ snappymail/v/0.0.0/check.php | 1 + 16 files changed, 468 insertions(+), 450 deletions(-) create mode 100644 snappymail/v/0.0.0/app/libraries/snappymail/crypt.php diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Crypt.php b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Crypt.php index 662fceac1..83e621422 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Crypt.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Crypt.php @@ -18,30 +18,22 @@ namespace MailSo\Base; class Crypt { - public static function Encrypt(string $sString, string $sKey, string $sCipher = '') : string + public static function Encrypt(string $sString, string $sKey) : string { if (!\strlen($sString)) { return ''; } - if ($sCipher && \is_callable('openssl_encrypt')) { - $iv = \str_pad('', \openssl_cipher_iv_length($sCipher), \sha1($sKey)); - return \openssl_encrypt($sString, $sCipher, $sKey, OPENSSL_RAW_DATA, $iv); - } if (\is_callable('xxtea_encrypt')) { return \xxtea_encrypt($sString, $sKey); } return Xxtea::encrypt($sString, $sKey); } - public static function Decrypt(string $sString, string $sKey, string $sCipher = '') : string + public static function Decrypt(string $sString, string $sKey) : string { if (!\strlen($sString)) { return ''; } - if ($sCipher && \is_callable('openssl_encrypt')) { - $iv = \str_pad('', \openssl_cipher_iv_length($sCipher), \sha1($sKey)); - return \openssl_decrypt($sString, $sCipher, $sKey, OPENSSL_RAW_DATA, $iv); - } if (\is_callable('xxtea_decrypt')) { return \xxtea_decrypt($sString, $sKey); } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php index 0a405d100..8788e2bf1 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -17,8 +17,20 @@ class Actions use Actions\Themes; const AUTH_MAILTO_TOKEN_KEY = 'smmailtoauth'; + + /** + * This 30 days cookie contains decrypt data, + * to decrypt a \RainLoop\Model\Account which is stored at + * /_data_/.../storage/DOMAIN/LOCAL/.sign_me/* + * Gets refreshed on each login + */ const AUTH_SIGN_ME_TOKEN_KEY = 'smremember'; - const AUTH_SPEC_TOKEN_KEY = 'smspecauth'; + + /** + * This session cookie contains a \RainLoop\Model\Account + */ + const AUTH_SPEC_TOKEN_KEY = 'smaccount'; + const AUTH_SPEC_LOGOUT_TOKEN_KEY = 'smspeclogout'; const AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY = 'smspeclogoutcmk'; @@ -130,7 +142,6 @@ class Actions $this->oAddressBookProvider = null; $this->oSuggestionsProvider = null; - $this->sSpecAuthToken = ''; $this->bIsJson = false; $oConfig = $this->Config(); @@ -309,7 +320,6 @@ class Actions if (false !== \strpos($sLine, '{imap:') || false !== \strpos($sLine, '{smtp:')) { if (!$oAccount) { - $this->getAuthAccountHash(); $oAccount = $this->getAccountFromToken(false); } @@ -363,7 +373,6 @@ class Actions if (\preg_match('/\{user:(email|login|domain)\}/i', $sLine)) { if (!$oAccount) { - $this->getAuthAccountHash(); $oAccount = $this->getAccountFromToken(false); } @@ -871,7 +880,8 @@ class Actions $aResult['IncLogin'] = $oAccount->IncLogin(); $aResult['OutLogin'] = $oAccount->OutLogin(); $aResult['AccountHash'] = $oAccount->Hash(); - $aResult['AccountSignMe'] = $oAccount->SignMe(); +// $aResult['AccountSignMe'] = $oAccount->SignMe(); + $aResult['AccountSignMe'] = false; $aResult['ContactsIsAllowed'] = $oAddressBookProvider->IsActive(); $aResult['ContactsSyncIsAllowed'] = (bool)$oConfig->Get('contacts', 'allow_sync', false); $aResult['ContactsSyncInterval'] = (int)$oConfig->Get('contacts', 'sync_interval', 20); @@ -1066,17 +1076,6 @@ class Actions } } - public function AuthToken(Model\Account $oAccount): void - { - $this->SetAuthToken($oAccount); - - $aAccounts = $this->GetAccounts($oAccount); - if (isset($aAccounts[$oAccount->Email()])) { - $aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken(); - $this->SetAccounts($oAccount, $aAccounts); - } - } - /** * @throws \RainLoop\Exceptions\ClientException */ @@ -1202,7 +1201,7 @@ class Actions { $iResult = 0; - $oAccount = $this->GetAccountFromCustomToken($sHash, false); + $oAccount = $this->GetAccountFromCustomToken($sHash); if ($oAccount) { try { $oMailClient = new \MailSo\Mail\MailClient(); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Accounts.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Accounts.php index 7ffb6ba8a..893e760bf 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Accounts.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Accounts.php @@ -73,9 +73,9 @@ trait Accounts $oAccountToChange = null; if ($oAccount->Email() === $sEmailToDelete && !empty($aAccounts[$sParentEmail])) { - $oAccountToChange = $this->GetAccountFromCustomToken($aAccounts[$sParentEmail], false, false); + $oAccountToChange = $this->GetAccountFromCustomToken($aAccounts[$sParentEmail], false); if ($oAccountToChange) { - $this->AuthToken($oAccountToChange); + $this->SetAuthToken($oAccountToChange); } } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php index 60d7fb558..970801031 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Messages.php @@ -707,15 +707,12 @@ trait Messages $this->Plugins()->RunHook('filter.smtp-hidden-rcpt', array($oAccount, $oMessage, &$aHiddenRcpt)); } - $bUsePhpMail = $oAccount->Domain()->OutUsePhpMail(); - $oSmtpClient = new \MailSo\Smtp\SmtpClient(); $oSmtpClient->SetLogger($this->Logger()); $oSmtpClient->SetTimeOuts(10, (int) \RainLoop\Api::Config()->Get('labs', 'smtp_timeout', 60)); - $oAccount->OutConnectAndLoginHelper( - $this->Plugins(), $oSmtpClient, $this->Config(), $bUsePhpMail - ); + $bUsePhpMail = false; + $oAccount->OutConnectAndLoginHelper($this->Plugins(), $oSmtpClient, $this->Config(), $bUsePhpMail); if ($bUsePhpMail) { diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php index b10bb575b..0d1f437e7 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php @@ -23,24 +23,16 @@ trait User $sEmail = \MailSo\Base\Utils::Trim($this->GetActionParam('Email', '')); $sPassword = $this->GetActionParam('Password', ''); $sLanguage = $this->GetActionParam('Language', ''); - $bSignMe = '1' === (string) $this->GetActionParam('SignMe', '0'); + $bSignMe = !empty($this->GetActionParam('SignMe', 0)); $oAccount = null; $this->Logger()->AddSecret($sPassword); - try - { - $oAccount = $this->LoginProcess($sEmail, $sPassword, - $bSignMe ? $this->generateSignMeToken($sEmail) : ''); - $this->Plugins()->RunHook('login.success', array($oAccount)); - } - catch (ClientException $oException) - { - throw $oException; - } + $oAccount = $this->LoginProcess($sEmail, $sPassword, $bSignMe); + $this->Plugins()->RunHook('login.success', array($oAccount)); - $this->AuthToken($oAccount); + $this->SetAuthToken($oAccount); if ($oAccount && \strlen($sLanguage)) { @@ -211,13 +203,9 @@ trait User $oAccount = $this->getAccountFromToken(false); if ($oAccount) { - if ($oAccount->SignMe()) - { - $this->ClearSignMeData($oAccount); - } - if (!$oAccount->IsAdditionalAccount()) { + $this->ClearSignMeData(); Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY); } } @@ -515,11 +503,6 @@ trait User $this->SettingsProvider()->Save($oAccount, $oSettings) : false); } - private function generateSignMeToken(string $sEmail) : string - { - return \MailSo\Base\Utils::Sha1Rand(APP_SALT.$sEmail); - } - private function getMimeFileByHash(\RainLoop\Model\Account $oAccount, string $sHash) : array { $aValues = $this->getDecodedRawKeyValue($sHash); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php index fa779367c..4a066560b 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/UserAuth.php @@ -10,21 +10,20 @@ use \RainLoop\Exceptions\ClientException; trait UserAuth { -/* - const AUTH_SIGN_ME_TOKEN_KEY = 'smremember'; - const AUTH_SPEC_TOKEN_KEY = 'smspecauth'; - const AUTH_SPEC_LOGOUT_TOKEN_KEY = 'smspeclogout'; - const AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY = 'smspeclogoutcmk'; -*/ /** * @var string */ - private $sSpecAuthToken; + private $sSpecAuthToken = null; + + /** + * Or use 'aes-256-xts' ? + */ + private static $sCipher = 'aes-256-cbc-hmac-sha1'; /** * @throws \RainLoop\Exceptions\ClientException */ - public function LoginProcess(string &$sEmail, string &$sPassword, string $sSignMeToken = ''): Account + public function LoginProcess(string &$sEmail, string &$sPassword, bool $bSignMe = false): Account { $sInputEmail = $sEmail; @@ -117,7 +116,7 @@ trait UserAuth $oAccount = null; $sClientCert = \trim($this->Config()->Get('ssl', 'client_cert', '')); try { - $oAccount = $this->LoginProvide($sEmail, $sLogin, $sPassword, $sSignMeToken, $sClientCert, true); + $oAccount = Account::NewInstanceByLogin($this, $sEmail, $sLogin, $sPassword, $sClientCert, true); if (!$oAccount) { throw new ClientException(Notifications::AuthError); @@ -130,6 +129,7 @@ trait UserAuth try { $this->CheckMailConnection($oAccount, true); + $bSignMe && $this->SetSignMeToken($oAccount); } catch (\Throwable $oException) { $this->loginErrorDelay(); @@ -142,107 +142,27 @@ trait UserAuth /** * @throws \RainLoop\Exceptions\ClientException */ - public function GetAccountFromCustomToken(string $sToken, bool $bThrowExceptionOnFalse = true, bool $bValidateShortToken = true, bool $bQ = false): ?Account + public function GetAccountFromCustomToken(string $sToken, bool $bValidateShortToken = true, bool $bQ = false, bool $bThrowExceptionOnFalse = false): ?Account { - $oResult = null; if (!empty($sToken)) { - $aAccountHash = $bQ ? Utils::DecodeKeyValuesQ($sToken) : Utils::DecodeKeyValues($sToken); - if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0] && // simple token validation - 8 <= \count($aAccountHash) && // length checking - !empty($aAccountHash[7]) && // does short token exist - (!$bValidateShortToken || Utils::GetShortToken() === $aAccountHash[7] || // check short token if needed - (isset($aAccountHash[10]) && 0 < $aAccountHash[10] && \time() < $aAccountHash[10])) - ) { - $oAccount = $this->LoginProvide($aAccountHash[1], $aAccountHash[2], $aAccountHash[3], - empty($aAccountHash[5]) ? '' : $aAccountHash[5], empty($aAccountHash[11]) ? '' : $aAccountHash[11], $bThrowExceptionOnFalse); - - if ($oAccount) { - // init proxy user/password - if (!empty($aAccountHash[8]) && !empty($aAccountHash[9])) { - $oAccount->SetProxyAuthUser($aAccountHash[8]); - $oAccount->SetProxyAuthPassword($aAccountHash[9]); - } - - $this->Logger()->AddSecret($oAccount->Password()); - $this->Logger()->AddSecret($oAccount->ProxyAuthPassword()); - - $oAccount->SetParentEmail($aAccountHash[6]); - $oResult = $oAccount; - } - } else if ($bThrowExceptionOnFalse) { - throw new ClientException(Notifications::AuthError); - } + $aToken = $bQ ? Utils::DecodeKeyValuesQ($sToken) : Utils::DecodeKeyValues($sToken); + return Account::NewInstanceFromTokenArray( + $this, + $bQ ? Utils::DecodeKeyValuesQ($sToken) : Utils::DecodeKeyValues($sToken), + $bThrowExceptionOnFalse + ); } - if ($bThrowExceptionOnFalse && !$oResult) { - throw new ClientException(Notifications::AuthError); + if ($bThrowExceptionOnFalse) { + throw new ClientException(\RainLoop\Notifications::AuthError); } - return $oResult; - } - - protected function LoginProvide(string $sEmail, string $sLogin, string $sPassword, string $sSignMeToken = '', string $sClientCert = '', bool $bThrowProvideException = false): ?Account - { - $oAccount = null; - if (\strlen($sEmail) && \strlen($sLogin) && \strlen($sPassword)) { - $oDomain = $this->DomainProvider()->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail), true); - if ($oDomain) { - if ($oDomain->ValidateWhiteList($sEmail, $sLogin)) { - $oAccount = new Account($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken, '', '', $sClientCert); - $this->Plugins()->RunHook('filter.account', array($oAccount)); - - if ($bThrowProvideException && !$oAccount) { - throw new ClientException(Notifications::AuthError); - } - } else if ($bThrowProvideException) { - throw new ClientException(Notifications::AccountNotAllowed); - } - } else if ($bThrowProvideException) { - throw new ClientException(Notifications::DomainNotAllowed); - } - } - - return $oAccount; - } - - public function GetSpecAuthTokenCookie(): string - { - return Utils::GetCookie(self::AUTH_SPEC_TOKEN_KEY, ''); - } - - // rlspecauth / AuthAccountHash - public function getAuthAccountHash() : string - { - if ('' === $this->sSpecAuthToken && !\strlen($this->GetSpecAuthLogoutTokenWithDeletion())) { - $sAuthAccountHash = $this->GetSpecAuthTokenCookie() ?: $this->GetSpecAuthToken(); - if (empty($sAuthAccountHash)) { - $oAccount = $this->GetAccountFromSignMeToken(); - if ($oAccount) try - { - $this->CheckMailConnection($oAccount); - $this->AuthToken($oAccount); - $sAuthAccountHash = $this->GetSpecAuthToken(); - } - catch (\Throwable $oException) - { - $oException = null; - $this->ClearSignMeData($oAccount); - } - } - $this->SetSpecAuthToken($sAuthAccountHash); - } - return $this->GetSpecAuthToken(); - } - - private function getLocalAuthToken(): string - { - $sToken = $this->GetSpecAuthToken(); - return !empty($sToken) && '_' === \substr($sToken, 0, 1) ? \substr($sToken, 1) : ''; + return null; } public function GetShortLifeSpecAuthToken(int $iLife = 60): string { - $aAccountHash = Utils::DecodeKeyValues($this->getLocalAuthToken()); + $aAccountHash = Utils::DecodeKeyValues($this->sSpecAuthToken); if (!empty($aAccountHash[0]) && 'token' === $aAccountHash[0]) { $aAccountHash[10] = \time() + $iLife; return Utils::EncodeKeyValues($aAccountHash); @@ -256,126 +176,141 @@ trait UserAuth */ public function getAccountFromToken(bool $bThrowExceptionOnFalse = true): ?Account { - return $this->GetAccountFromCustomToken($this->getLocalAuthToken(), $bThrowExceptionOnFalse, true, true); - } - - public function GetSpecAuthToken(): string - { - return $this->sSpecAuthToken; - } - - public function SetSpecAuthToken(string $sSpecAuthToken): self - { - $this->sSpecAuthToken = $sSpecAuthToken; - - return $this; + if (!\is_string($this->sSpecAuthToken)) { + $this->sSpecAuthToken = ''; + if (isset($_COOKIE[self::AUTH_SPEC_LOGOUT_TOKEN_KEY])) { + Utils::ClearCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY); + Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY); +// Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY); + } else { + $sAuthAccountHash = Utils::GetCookie(self::AUTH_SPEC_TOKEN_KEY); + if (empty($sAuthAccountHash)) { + $oAccount = $this->GetAccountFromSignMeToken(); + if ($oAccount) { + $this->SetAuthToken($oAccount); + $sAuthAccountHash = $this->sSpecAuthToken; + } + } + $this->sSpecAuthToken = $sAuthAccountHash ?: ''; + } + } + return $this->GetAccountFromCustomToken($this->sSpecAuthToken, true, true, $bThrowExceptionOnFalse); } public function SetAuthToken(Account $oAccount): void { - $sSpecAuthToken = '_' . $oAccount->GetAuthTokenQ(); + $sSpecAuthToken = $oAccount->GetAuthTokenQ(); - $this->SetSpecAuthToken($sSpecAuthToken); + $this->sSpecAuthToken = $sSpecAuthToken; Utils::SetCookie(self::AUTH_SPEC_TOKEN_KEY, $sSpecAuthToken); - if ($oAccount->SignMe()) { - $this->SetSignMeToken($oAccount); + if (isset($aAccounts[$oAccount->Email()])) { + $aAccounts[$oAccount->Email()] = $oAccount->GetAuthToken(); + $this->SetAccounts($oAccount, $aAccounts); } } private static function GetSignMeToken(): ?array { - $sSignMeToken = Utils::GetCookie(self::AUTH_SIGN_ME_TOKEN_KEY, ''); - return empty($sSignMeToken) ? null : Utils::DecodeKeyValuesQ($sSignMeToken); + $sSignMeToken = Utils::GetCookie(self::AUTH_SIGN_ME_TOKEN_KEY); + if (empty($sSignMeToken)) { + return null; + } + $aResult = \SnappyMail\Crypt::DecryptCookie($sSignMeToken); + return \is_array($aResult) ? $aResult : null; + } + + private static function SetSignMeTokenCookie(array $aData): void + { + Utils::SetCookie( + self::AUTH_SIGN_ME_TOKEN_KEY, + \SnappyMail\Crypt::EncryptCookie($aData), + \time() + 3600 * 24 * 30 // 30 days + ); } private function SetSignMeToken(Account $oAccount): void { - $this->ClearSignMeData($oAccount); + $this->ClearSignMeData(); $uuid = \SnappyMail\UUID::generate(); - $salt = \sha1(\random_bytes(16)); - Utils::SetCookie(self::AUTH_SIGN_ME_TOKEN_KEY, - Utils::EncodeKeyValuesQ(array( + $data = \SnappyMail\Crypt::EncryptRaw($oAccount); + + if ($data['xxtea']) { + static::SetSignMeTokenCookie(array( 'e' => $oAccount->Email(), 'u' => $uuid, - 's' => $salt - )), - \time() + 3600 * 24 * 30); // 30 days + 's' => \base64_encode($data[1]) + )); + } else { + static::SetSignMeTokenCookie(array( + 'e' => $oAccount->Email(), + 'u' => $uuid, + 'i' => \base64_encode($data[1]) + )); + } - $this->StorageProvider()->Put($oAccount, + $this->StorageProvider()->Put( + $oAccount, StorageType::SIGN_ME, $uuid, - Utils::EncryptString($oAccount->GetAuthToken(), $salt) + $data[2] ); } public function GetAccountFromSignMeToken(): ?Account { - $oAccount = null; - $aTokenData = static::GetSignMeToken(); if (!empty($aTokenData)) { - if (!empty($aTokenData['e']) && !empty($aTokenData['u']) && !empty($aTokenData['s']) && \SnappyMail\UUID::isValid($aTokenData['u'])) { - $sAuthToken = $this->StorageProvider()->Get($aTokenData['e'], + $oAccount = null; + if (!empty($aTokenData['e']) && !empty($aTokenData['u']) && \SnappyMail\UUID::isValid($aTokenData['u'])) { + $sAuthToken = $this->StorageProvider()->Get( + $aTokenData['e'], StorageType::SIGN_ME, $aTokenData['u'] ); if (empty($sAuthToken)) { return null; } - $sAuthToken = Utils::DecryptString($sAuthToken, $aTokenData['s']); - if (!empty($sAuthToken)) { - $oAccount = $this->GetAccountFromCustomToken($sAuthToken, false, false, true); + if (!empty($aTokenData['s'])) { + $aAccountHash = \SnappyMail\Crypt::XxteaDecrypt($sAuthToken, \base64_decode($aTokenData['s'])); + } else if (!empty($aTokenData['i'])) { + $aAccountHash = \SnappyMail\Crypt::OpenSSLDecrypt($sAuthToken, \base64_decode($aTokenData['i'])); } - } else if (!empty($aTokenData['e']) && !empty($aTokenData['t'])) { - // This is old, see https://github.com/the-djmaze/snappymail/issues/126 - $sTokenSettings = $this->StorageProvider()->Get($aTokenData['e'], - StorageType::CONFIG, - 'sign_me' - ); - if (!empty($sTokenSettings)) { - $aSignMeData = Utils::DecodeKeyValuesQ($sTokenSettings); - if (!empty($aSignMeData['AuthToken']) && - !empty($aSignMeData['SignMeToken']) && - $aSignMeData['SignMeToken'] === $aTokenData['t']) { - $oAccount = $this->GetAccountFromCustomToken($aSignMeData['AuthToken'], false, false, true); + if (!empty($aAccountHash) && \is_array($aAccountHash)) { + $oAccount = Account::NewInstanceFromTokenArray($this, $aAccountHash); + if ($oAccount) { + try + { + $this->CheckMailConnection($oAccount); + // Update lifetime + $this->SetSignMeToken($oAccount); + + return $oAccount; + } + catch (\Throwable $oException) + { + } } } } - if ($oAccount) { - // Update lifetime - $this->SetSignMeToken($oAccount); - } - } else { - Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY); } - return $oAccount; + $this->ClearSignMeData(); + return null; } - protected function ClearSignMeData(Account $oAccount) : void + protected function ClearSignMeData() : void { - if ($oAccount) { + if (isset($_COOKIE[self::AUTH_SIGN_ME_TOKEN_KEY])) { $aTokenData = static::GetSignMeToken(); - if (!empty($aTokenData['u']) && \SnappyMail\UUID::isValid($aTokenData['u'])) { - $this->StorageProvider()->Clear($oAccount, StorageType::SIGN_ME, $aTokenData['u']); + if (!empty($aTokenData['e']) && !empty($aTokenData['u']) && \SnappyMail\UUID::isValid($aTokenData['u'])) { + $this->StorageProvider()->Clear($aTokenData['e'], StorageType::SIGN_ME, $aTokenData['u']); } Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY); - $this->StorageProvider()->Clear($oAccount, StorageType::CONFIG, 'sign_me'); } } - public function GetSpecAuthLogoutTokenWithDeletion(): string - { - $sResult = Utils::GetCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY, ''); - if (\strlen($sResult)) { - Utils::ClearCookie(self::AUTH_SPEC_LOGOUT_TOKEN_KEY); - } - - return $sResult; - } - public function SetAuthLogoutToken(): void { \header('X-RainLoop-Action: Logout'); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php index 1e8aa9198..b1cbb6381 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Account.php @@ -2,7 +2,10 @@ namespace RainLoop\Model; -class Account +use \RainLoop\Utils; +use \RainLoop\Exceptions\ClientException; + +class Account implements \JsonSerializable { /** * @var string @@ -22,23 +25,18 @@ class Account /** * @var string */ - private $sProxyAuthUser; + private $sProxyAuthUser = ''; /** * @var string */ - private $sProxyAuthPassword; + private $sProxyAuthPassword = ''; /** * @var string */ private $sClientCert; - /** - * @var string - */ - private $sSignMeToken; - /** * @var \RainLoop\Model\Domain */ @@ -47,21 +45,7 @@ class Account /** * @var string */ - private $sParentEmail; - - function __construct(string $sEmail, string $sLogin, string $sPassword, Domain $oDomain, - string $sSignMeToken = '', string $sProxyAuthUser = '', string $sProxyAuthPassword = '', string $sClientCert = '') - { - $this->sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true); - $this->sLogin = \MailSo\Base\Utils::IdnToAscii($sLogin); - $this->sPassword = $sPassword; - $this->oDomain = $oDomain; - $this->sSignMeToken = $sSignMeToken; - $this->sProxyAuthUser = $sProxyAuthUser; - $this->sProxyAuthPassword = $sProxyAuthPassword; - $this->sClientCert = $sClientCert; - $this->sParentEmail = ''; - } + private $sParentEmail = ''; public function Email() : string { @@ -85,12 +69,12 @@ class Account public function ParentEmailHelper() : string { - return \strlen($this->sParentEmail) ? $this->sParentEmail : $this->sEmail; + return $this->sParentEmail ?: $this->sEmail; } - public function IsAdditionalAccount() : string + public function IsAdditionalAccount() : bool { - return \strlen($this->sParentEmail); + return !empty($this->sParentEmail); } public function IncLogin() : string @@ -135,16 +119,6 @@ class Account return $this->sClientCert; } - public function SignMe() : bool - { - return \strlen($this->sSignMeToken); - } - - public function SignMeToken() : string - { - return $this->sSignMeToken; - } - public function Domain() : Domain { return $this->oDomain; @@ -152,8 +126,13 @@ class Account public function Hash() : string { - return \md5(APP_SALT.$this->Email().APP_SALT.$this->DomainIncHost(). - APP_SALT.$this->DomainIncPort().APP_SALT.$this->Password().APP_SALT.'0'.APP_SALT.$this->ParentEmail().APP_SALT); + return \md5(\implode(APP_SALT, [ + $this->sEmail, + $this->Domain()->IncHost(), + $this->Domain()->IncPort(), + $this->sPassword, + $this->sParentEmail + ])); } public function SetPassword(string $sPassword) : void @@ -176,106 +155,108 @@ class Account $this->sProxyAuthPassword = $sProxyAuthPassword; } - public function DomainIncHost() : string + public function jsonSerialize() { - return $this->Domain()->IncHost(); - } - - public function DomainIncPort() : int - { - return $this->Domain()->IncPort(); - } - - public function DomainIncSecure() : int - { - return $this->Domain()->IncSecure(); - } - - public function DomainOutHost() : string - { - return $this->Domain()->OutHost(); - } - - public function DomainOutPort() : int - { - return $this->Domain()->OutPort(); - } - - public function DomainOutSecure() : int - { - return $this->Domain()->OutSecure(); - } - - public function DomainOutAuth() : bool - { - return $this->Domain()->OutAuth(); - } - - public function DomainSieveHost() : string - { - return $this->Domain()->SieveHost(); - } - - public function DomainSievePort() : int - { - return $this->Domain()->SievePort(); - } - - public function DomainSieveSecure() : int - { - return $this->Domain()->SieveSecure(); + return array( + 'account', // 0 + $this->sEmail, // 1 + $this->sLogin, // 2 + $this->sPassword, // 3 + $this->sClientCert, // 4 + $this->sParentEmail, // 5 + $this->sProxyAuthUser, // 6 + $this->sProxyAuthPassword // 7 + ); } public function GetAuthToken() : string { - return \RainLoop\Utils::EncodeKeyValues(array( - 'token', // 0 - $this->sEmail, // 1 - $this->sLogin, // 2 - $this->sPassword, // 3 - \RainLoop\Utils::Fingerprint(), // 4 - $this->sSignMeToken, // 5 - $this->sParentEmail, // 6 - \RainLoop\Utils::GetShortToken(), // 7 - $this->sProxyAuthUser, // 8 - $this->sProxyAuthPassword, // 9 - 0, // 10 // lifetime - $this->sClientCert // 11 - )); + return Utils::EncodeKeyValues($this->jsonSerialize()); } public function GetAuthTokenQ() : string { - return \RainLoop\Utils::EncodeKeyValuesQ(array( - 'token', // 0 - $this->sEmail, // 1 - $this->sLogin, // 2 - $this->sPassword, // 3 - \RainLoop\Utils::Fingerprint(), // 4 - $this->sSignMeToken, // 5 - $this->sParentEmail, // 6 - \RainLoop\Utils::GetShortToken(), // 7 - $this->sProxyAuthUser, // 8 - $this->sProxyAuthPassword, // 9 - 0, // 10 // lifetime - $this->sClientCert // 11 - )); + return Utils::EncodeKeyValuesQ($this->jsonSerialize()); + return \MailSo\Base\Utils::UrlSafeBase64Encode( + \MailSo\Base\Crypt::Encrypt(\json_encode($this), \sha1(APP_SALT)) + ); + } + + public static function NewInstanceByLogin(\RainLoop\Actions $oActions, string $sEmail, string $sLogin, string $sPassword, string $sClientCert = '', bool $bThrowException = false): ?self + { + $oAccount = null; + if (\strlen($sEmail) && \strlen($sLogin) && \strlen($sPassword)) { + $oDomain = $oActions->DomainProvider()->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail), true); + if ($oDomain) { + if ($oDomain->ValidateWhiteList($sEmail, $sLogin)) { + $oAccount = new self; + + $oAccount->sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true); + $oAccount->sLogin = \MailSo\Base\Utils::IdnToAscii($sLogin); + $oAccount->sPassword = $sPassword; + $oAccount->oDomain = $oDomain; + $oAccount->sClientCert = $sClientCert; + + $oActions->Plugins()->RunHook('filter.account', array($oAccount)); + + if ($bThrowException && !$oAccount) { + throw new ClientException(Notifications::AuthError); + } + } 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] && 8 === \count($aAccountHash)) { + $oAccount = static::NewInstanceByLogin( + $oActions, + $aAccountHash[1], + $aAccountHash[2], + $aAccountHash[3], + $aAccountHash[4] ?: '', + $bThrowExceptionOnFalse + ); + + if ($oAccount) { + // init proxy user/password + if (!empty($aAccountHash[6]) && !empty($aAccountHash[7])) { + $oAccount->SetProxyAuthUser($aAccountHash[6]); + $oAccount->SetProxyAuthPassword($aAccountHash[7]); + } + + $oActions->Logger()->AddSecret($oAccount->Password()); + $oActions->Logger()->AddSecret($oAccount->ProxyAuthPassword()); + + $oAccount->SetParentEmail($aAccountHash[5]); + return $oAccount; + } + } + return null; } public function IncConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Mail\MailClient $oMailClient, \RainLoop\Config\Application $oConfig) : bool { $oImapClient = $oMailClient->ImapClient(); - $aImapCredentials = array( - 'UseConnect' => true, - 'UseAuth' => true, - 'Host' => $this->DomainIncHost(), - 'Port' => $this->DomainIncPort(), - 'Secure' => $this->DomainIncSecure(), - 'Login' => $this->IncLogin(), - 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), - 'ClientCert' => $this->ClientCert(), - 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true) + $aImapCredentials = \array_merge( + $this->Domain()->ImapSettings(), + array( + 'Login' => $this->IncLogin(), + 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), + 'ClientCert' => $this->ClientCert(), + 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true) + ) ); $oPlugins->RunHook('imap.before-connect', array($this, $oImapClient, &$aImapCredentials)); @@ -292,17 +273,15 @@ class Account public function OutConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Smtp\SmtpClient $oSmtpClient, \RainLoop\Config\Application $oConfig, bool &$bUsePhpMail = false) : bool { - $aSmtpCredentials = array( - 'UseConnect' => !$bUsePhpMail, - 'UseAuth' => $this->DomainOutAuth(), - 'UsePhpMail' => $bUsePhpMail, - 'Ehlo' => \MailSo\Smtp\SmtpClient::EhloHelper(), - 'Host' => $this->DomainOutHost(), - 'Port' => $this->DomainOutPort(), - 'Secure' => $this->DomainOutSecure(), - 'Login' => $this->OutLogin(), - 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), - 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true) + $aSmtpCredentials = \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, &$aSmtpCredentials)); @@ -321,16 +300,14 @@ class Account public function SieveConnectAndLoginHelper(\RainLoop\Plugins\Manager $oPlugins, \MailSo\Sieve\ManageSieveClient $oSieveClient, \RainLoop\Config\Application $oConfig) { - $aSieveCredentials = array( - 'UseConnect' => true, - 'UseAuth' => true, - 'Host' => $this->DomainSieveHost(), - 'Port' => $this->DomainSievePort(), - 'Secure' => $this->DomainSieveSecure(), - 'Login' => $this->IncLogin(), - 'VerifySsl' => !!$oConfig->Get('ssl', 'verify_certificate', false), - 'AllowSelfSigned' => !!$oConfig->Get('ssl', 'allow_self_signed', true), - 'InitialAuthPlain' => !!$oConfig->Get('ssl', 'sieve_auth_plain_initial', true) + $aSieveCredentials = \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('ssl', 'sieve_auth_plain_initial', true) + ) ); $oPlugins->RunHook('sieve.before-connect', array($this, $oSieveClient, &$aSieveCredentials)); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Domain.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Domain.php index 8d75e250e..f79dec5f2 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Domain.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Model/Domain.php @@ -396,27 +396,62 @@ class Domain implements \JsonSerializable return true; } + public function ImapSettings() : array + { + return array( + 'UseConnect' => true, + 'UseAuth' => true, + 'Host' => $this->sIncHost, + 'Port' => $this->iIncPort, + 'Secure' => $this->iIncSecure, + ); + } + + public function SmtpSettings() : array + { + return array( + 'UseConnect' => !$this->bOutUsePhpMail, + 'UseAuth' => $this->bOutAuth, + 'Host' => $this->sOutHost, + 'Port' => $this->iOutPort, + 'Secure' => $this->iOutSecure, + 'Ehlo' => \MailSo\Smtp\SmtpClient::EhloHelper(), + 'UsePhpMail' => $this->bOutUsePhpMail + ); + } + + public function SieveSettings() : array + { + return array( + 'UseConnect' => true, + 'UseAuth' => true, + 'Host' => $this->sSieveHost, + 'Port' => $this->iSievePort, + 'Secure' => $this->iSieveSecure + ); + } + public function ToSimpleJSON() : array { return array( - 'Name' => $this->Name(), - 'IncHost' => $this->IncHost(), - 'IncPort' => $this->IncPort(), - 'IncSecure' => $this->IncSecure(), - 'IncShortLogin' => $this->IncShortLogin(), - 'UseSieve' => $this->UseSieve(), - 'SieveHost' => $this->SieveHost(), - 'SievePort' => $this->SievePort(), - 'SieveSecure' => $this->SieveSecure(), - 'OutHost' => $this->OutHost(), - 'OutPort' => $this->OutPort(), - 'OutSecure' => $this->OutSecure(), - 'OutShortLogin' => $this->OutShortLogin(), - 'OutAuth' => $this->OutAuth(), - 'OutSetSender' => $this->OutSetSender(), - 'OutUsePhpMail' => $this->OutUsePhpMail(), - 'WhiteList' => $this->WhiteList(), - 'AliasName' => $this->AliasName() + 'Name' => $this->sName, + 'IncHost' => $this->sIncHost, + 'IncPort' => $this->iIncPort, + 'IncSecure' => $this->iIncSecure, + 'IncShortLogin' => $this->bIncShortLogin, + 'UseSieve' => $this->bUseSieve, + 'SieveHost' => $this->sSieveHost, + 'SievePort' => $this->iSievePort, + 'SieveSecure' => $this->iSieveSecure, + 'OutHost' => $this->sOutHost, + 'OutPort' => $this->iOutPort, + 'OutSecure' => $this->iOutSecure, + 'OutShortLogin' => $this->bOutShortLogin, + 'OutAuth' => $this->bOutAuth, + 'OutSetSender' => $this->bOutSetSender, + 'OutUsePhpMail' => $this->bOutUsePhpMail, + 'WhiteList' => $this->sWhiteList, + 'AliasName' => $this->sAliasName ); } @@ -424,24 +459,24 @@ class Domain implements \JsonSerializable { return array( // '@Object' => 'Object/Domain', - 'Name' => \MailSo\Base\Utils::IdnToUtf8($this->Name()), - 'IncHost' => \MailSo\Base\Utils::IdnToUtf8($this->IncHost()), - 'IncPort' => $this->IncPort(), - 'IncSecure' => $this->IncSecure(), - 'IncShortLogin' => $this->IncShortLogin(), - 'UseSieve' => $this->UseSieve(), - 'SieveHost' => \MailSo\Base\Utils::IdnToUtf8($this->SieveHost()), - 'SievePort' => $this->SievePort(), - 'SieveSecure' => $this->SieveSecure(), - 'OutHost' => \MailSo\Base\Utils::IdnToUtf8($this->OutHost()), - 'OutPort' => $this->OutPort(), - 'OutSecure' => $this->OutSecure(), - 'OutShortLogin' => $this->OutShortLogin(), - 'OutAuth' => $this->OutAuth(), - 'OutSetSender' => $this->OutSetSender(), - 'OutUsePhpMail' => $this->OutUsePhpMail(), - 'WhiteList' => $this->WhiteList(), - 'AliasName' => $this->AliasName() + 'Name' => \MailSo\Base\Utils::IdnToUtf8($this->sName), + 'IncHost' => \MailSo\Base\Utils::IdnToUtf8($this->sIncHost), + 'IncPort' => $this->iIncPort, + 'IncSecure' => $this->iIncSecure, + 'IncShortLogin' => $this->bIncShortLogin, + 'UseSieve' => $this->bUseSieve, + 'SieveHost' => \MailSo\Base\Utils::IdnToUtf8($this->sSieveHost), + 'SievePort' => $this->iSievePort, + 'SieveSecure' => $this->iSieveSecure, + 'OutHost' => \MailSo\Base\Utils::IdnToUtf8($this->sOutHost), + 'OutPort' => $this->iOutPort, + 'OutSecure' => $this->iOutSecure, + 'OutShortLogin' => $this->bOutShortLogin, + 'OutAuth' => $this->bOutAuth, + 'OutSetSender' => $this->bOutSetSender, + 'OutUsePhpMail' => $this->bOutUsePhpMail, + 'WhiteList' => $this->sWhiteList, + 'AliasName' => $this->sAliasName ); } } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage.php index ca9368e8b..7788e3684 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage.php @@ -29,54 +29,54 @@ class Storage extends \RainLoop\Providers\AbstractProvider } /** - * @param \RainLoop\Model\Account|string|null $oAccount + * @param \RainLoop\Model\Account|string|null $mAccount * @param mixed $sValue */ - public function Put($oAccount, int $iStorageType, string $sKey, string $sValue) : bool + public function Put($mAccount, int $iStorageType, string $sKey, string $sValue) : bool { - if (!$this->verifyAccount($oAccount, $iStorageType)) + if (!$this->verifyAccount($mAccount, $iStorageType)) { return false; } - return $this->oDriver->Put($oAccount, $iStorageType, $sKey, $sValue); + return $this->oDriver->Put($mAccount, $iStorageType, $sKey, $sValue); } /** - * @param \RainLoop\Model\Account|string|null $oAccount + * @param \RainLoop\Model\Account|string|null $mAccount * @param mixed $mDefault = false * * @return mixed */ - public function Get($oAccount, int $iStorageType, string $sKey, $mDefault = false) + public function Get($mAccount, int $iStorageType, string $sKey, $mDefault = false) { - if (!$this->verifyAccount($oAccount, $iStorageType)) + if (!$this->verifyAccount($mAccount, $iStorageType)) { return $mDefault; } - return $this->oDriver->Get($oAccount, $iStorageType, $sKey, $mDefault); + return $this->oDriver->Get($mAccount, $iStorageType, $sKey, $mDefault); } /** - * @param \RainLoop\Model\Account|string|null $oAccount + * @param \RainLoop\Model\Account|string|null $mAccount */ - public function Clear($oAccount, int $iStorageType, string $sKey) : bool + public function Clear($mAccount, int $iStorageType, string $sKey) : bool { - if (!$this->verifyAccount($oAccount, $iStorageType)) + if (!$this->verifyAccount($mAccount, $iStorageType)) { return false; } - return $this->oDriver->Clear($oAccount, $iStorageType, $sKey); + return $this->oDriver->Clear($mAccount, $iStorageType, $sKey); } /** - * @param \RainLoop\Model\Account|string $oAccount + * @param \RainLoop\Model\Account|string $mAccount */ - public function DeleteStorage($oAccount) : bool + public function DeleteStorage($mAccount) : bool { - return $this->oDriver->DeleteStorage($oAccount); + return $this->oDriver->DeleteStorage($mAccount); } public function IsActive() : bool diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage/FileStorage.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage/FileStorage.php index abff6a77a..74d58d498 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage/FileStorage.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage/FileStorage.php @@ -29,24 +29,24 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage } /** - * @param \RainLoop\Model\Account|string|null $oAccount + * @param \RainLoop\Model\Account|string|null $mAccount */ - public function Put($oAccount, int $iStorageType, string $sKey, string $sValue) : bool + public function Put($mAccount, int $iStorageType, string $sKey, string $sValue) : bool { - $sFileName = $this->generateFileName($oAccount, $iStorageType, $sKey, true); + $sFileName = $this->generateFileName($mAccount, $iStorageType, $sKey, true); return $sFileName && false !== \file_put_contents($sFileName, $sValue); } /** - * @param \RainLoop\Model\Account|string|null $oAccount + * @param \RainLoop\Model\Account|string|null $mAccount * @param mixed $mDefault = false * * @return mixed */ - public function Get($oAccount, int $iStorageType, string $sKey, $mDefault = false) + public function Get($mAccount, int $iStorageType, string $sKey, $mDefault = false) { $mValue = false; - $sFileName = $this->generateFileName($oAccount, $iStorageType, $sKey); + $sFileName = $this->generateFileName($mAccount, $iStorageType, $sKey); if ($sFileName && \file_exists($sFileName)) { $mValue = \file_get_contents($sFileName); } @@ -55,12 +55,12 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage } /** - * @param \RainLoop\Model\Account|string|null $oAccount + * @param \RainLoop\Model\Account|string|null $mAccount */ - public function Clear($oAccount, int $iStorageType, string $sKey) : bool + public function Clear($mAccount, int $iStorageType, string $sKey) : bool { $mResult = true; - $sFileName = $this->generateFileName($oAccount, $iStorageType, $sKey); + $sFileName = $this->generateFileName($mAccount, $iStorageType, $sKey); if ($sFileName && \file_exists($sFileName)) { $mResult = \unlink($sFileName); } @@ -69,11 +69,11 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage } /** - * @param \RainLoop\Model\Account|string $oAccount + * @param \RainLoop\Model\Account|string $mAccount */ - public function DeleteStorage($oAccount) : bool + public function DeleteStorage($mAccount) : bool { - $sPath = $this->generateFileName($oAccount, StorageType::CONFIG, '', false, true); + $sPath = $this->generateFileName($mAccount, StorageType::CONFIG, '', false, true); if ($sPath && \is_dir($sPath)) { \MailSo\Base\Utils::RecRmDir($sPath); } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage/IStorage.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage/IStorage.php index 78f7663b3..66bf5b93b 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage/IStorage.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/Storage/IStorage.php @@ -5,22 +5,22 @@ namespace RainLoop\Providers\Storage; interface IStorage { /** - * @param \RainLoop\Model\Account|null $oAccount + * @param \RainLoop\Model\Account|null $mAccount */ - public function Put($oAccount, int $iStorageType, string $sKey, string $sValue) : bool; + public function Put($mAccount, int $iStorageType, string $sKey, string $sValue) : bool; /** - * @param \RainLoop\Model\Account|null $oAccount + * @param \RainLoop\Model\Account|null $mAccount * @param mixed $mDefault = false * * @return mixed */ - public function Get($oAccount, int $iStorageType, string $sKey, $mDefault = false); + public function Get($mAccount, int $iStorageType, string $sKey, $mDefault = false); /** - * @param \RainLoop\Model\Account|null $oAccount + * @param \RainLoop\Model\Account|null $mAccount */ - public function Clear($oAccount, int $iStorageType, string $sKey) : bool; + public function Clear($mAccount, int $iStorageType, string $sKey) : bool; public function IsLocal() : bool; } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Service.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Service.php index e5d40a55d..839d5d9e8 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Service.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Service.php @@ -96,8 +96,6 @@ class Service $bAdmin = true; } - $bAdmin || $this->oActions->getAuthAccountHash(); - if ($this->oHttp->IsPost()) { $this->oHttp->ServerNoCache(); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php index 85cebda03..51c70b05c 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php @@ -684,7 +684,7 @@ class ServiceActions { $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); - if ($oAccount instanceof Model\Account && $aAdditionalOptions) + if ($aAdditionalOptions) { $bNeedToSettings = false; @@ -711,7 +711,7 @@ class ServiceActions } } - $this->oActions->AuthToken($oAccount); + $this->oActions->SetAuthToken($oAccount); $bLogout = !($oAccount instanceof Model\Account); } @@ -746,7 +746,7 @@ class ServiceActions try { $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); - $this->oActions->AuthToken($oAccount); + $this->oActions->SetAuthToken($oAccount); $bLogout = !($oAccount instanceof Model\Account); } catch (\Throwable $oException) @@ -824,13 +824,13 @@ class ServiceActions $aAccounts = $this->oActions->GetAccounts($oAccount); if (isset($aAccounts[$sEmail])) { - $oAccountToLogin = $this->oActions->GetAccountFromCustomToken($aAccounts[$sEmail], false, false); + $oAccountToLogin = $this->oActions->GetAccountFromCustomToken($aAccounts[$sEmail], false); } } if ($oAccountToLogin) { - $this->oActions->AuthToken($oAccountToLogin); + $this->oActions->SetAuthToken($oAccountToLogin); } } } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php index 037be1272..349484188 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php @@ -16,15 +16,17 @@ class Utils const /** + * 30 days cookie * Used by: ServiceProxyExternal, compileLogParams, GetCsrfToken * To preven CSRF attacks on all requests. */ - CONNECTION_TOKEN = 'rltoken', + CONNECTION_TOKEN = 'smtoken', /** + * Session cookie * Used by: GetAuthToken, GetAuthTokenQ, GetAccountFromCustomToken, EncryptStringQ, DecryptStringQ */ - SHORT_TOKEN = 'rlsession'; + SHORT_TOKEN = 'smsession'; public static function EncryptString(string $sString, string $sKey) : string { @@ -96,14 +98,13 @@ class Utils public static function Fingerprint() : string { - return \md5($_SERVER['HTTP_USER_AGENT'] ?: 'RainLoopFingerprint'); + return \sha1(\preg_replace('/[^a-z]+/i', '', \explode(')', $_SERVER['HTTP_USER_AGENT'])[0])); } public static function GetShortToken() : string { $sToken = static::GetCookie(self::SHORT_TOKEN, null); - if (!$sToken) - { + if (!$sToken) { $sToken = \MailSo\Base\Utils::Sha1Rand(APP_SALT); static::SetCookie(self::SHORT_TOKEN, $sToken, 0); } diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php b/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php new file mode 100644 index 000000000..7c5d66c1c --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/snappymail/crypt.php @@ -0,0 +1,100 @@ + extension_loaded('imagick'), 'intl' => function_exists('idn_to_ascii'), 'ldap' => extension_loaded('ldap'), + 'OpenSSL' => extension_loaded('openssl'), 'mysql' => extension_loaded('pdo_mysql'), 'pgsql' => extension_loaded('pdo_pgsql'), 'sqlite' => extension_loaded('pdo_sqlite'),