authInfo->isLoggedIn) { Tools::redirect($msz->urls->format('index')); return; } $ipAddress = $_SERVER['REMOTE_ADDR']; $countryCode = $_SERVER['COUNTRY_CODE'] ?? 'XX'; $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? ''; $twofactor = !empty($_POST['twofactor']) && is_array($_POST['twofactor']) ? $_POST['twofactor'] : []; $notices = []; $remainingAttempts = $msz->authCtx->loginAttempts->countRemainingAttempts($ipAddress); $tokenString = !empty($_GET['token']) && is_string($_GET['token']) ? $_GET['token'] : ( !empty($twofactor['token']) && is_string($twofactor['token']) ? $twofactor['token'] : '' ); $tokenUserId = $msz->authCtx->tfaSessions->getTokenUserId($tokenString); if(empty($tokenUserId)) { Tools::redirect($msz->urls->format('auth-login')); 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) { Tools::redirect($msz->urls->format('auth-login')); return; } while(!empty($twofactor)) { if(!CSRF::validateRequest()) { $notices[] = 'Was unable to verify the request, please try again!'; break; } $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? ''; $redirect = !empty($twofactor['redirect']) && is_string($twofactor['redirect']) ? $twofactor['redirect'] : ''; if(empty($twofactor['code']) || !is_string($twofactor['code'])) { $notices[] = 'Code field was empty.'; break; } if($remainingAttempts < 1) { $notices[] = 'There are too many failed login attempts from your IP address, please try again later.'; break; } $clientInfo = ClientInfo::fromRequest(); $totp = new TOTPGenerator($userInfo->totpKey); if(!in_array($twofactor['code'], $totp->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); break; } $msz->authCtx->loginAttempts->recordAttempt(true, $ipAddress, $countryCode, $userAgent, $clientInfo, $userInfo); $msz->authCtx->tfaSessions->deleteToken($tokenString); try { $sessionInfo = $msz->authCtx->sessions->createSession($userInfo, $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->setSessionToken($sessionInfo); $tokenBuilder->removeImpersonatedUserId(); $tokenInfo = $tokenBuilder->toInfo(); AuthTokenCookie::apply($msz->authCtx->createAuthTokenPacker()->pack($tokenInfo)); if(!Tools::isLocalURL($redirect)) $redirect = $msz->urls->format('index'); Tools::redirect($redirect); return; } Template::render('auth.twofactor', [ 'twofactor_notices' => $notices, 'twofactor_redirect' => !empty($_GET['redirect']) && is_string($_GET['redirect']) ? $_GET['redirect'] : $msz->urls->format('index'), 'twofactor_attempts_remaining' => $remainingAttempts, 'twofactor_token' => $tokenString, ]);