Moved TOTP codes out of the main users table.
This commit is contained in:
parent
3897dc13fe
commit
b13cc7804d
13 changed files with 173 additions and 53 deletions
public-legacy
|
@ -118,7 +118,7 @@ while(!empty($_POST['login']) && is_array($_POST['login'])) {
|
|||
break;
|
||||
}
|
||||
|
||||
if($userInfo->hasTOTP) {
|
||||
if($msz->usersCtx->totps->hasUserTotp($userInfo)) {
|
||||
$tfaToken = $msz->authCtx->tfaSessions->createToken($userInfo);
|
||||
Tools::redirect($msz->urls->format('auth-two-factor', ['token' => $tfaToken, 'redirect' => $loginRedirect]));
|
||||
return;
|
||||
|
|
|
@ -71,7 +71,8 @@ while($canResetPassword) {
|
|||
|
||||
// also disables two factor auth to prevent getting locked out of account entirely
|
||||
// this behaviour should really be replaced with recovery keys...
|
||||
$msz->usersCtx->users->updateUser($userInfo, password: $passwordNew, totpKey: '');
|
||||
$msz->usersCtx->users->updateUser($userInfo, password: $passwordNew);
|
||||
$msz->usersCtx->totps->deleteUserTotp($userInfo);
|
||||
|
||||
$msz->createAuditLog('PASSWORD_RESET', [], $userInfo);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
namespace Misuzu;
|
||||
|
||||
use RuntimeException;
|
||||
use Misuzu\TOTPGenerator;
|
||||
use Misuzu\TotpGenerator;
|
||||
use Misuzu\Auth\AuthTokenCookie;
|
||||
|
||||
if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext))
|
||||
|
@ -31,11 +31,8 @@ if(empty($tokenUserId)) {
|
|||
return;
|
||||
}
|
||||
|
||||
$userInfo = $msz->usersCtx->users->getUser($tokenUserId, 'id');
|
||||
|
||||
// checking user_totp_key specifically because there's a fringe chance that
|
||||
// there's a token present, but totp is actually disabled
|
||||
if(!$userInfo->hasTOTP) {
|
||||
$totpInfo = $msz->usersCtx->totps->getUserTotp($tokenUserId);
|
||||
if($totpInfo === null) {
|
||||
Tools::redirect($msz->urls->format('auth-login'));
|
||||
return;
|
||||
}
|
||||
|
@ -60,30 +57,30 @@ while(!empty($twofactor)) {
|
|||
}
|
||||
|
||||
$clientInfo = ClientInfo::fromRequest();
|
||||
$totp = new TOTPGenerator($userInfo->totpKey);
|
||||
$generator = $totpInfo->createGenerator();
|
||||
|
||||
if(!in_array($twofactor['code'], $totp->generateRange())) {
|
||||
if(!in_array($twofactor['code'], $generator->generateRange())) {
|
||||
$notices[] = sprintf(
|
||||
"Invalid two factor code, %d attempt%s remaining",
|
||||
$remainingAttempts - 1,
|
||||
$remainingAttempts === 2 ? '' : 's'
|
||||
);
|
||||
$msz->authCtx->loginAttempts->recordAttempt(false, $ipAddress, $countryCode, $userAgent, $clientInfo, $userInfo);
|
||||
$msz->authCtx->loginAttempts->recordAttempt(false, $ipAddress, $countryCode, $userAgent, $clientInfo, $tokenUserId);
|
||||
break;
|
||||
}
|
||||
|
||||
$msz->authCtx->loginAttempts->recordAttempt(true, $ipAddress, $countryCode, $userAgent, $clientInfo, $userInfo);
|
||||
$msz->authCtx->loginAttempts->recordAttempt(true, $ipAddress, $countryCode, $userAgent, $clientInfo, $tokenUserId);
|
||||
$msz->authCtx->tfaSessions->deleteToken($tokenString);
|
||||
|
||||
try {
|
||||
$sessionInfo = $msz->authCtx->sessions->createSession($userInfo, $ipAddress, $countryCode, $userAgent, $clientInfo);
|
||||
$sessionInfo = $msz->authCtx->sessions->createSession($tokenUserId, $ipAddress, $countryCode, $userAgent, $clientInfo);
|
||||
} catch(RuntimeException $ex) {
|
||||
$notices[] = "Something broke while creating a session for you, please tell an administrator or developer about this!";
|
||||
break;
|
||||
}
|
||||
|
||||
$tokenBuilder = $msz->authInfo->tokenInfo->toBuilder();
|
||||
$tokenBuilder->setUserId($userInfo);
|
||||
$tokenBuilder->setUserId($tokenUserId);
|
||||
$tokenBuilder->setSessionToken($sessionInfo);
|
||||
$tokenBuilder->removeImpersonatedUserId();
|
||||
$tokenInfo = $tokenBuilder->toInfo();
|
||||
|
|
|
@ -15,6 +15,7 @@ if(!$msz->authInfo->loggedIn)
|
|||
$errors = [];
|
||||
$userInfo = $msz->authInfo->userInfo;
|
||||
$isRestricted = $msz->usersCtx->hasActiveBan($userInfo);
|
||||
$hasTotp = $msz->usersCtx->totps->hasUserTotp($userInfo);
|
||||
$isVerifiedRequest = CSRF::validateRequest();
|
||||
|
||||
if(!$isRestricted && $isVerifiedRequest && !empty($_POST['role'])) {
|
||||
|
@ -47,28 +48,29 @@ if(!$isRestricted && $isVerifiedRequest && !empty($_POST['role'])) {
|
|||
}
|
||||
}
|
||||
|
||||
if($isVerifiedRequest && isset($_POST['tfa']['enable']) && $userInfo->hasTOTP !== (bool)$_POST['tfa']['enable']) {
|
||||
$totpKey = '';
|
||||
|
||||
if($isVerifiedRequest && isset($_POST['tfa']['enable']) && $msz->usersCtx->totps->hasUserTotp($userInfo) !== (bool)$_POST['tfa']['enable']) {
|
||||
if((bool)$_POST['tfa']['enable']) {
|
||||
$totpKey = TOTPGenerator::generateKey();
|
||||
$totpInfo = $msz->usersCtx->totps->createUserTotp($userInfo);
|
||||
$totpSecret = $totpInfo->encodedSecret;
|
||||
$totpIssuer = $msz->siteInfo->name;
|
||||
$totpQrcode = (new QRCode(new QROptions([
|
||||
'version' => 5,
|
||||
'outputType' => QRCode::OUTPUT_IMAGE_JPG,
|
||||
'eccLevel' => QRCode::ECC_L,
|
||||
])))->render(sprintf('otpauth://totp/%s:%s?%s', $totpIssuer, $userInfo->name, http_build_query([
|
||||
'secret' => $totpKey,
|
||||
'secret' => $totpSecret,
|
||||
'issuer' => $totpIssuer,
|
||||
])));
|
||||
|
||||
$hasTotp = true;
|
||||
Template::set([
|
||||
'settings_2fa_code' => $totpKey,
|
||||
'settings_2fa_code' => $totpSecret,
|
||||
'settings_2fa_image' => $totpQrcode,
|
||||
]);
|
||||
} else {
|
||||
$hasTotp = false;
|
||||
$msz->usersCtx->totps->deleteUserTotp($userInfo);
|
||||
}
|
||||
|
||||
$msz->usersCtx->users->updateUser(userInfo: $userInfo, totpKey: $totpKey);
|
||||
}
|
||||
|
||||
if($isVerifiedRequest && !empty($_POST['current_password'])) {
|
||||
|
@ -122,4 +124,5 @@ Template::render('settings.account', [
|
|||
'settings_user' => $userInfo,
|
||||
'settings_roles' => $userRoles,
|
||||
'is_restricted' => $isRestricted,
|
||||
'has_totp' => $hasTotp,
|
||||
]);
|
||||
|
|
|
@ -143,7 +143,7 @@ if(isset($_POST['action']) && is_string($_POST['action'])) {
|
|||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'perms_calculated', ['user_id:s:n', 'forum_id:s:n', 'perms_category:s', 'perms_calculated:i']);
|
||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'profile_fields_values', ['field_id:s', 'user_id:s', 'format_id:s', 'field_value:s']);
|
||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'sessions', ['session_id:s', 'user_id:s', 'session_key:n', 'session_remote_addr_first:a', 'session_remote_addr_last:a:n', 'session_user_agent:s', 'session_country:s', 'session_expires:t', 'session_expires_bump:b', 'session_created:t', 'session_active:t:n']);
|
||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'users', ['user_id:s', 'user_name:s', 'user_password:n', 'user_email:s', 'user_remote_addr_first:a', 'user_remote_addr_last:a', 'user_super:b', 'user_country:s', 'user_colour:i:n', 'user_created:t', 'user_active:t:n', 'user_deleted:t:n', 'user_display_role_id:s:n', 'user_totp_key:n', 'user_about_content:s:n', 'user_about_parser:i', 'user_signature_content:s:n', 'user_signature_parser:i', 'user_birthdate:s:n', 'user_background_settings:i:n', 'user_title:s:n']);
|
||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'users', ['user_id:s', 'user_name:s', 'user_password:n', 'user_email:s', 'user_remote_addr_first:a', 'user_remote_addr_last:a', 'user_super:b', 'user_country:s', 'user_colour:i:n', 'user_created:t', 'user_active:t:n', 'user_deleted:t:n', 'user_display_role_id:s:n', 'user_about_content:s:n', 'user_about_parser:i', 'user_signature_content:s:n', 'user_signature_parser:i', 'user_birthdate:s:n', 'user_background_settings:i:n', 'user_title:s:n']);
|
||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'users_bans', ['ban_id:s', 'user_id:s', 'mod_id:n', 'ban_severity:i', 'ban_reason_public:s', 'ban_reason_private:s', 'ban_created:t', 'ban_expires:t:n']);
|
||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'users_password_resets', ['reset_id:s', 'user_id:s', 'reset_remote_addr:a', 'reset_requested:t', 'reset_code:n']);
|
||||
$tmpFiles[] = db_to_zip($archive, $userInfo, 'users_warnings', ['warn_id:s', 'user_id:s', 'mod_id:n', 'warn_body:s', 'warn_created:t']);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue