mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-08 17:07:03 +03:00
parent
40471957ee
commit
5719b63619
5 changed files with 62 additions and 27 deletions
|
|
@ -131,7 +131,10 @@ trait UserAuth
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->CheckMailConnection($oAccount, true);
|
$this->CheckMailConnection($oAccount, true);
|
||||||
$bSignMe && $this->SetSignMeToken($oAccount);
|
if (!$oMainAccount) {
|
||||||
|
$bSignMe && $this->SetSignMeToken($oAccount);
|
||||||
|
$this->StorageProvider()->Put($oAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true');
|
||||||
|
}
|
||||||
} catch (\Throwable $oException) {
|
} catch (\Throwable $oException) {
|
||||||
$this->loginErrorDelay();
|
$this->loginErrorDelay();
|
||||||
|
|
||||||
|
|
@ -177,6 +180,8 @@ trait UserAuth
|
||||||
*/
|
*/
|
||||||
public function getAccountFromToken(bool $bThrowExceptionOnFalse = true): ?Account
|
public function getAccountFromToken(bool $bThrowExceptionOnFalse = true): ?Account
|
||||||
{
|
{
|
||||||
|
$this->getMainAccountFromToken($bThrowExceptionOnFalse);
|
||||||
|
|
||||||
if (\is_null($this->oAdditionalAuthAccount) && isset($_COOKIE[self::AUTH_ADDITIONAL_TOKEN_KEY])) {
|
if (\is_null($this->oAdditionalAuthAccount) && isset($_COOKIE[self::AUTH_ADDITIONAL_TOKEN_KEY])) {
|
||||||
$aData = Utils::GetSecureCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
|
$aData = Utils::GetSecureCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
|
||||||
if ($aData) {
|
if ($aData) {
|
||||||
|
|
@ -191,7 +196,8 @@ trait UserAuth
|
||||||
Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
|
Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $this->oAdditionalAuthAccount ?: $this->getMainAccountFromToken($bThrowExceptionOnFalse);
|
|
||||||
|
return $this->oAdditionalAuthAccount ?: $this->oMainAuthAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -205,15 +211,34 @@ trait UserAuth
|
||||||
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
|
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
|
||||||
// Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
|
// Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
|
||||||
// Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
|
// Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
|
||||||
|
Utils::ClearCookie(Utils::SESSION_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
$aData = Utils::GetSecureCookie(self::AUTH_SPEC_TOKEN_KEY);
|
$aData = Utils::GetSecureCookie(self::AUTH_SPEC_TOKEN_KEY);
|
||||||
if ($aData) {
|
if ($aData) {
|
||||||
$this->oMainAuthAccount = MainAccount::NewInstanceFromTokenArray(
|
/**
|
||||||
$this,
|
* Server side control/kickout of logged in sessions
|
||||||
$aData,
|
* https://github.com/the-djmaze/snappymail/issues/151
|
||||||
$bThrowExceptionOnFalse
|
*/
|
||||||
);
|
if (isset($_COOKIE[Utils::SESSION_TOKEN])) {
|
||||||
|
$oMainAuthAccount = MainAccount::NewInstanceFromTokenArray(
|
||||||
|
$this,
|
||||||
|
$aData,
|
||||||
|
$bThrowExceptionOnFalse
|
||||||
|
);
|
||||||
|
$sToken = Utils::GetSessionToken();
|
||||||
|
if ($oMainAuthAccount && $this->StorageProvider()->Get($oMainAuthAccount, StorageType::SESSION, $sToken)) {
|
||||||
|
$this->oMainAuthAccount = $oMainAuthAccount;
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
|
||||||
|
Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$oAccount = $this->GetAccountFromSignMeToken();
|
$oAccount = $this->GetAccountFromSignMeToken();
|
||||||
if ($oAccount) {
|
if ($oAccount) {
|
||||||
|
|
@ -224,6 +249,10 @@ trait UserAuth
|
||||||
if ($bThrowExceptionOnFalse && !$this->oMainAuthAccount) {
|
if ($bThrowExceptionOnFalse && !$this->oMainAuthAccount) {
|
||||||
throw new ClientException(Notifications::AuthError);
|
throw new ClientException(Notifications::AuthError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->oMainAuthAccount) {
|
||||||
|
$this->StorageProvider()->Put($this->oMainAuthAccount, StorageType::SESSION, $sToken, 'true');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->oMainAuthAccount;
|
return $this->oMainAuthAccount;
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@ class Api
|
||||||
public static function LogoutCurrentLogginedUser() : bool
|
public static function LogoutCurrentLogginedUser() : bool
|
||||||
{
|
{
|
||||||
// TODO: kill SignMe data to prevent automatic login?
|
// TODO: kill SignMe data to prevent automatic login?
|
||||||
Utils::ClearCookie(Utils::SHORT_TOKEN);
|
Utils::ClearCookie(Utils::SESSION_TOKEN);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,5 @@ class StorageType
|
||||||
const CONFIG = 2;
|
const CONFIG = 2;
|
||||||
const NOBODY = 3;
|
const NOBODY = 3;
|
||||||
const SIGN_ME = 4;
|
const SIGN_ME = 4;
|
||||||
|
const SESSION = 5;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
|
||||||
if ($sFileName && \file_exists($sFileName)) {
|
if ($sFileName && \file_exists($sFileName)) {
|
||||||
$mValue = \file_get_contents($sFileName);
|
$mValue = \file_get_contents($sFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false === $mValue ? $mDefault : $mValue;
|
return false === $mValue ? $mDefault : $mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,13 +58,8 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
|
||||||
*/
|
*/
|
||||||
public function Clear($mAccount, int $iStorageType, string $sKey) : bool
|
public function Clear($mAccount, int $iStorageType, string $sKey) : bool
|
||||||
{
|
{
|
||||||
$mResult = true;
|
|
||||||
$sFileName = $this->generateFileName($mAccount, $iStorageType, $sKey);
|
$sFileName = $this->generateFileName($mAccount, $iStorageType, $sKey);
|
||||||
if ($sFileName && \file_exists($sFileName)) {
|
return $sFileName && \file_exists($sFileName) && \unlink($sFileName);
|
||||||
$mResult = \unlink($sFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $mResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -90,14 +84,20 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
|
||||||
*/
|
*/
|
||||||
protected function generateFileName($mAccount, int $iStorageType, string $sKey, bool $bMkDir = false, bool $bForDeleteAction = false) : string
|
protected function generateFileName($mAccount, int $iStorageType, string $sKey, bool $bMkDir = false, bool $bForDeleteAction = false) : string
|
||||||
{
|
{
|
||||||
$sEmail = $sSubEmail = '';
|
$sEmail = $sSubFolder = '';
|
||||||
if (null === $mAccount) {
|
if (null === $mAccount) {
|
||||||
$iStorageType = StorageType::NOBODY;
|
$iStorageType = StorageType::NOBODY;
|
||||||
} else if ($mAccount instanceof \RainLoop\Model\Account) {
|
} else if ($mAccount instanceof \RainLoop\Model\MainAccount) {
|
||||||
$sEmail = $mAccount instanceof \RainLoop\Model\AdditionalAccount ? $mAccount->ParentEmail() : $mAccount->Email();
|
$sEmail = $mAccount->Email();
|
||||||
if ($this->bLocal && $mAccount instanceof \RainLoop\Model\AdditionalAccount && !$bForDeleteAction)
|
if (StorageType::SIGN_ME === $iStorageType) {
|
||||||
{
|
$sSubFolder = '.sign_me';
|
||||||
$sSubEmail = $mAccount->Email();
|
} else if (StorageType::SESSION === $iStorageType) {
|
||||||
|
$sSubFolder = '.sessions';
|
||||||
|
}
|
||||||
|
} else if ($mAccount instanceof \RainLoop\Model\AdditionalAccount) {
|
||||||
|
$sEmail = $mAccount->ParentEmail();
|
||||||
|
if ($this->bLocal && !$bForDeleteAction) {
|
||||||
|
$sSubFolder = $mAccount->Email();
|
||||||
}
|
}
|
||||||
} else if (\is_string($mAccount) && empty($sEmail)) {
|
} else if (\is_string($mAccount) && empty($sEmail)) {
|
||||||
$sEmail = $mAccount;
|
$sEmail = $mAccount;
|
||||||
|
|
@ -110,7 +110,7 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
|
||||||
$sFilePath = $this->sDataPath.'/__nobody__/'.\sha1($sKey ?: \time());
|
$sFilePath = $this->sDataPath.'/__nobody__/'.\sha1($sKey ?: \time());
|
||||||
break;
|
break;
|
||||||
case StorageType::SIGN_ME:
|
case StorageType::SIGN_ME:
|
||||||
$sSubEmail = '.sign_me';
|
case StorageType::SESSION:
|
||||||
case StorageType::CONFIG:
|
case StorageType::CONFIG:
|
||||||
if (empty($sEmail)) {
|
if (empty($sEmail)) {
|
||||||
return '';
|
return '';
|
||||||
|
|
@ -123,7 +123,7 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
|
||||||
$sFilePath = $this->sDataPath
|
$sFilePath = $this->sDataPath
|
||||||
.'/'.\RainLoop\Utils::fixName($sDomain ?: 'unknown.tld')
|
.'/'.\RainLoop\Utils::fixName($sDomain ?: 'unknown.tld')
|
||||||
.'/'.\RainLoop\Utils::fixName(\implode('@', $aEmail) ?: '.unknown')
|
.'/'.\RainLoop\Utils::fixName(\implode('@', $aEmail) ?: '.unknown')
|
||||||
.'/'.($sSubEmail ? \RainLoop\Utils::fixName($sSubEmail).'/' : '')
|
.'/'.($sSubFolder ? \RainLoop\Utils::fixName($sSubFolder).'/' : '')
|
||||||
.($sKey ? \RainLoop\Utils::fixName($sKey) : '');
|
.($sKey ? \RainLoop\Utils::fixName($sKey) : '');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -138,11 +138,16 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CleanupSignMeData
|
// Cleanup SignMe
|
||||||
if (StorageType::SIGN_ME === $iStorageType && $sKey && 0 === \random_int(0, 25) && \is_dir($sFilePath)) {
|
if (StorageType::SIGN_ME === $iStorageType && $sKey && 0 === \random_int(0, 25) && \is_dir($sFilePath)) {
|
||||||
\MailSo\Base\Utils::RecTimeDirRemove(\is_dir($sFilePath), 3600 * 24 * 30); // 30 days
|
\MailSo\Base\Utils::RecTimeDirRemove(\is_dir($sFilePath), 3600 * 24 * 30); // 30 days
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cleanup sessions
|
||||||
|
if (StorageType::SESSION === $iStorageType && $sKey && 0 === \random_int(0, 25) && \is_dir($sFilePath)) {
|
||||||
|
\MailSo\Base\Utils::RecTimeDirRemove(\is_dir($sFilePath), 3600 * 3); // 3 hours
|
||||||
|
}
|
||||||
|
|
||||||
return $sFilePath;
|
return $sFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class Utils
|
||||||
* Session cookie
|
* Session cookie
|
||||||
* Used by: EncodeKeyValuesQ, DecodeKeyValuesQ
|
* Used by: EncodeKeyValuesQ, DecodeKeyValuesQ
|
||||||
*/
|
*/
|
||||||
SHORT_TOKEN = 'smsession';
|
SESSION_TOKEN = 'smsession';
|
||||||
|
|
||||||
public static function EncodeKeyValues(array $aValues, string $sCustomKey = '') : string
|
public static function EncodeKeyValues(array $aValues, string $sCustomKey = '') : string
|
||||||
{
|
{
|
||||||
|
|
@ -74,10 +74,10 @@ class Utils
|
||||||
|
|
||||||
public static function GetSessionToken() : string
|
public static function GetSessionToken() : string
|
||||||
{
|
{
|
||||||
$sToken = static::GetCookie(self::SHORT_TOKEN, null);
|
$sToken = static::GetCookie(self::SESSION_TOKEN, null);
|
||||||
if (!$sToken) {
|
if (!$sToken) {
|
||||||
$sToken = \MailSo\Base\Utils::Sha1Rand(APP_SALT);
|
$sToken = \MailSo\Base\Utils::Sha1Rand(APP_SALT);
|
||||||
static::SetCookie(self::SHORT_TOKEN, $sToken, 0);
|
static::SetCookie(self::SESSION_TOKEN, $sToken, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return \sha1('Session'.APP_SALT.$sToken.'Token'.APP_SALT);
|
return \sha1('Session'.APP_SALT.$sToken.'Token'.APP_SALT);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue