Resolve #126 and nice for #151

This commit is contained in:
djmaze 2021-11-08 12:07:44 +01:00
parent 40f9f69b42
commit aed4d9e4c2
3 changed files with 85 additions and 51 deletions

View file

@ -209,35 +209,6 @@ trait UserAuth
return Utils::GetCookie(self::AUTH_SPEC_TOKEN_KEY, ''); return Utils::GetCookie(self::AUTH_SPEC_TOKEN_KEY, '');
} }
public function GetAccountFromSignMeToken(): ?Account
{
$oAccount = null;
$sSignMeToken = Utils::GetCookie(self::AUTH_SIGN_ME_TOKEN_KEY, '');
if (!empty($sSignMeToken)) {
$aTokenData = Utils::DecodeKeyValuesQ($sSignMeToken);
if (!empty($aTokenData['e']) && !empty($aTokenData['t'])) {
$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);
}
}
}
} else {
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
}
return $oAccount;
}
// rlspecauth / AuthAccountHash // rlspecauth / AuthAccountHash
public function getAuthAccountHash() : string public function getAuthAccountHash() : string
{ {
@ -306,34 +277,89 @@ trait UserAuth
$this->SetSpecAuthToken($sSpecAuthToken); $this->SetSpecAuthToken($sSpecAuthToken);
Utils::SetCookie(self::AUTH_SPEC_TOKEN_KEY, $sSpecAuthToken); Utils::SetCookie(self::AUTH_SPEC_TOKEN_KEY, $sSpecAuthToken);
if ($oAccount->SignMe() && \strlen($oAccount->SignMeToken())) { if ($oAccount->SignMe()) {
$this->SetSignMeToken($oAccount);
}
}
private static function GetSignMeToken(): ?array
{
$sSignMeToken = Utils::GetCookie(self::AUTH_SIGN_ME_TOKEN_KEY, '');
return empty($sSignMeToken) ? null : Utils::DecodeKeyValuesQ($sSignMeToken);
}
private function SetSignMeToken(Account $oAccount): void
{
$this->ClearSignMeData($oAccount);
$uuid = \SnappyMail\UUID::generate();
Utils::SetCookie(self::AUTH_SIGN_ME_TOKEN_KEY, Utils::SetCookie(self::AUTH_SIGN_ME_TOKEN_KEY,
Utils::EncodeKeyValuesQ(array( Utils::EncodeKeyValuesQ(array(
'e' => $oAccount->Email(), 'e' => $oAccount->Email(),
't' => $oAccount->SignMeToken() 'u' => $uuid
)), )),
\time() + 60 * 60 * 24 * 30); \time() + 3600 * 24 * 30); // 30 days
$this->StorageProvider()->Put($oAccount, $this->StorageProvider()->Put($oAccount,
StorageType::CONFIG, StorageType::SIGN_ME,
'sign_me', $uuid,
Utils::EncodeKeyValuesQ(array( Utils::EncryptString($oAccount->GetAuthToken(), \sha1(APP_SALT . $uuid))
'Time' => \time(),
'AuthToken' => $oAccount->GetAuthTokenQ(),
'SignMeToken' => $oAccount->SignMeToken()
))
); );
} }
public function GetAccountFromSignMeToken(): ?Account
{
$oAccount = null;
$aTokenData = static::GetSignMeToken();
if (!empty($aTokenData)) {
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, \sha1(APP_SALT . $aTokenData['u']));
if (!empty($sAuthToken)) {
$oAccount = $this->GetAccountFromCustomToken($sAuthToken, false, false, true);
}
} 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 ($oAccount) {
// Update lifetime
$this->SetSignMeToken($oAccount);
}
} else {
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
}
return $oAccount;
} }
protected function ClearSignMeData(Account $oAccount) : void protected function ClearSignMeData(Account $oAccount) : void
{ {
if ($oAccount) { if ($oAccount) {
$aTokenData = static::GetSignMeToken();
if (!empty($aTokenData['u']) && \SnappyMail\UUID::isValid($aTokenData['u'])) {
$this->StorageProvider()->Clear($oAccount, StorageType::SIGN_ME, $aTokenData['u']);
}
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY); Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
$this->StorageProvider()->Clear($oAccount, $this->StorageProvider()->Clear($oAccount, StorageType::CONFIG, 'sign_me');
StorageType::CONFIG,
'sign_me'
);
} }
} }

View file

@ -7,4 +7,5 @@ class StorageType
const USER = 1; const USER = 1;
const CONFIG = 2; const CONFIG = 2;
const NOBODY = 3; const NOBODY = 3;
const SIGN_ME = 4;
} }

View file

@ -85,7 +85,7 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
*/ */
public function DeleteStorage($oAccount) : bool public function DeleteStorage($oAccount) : bool
{ {
$sPath = $this->generateFileName($oAccount, StorageType::USER, '', false, true); $sPath = $this->generateFileName($oAccount, StorageType::CONFIG, '', false, true);
if ($sPath && \is_dir($sPath)) { if ($sPath && \is_dir($sPath)) {
\MailSo\Base\Utils::RecRmDir($sPath); \MailSo\Base\Utils::RecRmDir($sPath);
} }
@ -141,6 +141,8 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
case StorageType::NOBODY: case StorageType::NOBODY:
$sFilePath = $this->sDataPath.'/__nobody__/'.\sha1($sKey ?: \time()); $sFilePath = $this->sDataPath.'/__nobody__/'.\sha1($sKey ?: \time());
break; break;
case StorageType::SIGN_ME:
$sSubEmail = '.sign_me';
case StorageType::CONFIG: case StorageType::CONFIG:
if (empty($sEmail)) { if (empty($sEmail)) {
return ''; return '';
@ -165,6 +167,11 @@ class FileStorage implements \RainLoop\Providers\Storage\IStorage
} }
} }
// CleanupSignMeData
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
}
return $sFilePath; return $sFilePath;
} }