mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Enhancement to Two Factor Auth (Closes #123)
This commit is contained in:
parent
01a1bbf8f1
commit
524743ecbe
7 changed files with 215 additions and 262 deletions
|
|
@ -10,6 +10,7 @@ define('RL_CONTACTS_MAX', 300);
|
||||||
|
|
||||||
class Actions
|
class Actions
|
||||||
{
|
{
|
||||||
|
const AUTH_TFA_SIGN_ME_TOKEN_KEY = 'rltfasmauth';
|
||||||
const AUTH_SIGN_ME_TOKEN_KEY = 'rlsmauth';
|
const AUTH_SIGN_ME_TOKEN_KEY = 'rlsmauth';
|
||||||
const AUTH_MAILTO_TOKEN_KEY = 'rlmailtoauth';
|
const AUTH_MAILTO_TOKEN_KEY = 'rlmailtoauth';
|
||||||
const AUTH_SPEC_TOKEN_KEY = 'rlspecauth';
|
const AUTH_SPEC_TOKEN_KEY = 'rlspecauth';
|
||||||
|
|
@ -1426,20 +1427,20 @@ class Actions
|
||||||
$aData = $this->getTwoFactorInfo($oAccount->ParentEmailHelper());
|
$aData = $this->getTwoFactorInfo($oAccount->ParentEmailHelper());
|
||||||
if ($aData && isset($aData['IsSet'], $aData['Enable']) && !empty($aData['Secret']) && $aData['IsSet'] && $aData['Enable'])
|
if ($aData && isset($aData['IsSet'], $aData['Enable']) && !empty($aData['Secret']) && $aData['IsSet'] && $aData['Enable'])
|
||||||
{
|
{
|
||||||
$iAdditionalCodeTimeoutLimit = 60 * 60 * 24 * 14; // two weeks
|
$sSecretHash = \md5(APP_SALT.$aData['Secret'].\RainLoop\Utils::Fingerprint());
|
||||||
$iAdditionalCodeTimeout = isset($aData['Timeout']) && \is_numeric($aData['Timeout']) ? (int) $aData['Timeout'] : 0;
|
$sSecretCookieHash = \RainLoop\Utils::GetCookie(self::AUTH_TFA_SIGN_ME_TOKEN_KEY, '');
|
||||||
|
|
||||||
if (0 === $iAdditionalCodeTimeout || $iAdditionalCodeTimeout + $iAdditionalCodeTimeoutLimit < \time())
|
if (empty($sSecretCookieHash) || $sSecretHash !== $sSecretCookieHash)
|
||||||
{
|
{
|
||||||
$sAdditionalCode = \trim($sAdditionalCode);
|
$sAdditionalCode = \trim($sAdditionalCode);
|
||||||
if (empty($sAdditionalCode))
|
if (empty($sAdditionalCode))
|
||||||
{
|
{
|
||||||
$this->Logger()->Write('TwoFactorAuth: Required Code for '.$oAccount->ParentEmailHelper().' account.');
|
$this->Logger()->Write('TFA: Required Code for '.$oAccount->ParentEmailHelper().' account.');
|
||||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountTwoFactorAuthRequired);
|
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountTwoFactorAuthRequired);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$this->Logger()->Write('TwoFactorAuth: Verify Code for '.$oAccount->ParentEmailHelper().' account.');
|
$this->Logger()->Write('TFA: Verify Code for '.$oAccount->ParentEmailHelper().' account.');
|
||||||
|
|
||||||
$bGood = false;
|
$bGood = false;
|
||||||
if (6 < \strlen($sAdditionalCode) && !empty($aData['BackupCodes']))
|
if (6 < \strlen($sAdditionalCode) && !empty($aData['BackupCodes']))
|
||||||
|
|
@ -1455,7 +1456,8 @@ class Actions
|
||||||
|
|
||||||
if ($bAdditionalCodeSignMeSignMe)
|
if ($bAdditionalCodeSignMeSignMe)
|
||||||
{
|
{
|
||||||
$this->setSkipTimeoutForTwoFactor($oAccount->ParentEmailHelper(), \time());
|
\RainLoop\Utils::SetCookie(self::AUTH_TFA_SIGN_ME_TOKEN_KEY, $sSecretHash,
|
||||||
|
\time() + 60 * 60 * 24 * 14, '/', null, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$bGood && !$this->TwoFactorAuthProvider()->VerifyCode($aData['Secret'], $sAdditionalCode))
|
if (!$bGood && !$this->TwoFactorAuthProvider()->VerifyCode($aData['Secret'], $sAdditionalCode))
|
||||||
|
|
@ -1907,15 +1909,6 @@ class Actions
|
||||||
'SignMe/UserToken/'.$oAccount->SignMeToken());
|
'SignMe/UserToken/'.$oAccount->SignMeToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($oAccount && $this->TwoFactorAuthProvider()->IsActive())
|
|
||||||
{
|
|
||||||
$aData = $this->getTwoFactorInfo($oAccount->ParentEmailHelper());
|
|
||||||
if (\is_array($aData) && isset($aData['IsSet'], $aData['Enable']))
|
|
||||||
{
|
|
||||||
$this->setSkipTimeoutForTwoFactor($oAccount->ParentEmailHelper(), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->TrueResponse(__FUNCTION__);
|
return $this->TrueResponse(__FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4654,8 +4647,7 @@ class Actions
|
||||||
'Enable' => false,
|
'Enable' => false,
|
||||||
'Secret' => '',
|
'Secret' => '',
|
||||||
'Url' => '',
|
'Url' => '',
|
||||||
'BackupCodes' => '',
|
'BackupCodes' => ''
|
||||||
'Timeout' => 0
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!empty($sEmail))
|
if (!empty($sEmail))
|
||||||
|
|
@ -4681,7 +4673,6 @@ class Actions
|
||||||
$aResult['Enable'] = isset($mData['Enable']) ? !!$mData['Enable'] : false;
|
$aResult['Enable'] = isset($mData['Enable']) ? !!$mData['Enable'] : false;
|
||||||
$aResult['Secret'] = $mData['Secret'];
|
$aResult['Secret'] = $mData['Secret'];
|
||||||
$aResult['BackupCodes'] = $mData['BackupCodes'];
|
$aResult['BackupCodes'] = $mData['BackupCodes'];
|
||||||
$aResult['Timeout'] = isset($mData['Timeout']) ? (int) $mData['Timeout'] : 0;
|
|
||||||
|
|
||||||
$aResult['Url'] = $this->TwoFactorAuthProvider()->GetQRCodeGoogleUrl(
|
$aResult['Url'] = $this->TwoFactorAuthProvider()->GetQRCodeGoogleUrl(
|
||||||
$aResult['User'], $aResult['Secret'], $this->Config()->Get('webmail', 'title', ''));
|
$aResult['User'], $aResult['Secret'], $this->Config()->Get('webmail', 'title', ''));
|
||||||
|
|
@ -4748,42 +4739,6 @@ class Actions
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $sEmail
|
|
||||||
* @param int $iTime = 0
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private function setSkipTimeoutForTwoFactor($sEmail, $iTime = 0)
|
|
||||||
{
|
|
||||||
if (empty($sEmail))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sData = $this->StorageProvider()->Get(null,
|
|
||||||
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
|
|
||||||
'TwoFactorAuth/User/'.$sEmail.'/Data/'
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($sData)
|
|
||||||
{
|
|
||||||
$mData = \RainLoop\Utils::DecodeKeyValues($sData);
|
|
||||||
if (\is_array($mData))
|
|
||||||
{
|
|
||||||
$mData['Timeout'] = 0 < $iTime ? $iTime : 0;
|
|
||||||
|
|
||||||
return $this->StorageProvider()->Put(null,
|
|
||||||
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
|
|
||||||
'TwoFactorAuth/User/'.$sEmail.'/Data/',
|
|
||||||
\RainLoop\Utils::EncodeKeyValues($mData)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
|
|
@ -4828,7 +4783,6 @@ class Actions
|
||||||
'User' => $sEmail,
|
'User' => $sEmail,
|
||||||
'Enable' => false,
|
'Enable' => false,
|
||||||
'Secret' => $sSecret,
|
'Secret' => $sSecret,
|
||||||
'Timeout' => 0,
|
|
||||||
'BackupCodes' => \implode(' ', $aCodes)
|
'BackupCodes' => \implode(' ', $aCodes)
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
@ -4884,7 +4838,6 @@ class Actions
|
||||||
'User' => $sEmail,
|
'User' => $sEmail,
|
||||||
'Enable' => '1' === \trim($this->GetActionParam('Enable', '0')),
|
'Enable' => '1' === \trim($this->GetActionParam('Enable', '0')),
|
||||||
'Secret' => $mData['Secret'],
|
'Secret' => $mData['Secret'],
|
||||||
'Timeout' => isset($mData['Timeout']) ? $mData['Timeout'] : 0,
|
|
||||||
'BackupCodes' => $mData['BackupCodes']
|
'BackupCodes' => $mData['BackupCodes']
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
|
||||||
6
rainloop/v/0.0.0/static/js/admin.min.js
vendored
6
rainloop/v/0.0.0/static/js/admin.min.js
vendored
File diff suppressed because one or more lines are too long
14
rainloop/v/0.0.0/static/js/app.min.js
vendored
14
rainloop/v/0.0.0/static/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue