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 aa7c9ad3f..056956b0f 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 @@ -237,7 +237,7 @@ trait UserAuth * Server side control/kickout of logged in sessions * https://github.com/the-djmaze/snappymail/issues/151 */ - if (!isset($_COOKIE[Utils::SESSION_TOKEN])) { + if (empty($_COOKIE[Utils::SESSION_TOKEN])) { // \MailSo\Base\Http::StatusHeader(401); $this->Logout(true); // $sAdditionalMessage = $this->StaticI18N('SESSION_UNDEFINED'); @@ -248,11 +248,19 @@ trait UserAuth $aData, $bThrowExceptionOnFalse ); - $sToken = Utils::GetSessionToken(); - if ($oMainAuthAccount && $this->StorageProvider()->Get($oMainAuthAccount, StorageType::SESSION, $sToken)) { + $oMainAuthAccount || \SnappyMail\LOG::notice('TOKENS', 'AUTH_SPEC_TOKEN_KEY invalid'); + $sToken = $oMainAuthAccount ? Utils::GetSessionToken(false) : null; + $sTokenValue = $sToken ? $this->StorageProvider()->Get($oMainAuthAccount, StorageType::SESSION, $sToken) : null; + if ($oMainAuthAccount && $sTokenValue) { $this->oMainAuthAccount = $oMainAuthAccount; } else { - $oMainAuthAccount && $this->StorageProvider()->Clear($oMainAuthAccount, StorageType::SESSION, $sToken); + if ($oMainAuthAccount) { + $sToken || \SnappyMail\LOG::notice('TOKENS', 'SESSION_TOKEN not found'); + if ($sToken) { + $oMainAuthAccount && $this->StorageProvider()->Clear($oMainAuthAccount, StorageType::SESSION, $sToken); + $sTokenValue || \SnappyMail\LOG::notice('TOKENS', 'SESSION_TOKEN value invalid: ' . \gettype($sTokenValue)); + } + } Utils::ClearCookie(Utils::SESSION_TOKEN); // \MailSo\Base\Http::StatusHeader(401); $this->Logout(true); @@ -266,10 +274,7 @@ trait UserAuth } } - if ($this->oMainAuthAccount) { - // Extend session cookie lifetime - $this->StorageProvider()->Put($this->oMainAuthAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true'); - } else if ($bThrowExceptionOnFalse) { + if ($bThrowExceptionOnFalse && !$this->oMainAuthAccount) { throw new ClientException(Notifications::InvalidToken, null, 'Account undefined'); } } 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 18c302c31..75e974988 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 @@ -19,13 +19,9 @@ class Storage extends \RainLoop\Providers\AbstractProvider */ private function verifyAccount($mAccount, int $iStorageType) : bool { - if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && - !($mAccount instanceof \RainLoop\Model\Account || \is_string($mAccount))) - { - return false; - } - - return true; + return \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY === $iStorageType + || $mAccount instanceof \RainLoop\Model\Account + || \is_string($mAccount); } /** @@ -34,12 +30,9 @@ class Storage extends \RainLoop\Providers\AbstractProvider */ public function Put($mAccount, int $iStorageType, string $sKey, string $sValue) : bool { - if (!$this->verifyAccount($mAccount, $iStorageType)) - { - return false; - } - - return $this->oDriver->Put($mAccount, $iStorageType, $sKey, $sValue); + return $this->verifyAccount($mAccount, $iStorageType) + ? $this->oDriver->Put($mAccount, $iStorageType, $sKey, $sValue) + : false; } /** @@ -50,12 +43,9 @@ class Storage extends \RainLoop\Providers\AbstractProvider */ public function Get($mAccount, int $iStorageType, string $sKey, $mDefault = false) { - if (!$this->verifyAccount($mAccount, $iStorageType)) - { - return $mDefault; - } - - return $this->oDriver->Get($mAccount, $iStorageType, $sKey, $mDefault); + return $this->verifyAccount($mAccount, $iStorageType) + ? $this->oDriver->Get($mAccount, $iStorageType, $sKey, $mDefault) + : $mDefault; } /** @@ -63,12 +53,9 @@ class Storage extends \RainLoop\Providers\AbstractProvider */ public function Clear($mAccount, int $iStorageType, string $sKey) : bool { - if (!$this->verifyAccount($mAccount, $iStorageType)) - { - return false; - } - - return $this->oDriver->Clear($mAccount, $iStorageType, $sKey); + return $this->verifyAccount($mAccount, $iStorageType) + ? $this->oDriver->Clear($mAccount, $iStorageType, $sKey) + : false; } /** 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 435cddbc8..4e93b65d3 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 @@ -38,7 +38,7 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage $sFileName && \RainLoop\Utils::saveFile($sFileName, $sValue); return true; } catch (\Throwable $e) { - \error_log("{$e->getMessage()}: {$sFileName}"); + \SnappyMail\LOG::warning('FileStorage', $e->getMessage()); } return false; } @@ -55,6 +55,10 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage $sFileName = $this->generateFileName($mAccount, $iStorageType, $sKey); if ($sFileName && \file_exists($sFileName)) { $mValue = \file_get_contents($sFileName); + // Update mtime to prevent garbage collection + if (StorageType::SESSION === $iStorageType) { + \touch($sFileName); + } } return false === $mValue ? $mDefault : $mValue; } @@ -154,6 +158,7 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage public function GC() : void { + \clearstatcache(); foreach (\glob("{$this->sDataPath}/*", GLOB_ONLYDIR) as $sDomain) { foreach (\glob("{$sDomain}/*", GLOB_ONLYDIR) as $sLocal) { \MailSo\Base\Utils::RecTimeDirRemove("{$sLocal}/.sign_me", 3600 * 24 * 30); // 30 days 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 56952b90b..a7ba13b73 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php @@ -59,7 +59,7 @@ class Utils { return \SnappyMail\Crypt::DecryptUrlSafe( $sEncodedValues, - \sha1(APP_SALT.$sCustomKey.'Q'.static::GetSessionToken()) + \sha1(APP_SALT.$sCustomKey.'Q'.static::GetSessionToken(false)) ) ?: null; } @@ -72,14 +72,17 @@ class Utils } } - public static function GetSessionToken() : string + public static function GetSessionToken(bool $generate = true) : ?string { $sToken = static::GetCookie(self::SESSION_TOKEN, null); if (!$sToken) { + if (!$generate) { + return null; + } + \SnappyMail\LOG::debug('TOKENS', 'New SESSION_TOKEN'); $sToken = \MailSo\Base\Utils::Sha1Rand(APP_SALT); static::SetCookie(self::SESSION_TOKEN, $sToken); } - return \sha1('Session'.APP_SALT.$sToken.'Token'.APP_SALT); } @@ -225,11 +228,18 @@ class Utils { $dir = \dirname($filename); if (!\is_dir($dir) && !\mkdir($dir, 0700, true)) { - throw new \RainLoop\Exceptions\Exception('Failed to create directory "'.$dir.'"'); + throw new Exceptions\Exception('Failed to create directory "'.$dir.'"'); } if (false === \file_put_contents($filename, $data)) { - throw new \RainLoop\Exceptions\Exception('Failed to save file "'.$filename.'"'); + throw new Exceptions\Exception('Failed to save file "'.$filename.'"'); } + \clearstatcache(); \chmod($filename, 0600); +/* + try { + } catch (\Throwable $oException) { + throw new Exceptions\Exception($oException->getMessage() . ': ' . \error_get_last()['message']); + } +*/ } }