From abe2af153d18db2085033590ed70c223ed9762cd Mon Sep 17 00:00:00 2001 From: djmaze Date: Tue, 14 Dec 2021 12:42:41 +0100 Subject: [PATCH] Improved account login/switch handling --- .../libraries/RainLoop/Actions/Accounts.php | 2 +- .../app/libraries/RainLoop/Actions/User.php | 11 ++-- .../libraries/RainLoop/Actions/UserAuth.php | 54 ++++++++++++------- .../app/libraries/RainLoop/Model/Account.php | 19 ++----- .../app/libraries/RainLoop/Notifications.php | 1 + .../app/libraries/RainLoop/ServiceActions.php | 47 +--------------- .../v/0.0.0/app/libraries/RainLoop/Utils.php | 12 +---- 7 files changed, 45 insertions(+), 101 deletions(-) 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 3d7cf49b4..b3cddfc41 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 @@ -79,7 +79,7 @@ trait Accounts throw new ClientException(Notifications::AccountDoesNotExist); } - $oNewAccount = $this->LoginProcess($sEmail, $sPassword, false, $oMainAccount); + $oNewAccount = $this->LoginProcess($sEmail, $sPassword, false, false); $aAccounts[$oNewAccount->Email()] = $oNewAccount->asTokenArray($oMainAccount); $this->SetAccounts($oMainAccount, $aAccounts); 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 d63c6354e..4c65c5ea7 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 @@ -200,14 +200,9 @@ trait User public function DoLogout() : array { - $oAccount = $this->getAccountFromToken(false); - if ($oAccount) { - if ($oAccount instanceof \RainLoop\Model\MainAccount) { - $this->ClearSignMeData(); - Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY); - } - Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY); - } + $bMain = empty($_COOKIE[self::AUTH_ADDITIONAL_TOKEN_KEY]); + $this->Logout($bMain); + $bMain && $this->ClearSignMeData(); return $this->TrueResponse(__FUNCTION__); } 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 87fd2bd97..a7c80d079 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 @@ -21,7 +21,7 @@ trait UserAuth /** * @throws \RainLoop\Exceptions\ClientException */ - public function LoginProcess(string &$sEmail, string &$sPassword, bool $bSignMe = false, Account $oMainAccount = null): Account + public function LoginProcess(string &$sEmail, string &$sPassword, bool $bSignMe = false, bool $bMainAccount = true): Account { $sInputEmail = $sEmail; @@ -114,10 +114,10 @@ trait UserAuth $oAccount = null; $sClientCert = \trim($this->Config()->Get('ssl', 'client_cert', '')); try { - if ($oMainAccount) { - $oAccount = AdditionalAccount::NewInstanceByLogin($this, $sEmail, $sLogin, $sPassword, $sClientCert, true); + if ($bMainAccount) { + $oAccount = MainAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $sPassword, $sClientCert, true); } else { - $oAccount = MainAccount::NewInstanceByLogin($this, $sEmail, $sLogin, $sPassword, $sClientCert, true); + $oAccount = AdditionalAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $sPassword, $sClientCert, true); } if (!$oAccount) { @@ -131,7 +131,7 @@ trait UserAuth try { $this->CheckMailConnection($oAccount, true); - if (!$oMainAccount) { + if ($bMainAccount) { $bSignMe && $this->SetSignMeToken($oAccount); $this->StorageProvider()->Put($oAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true'); } @@ -144,6 +144,18 @@ trait UserAuth return $oAccount; } + private static function SetAccountCookie(string $sName, ?Account $oAccount) + { + if ($oAccount) { + Utils::SetCookie( + $sName, + \MailSo\Base\Utils::UrlSafeBase64Encode(\SnappyMail\Crypt::EncryptToJSON($oAccount)) + ); + } else { + Utils::ClearCookie($sName); + } + } + public function switchAccount(string $sEmail) : bool { $this->Http()->ServerNoCache(); @@ -165,6 +177,9 @@ trait UserAuth if (!$oAccountToLogin) { throw new ClientException(Notifications::AccountSwitchFailed); } + +// $this->CheckMailConnection($oAccountToLogin); + $this->SetAdditionalAuthToken($oAccountToLogin); return true; } @@ -233,12 +248,10 @@ trait UserAuth } else { $oMainAuthAccount && $this->StorageProvider()->Clear($oMainAuthAccount, StorageType::SESSION, $sToken); Utils::ClearCookie(Utils::SESSION_TOKEN); - Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY); - Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY); + $this->Logout(true); } } else { - Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY); - Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY); + $this->Logout(true); } } else { $oAccount = $this->GetAccountFromSignMeToken(); @@ -252,7 +265,7 @@ trait UserAuth } if ($this->oMainAuthAccount) { - $this->StorageProvider()->Put($this->oMainAuthAccount, StorageType::SESSION, $sToken, 'true'); + $this->StorageProvider()->Put($this->oMainAuthAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true'); } } @@ -263,17 +276,13 @@ trait UserAuth { $this->oAdditionalAuthAccount = false; $this->oMainAuthAccount = $oAccount; - Utils::SetSecureCookie(self::AUTH_SPEC_TOKEN_KEY, $oAccount); + static::SetAccountCookie(self::AUTH_SPEC_TOKEN_KEY, $oAccount); } public function SetAdditionalAuthToken(?AdditionalAccount $oAccount): void { $this->oAdditionalAuthAccount = $oAccount ?: false; - if ($oAccount) { - Utils::SetSecureCookie(self::AUTH_ADDITIONAL_TOKEN_KEY, $oAccount); - } else { - Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY); - } + static::SetAccountCookie(self::AUTH_ADDITIONAL_TOKEN_KEY, $oAccount); } /** @@ -288,7 +297,6 @@ trait UserAuth if (isset($aResult['e'], $aResult['u']) && \SnappyMail\UUID::isValid($aResult['u'])) { return $aResult; } - Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY); } return null; } @@ -350,10 +358,10 @@ trait UserAuth catch (\Throwable $oException) { } - - $this->ClearSignMeData(); } + $this->ClearSignMeData(); + return null; } @@ -362,8 +370,8 @@ trait UserAuth $aTokenData = static::GetSignMeToken(); if ($aTokenData) { $this->StorageProvider()->Clear($aTokenData['e'], StorageType::SIGN_ME, $aTokenData['u']); - Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY); } + Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY); } /** @@ -391,6 +399,12 @@ trait UserAuth Utils::SetCookie(self::AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY, $sMessage); } + protected function Logout(bool $bMain) : void + { + Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY); + $bMain && Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY); + } + /** * @throws \RainLoop\Exceptions\ClientException */ 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 99d0c3194..20509e685 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 @@ -143,20 +143,7 @@ abstract class Account implements \JsonSerializable ); } - /** - * @throws \RainLoop\Exceptions\ClientException - */ - public static function NewInstanceFromAuthToken(\RainLoop\Actions $oActions, string $sToken): ?self - { - return empty($sToken) ? null - : static::NewInstanceFromTokenArray( - $oActions, - Utils::DecodeKeyValues($sToken), - false - ); - } - - public static function NewInstanceByLogin(\RainLoop\Actions $oActions, + public static function NewInstanceFromCredentials(\RainLoop\Actions $oActions, string $sEmail, string $sLogin, string $sPassword, string $sClientCert = '', bool $bThrowException = false): ?self { @@ -176,7 +163,7 @@ abstract class Account implements \JsonSerializable $oActions->Plugins()->RunHook('filter.account', array($oAccount)); if ($bThrowException && !$oAccount) { - throw new ClientException(Notifications::AuthError); + throw new ClientException(Notifications::AccountFilterError); } } else if ($bThrowException) { throw new ClientException(Notifications::AccountNotAllowed); @@ -195,7 +182,7 @@ abstract class Account implements \JsonSerializable bool $bThrowExceptionOnFalse = false): ?self { if (!empty($aAccountHash[0]) && 'account' === $aAccountHash[0] && 7 <= \count($aAccountHash)) { - $oAccount = static::NewInstanceByLogin( + $oAccount = static::NewInstanceFromCredentials( $oActions, $aAccountHash[1] ?: '', $aAccountHash[2] ?: '', diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Notifications.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Notifications.php index b0ef09228..0bba7ecee 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Notifications.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Notifications.php @@ -47,6 +47,7 @@ class Notifications const AccountAlreadyExists = 801; const AccountDoesNotExist = 802; const AccountSwitchFailed = 803; + const AccountFilterError = 804; const MailServerError = 901; const ClientViewError = 902; 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 678dc5618..063c682c7 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php @@ -717,7 +717,7 @@ class ServiceActions $this->oActions->SetAuthToken($oAccount); - $bLogout = !($oAccount instanceof Model\Account); + $bLogout = !($oAccount instanceof Model\MainAccount); } catch (\Throwable $oException) { @@ -751,7 +751,7 @@ class ServiceActions { $oAccount = $this->oActions->LoginProcess($sEmail, $sPassword); $this->oActions->SetAuthToken($oAccount); - $bLogout = !($oAccount instanceof Model\Account); + $bLogout = !($oAccount instanceof Model\MainAccount); } catch (\Throwable $oException) { @@ -768,49 +768,6 @@ class ServiceActions return ''; } - public function ServiceExternalLogin() : string - { - $this->oHttp->ServerNoCache(); - - $oException = null; - $oAccount = null; - $bLogout = true; - - switch (\strtolower($_REQUEST['Output'] ?? 'Redirect')) - { - case 'json': - - \header('Content-Type: application/json; charset=utf-8'); - - $aResult = array( - 'Action' => 'ExternalLogin', - 'Result' => $oAccount instanceof Model\Account ? true : false, - 'ErrorCode' => 0 - ); - - if (!$aResult['Result']) - { - if ($oException instanceof Exceptions\ClientException) - { - $aResult['ErrorCode'] = $oException->getCode(); - } - else - { - $aResult['ErrorCode'] = Notifications::AuthError; - } - } - - return \MailSo\Base\Utils::Php2js($aResult, $this->Logger()); - - case 'redirect': - default: - $this->oActions->Location('./'); - break; - } - - return ''; - } - /** * @return mixed */ 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 906404162..87f79912d 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php @@ -77,7 +77,7 @@ class Utils $sToken = static::GetCookie(self::SESSION_TOKEN, null); if (!$sToken) { $sToken = \MailSo\Base\Utils::Sha1Rand(APP_SALT); - static::SetCookie(self::SESSION_TOKEN, $sToken, 0); + static::SetCookie(self::SESSION_TOKEN, $sToken); } return \sha1('Session'.APP_SALT.$sToken.'Token'.APP_SALT); @@ -149,16 +149,6 @@ class Utils )); } - public static function SetSecureCookie(string $sName, $mValue, int $iExpire = 0, bool $bHttpOnly = true) - { - static::SetCookie( - $sName, - \MailSo\Base\Utils::UrlSafeBase64Encode(\SnappyMail\Crypt::EncryptToJSON($mValue)), - $iExpire, - true - ); - } - public static function ClearCookie(string $sName) { if (isset($_COOKIE[$sName])) {