twofactor; $notices = []; $ipAddress = ip_remote_address(); $remainingAttempts = user_login_attempts_remaining($ipAddress); $tokenInfo = user_auth_tfa_token_info( RequestVar::get()->token->value('string') ?? $twofactor->token->value('string', '') ); // checking user_totp_key specifically because there's a fringe chance that // there's a token present, but totp is actually disabled if (empty($tokenInfo['user_totp_key'])) { header(sprintf('Location: %s', url('auth-login'))); return; } while (!empty($twofactor->value('array'))) { if (!csrf_verify('twofactor', $_POST['csrf'] ?? '')) { $notices[] = 'Was unable to verify the request, please try again!'; break; } $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? ''; $redirect = $twofactor->redirect->value('string', ''); if ($twofactor->code->empty()) { $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; } $givenCode = $twofactor->code->value('string', ''); $currentCode = totp_generate($tokenInfo['user_totp_key']); $previousCode = totp_generate($tokenInfo['user_totp_key'], time() - 30); if ($currentCode !== $givenCode && $previousCode !== $givenCode) { $notices[] = sprintf( "Invalid two factor code, %d attempt%s remaining", $remainingAttempts - 1, $remainingAttempts === 2 ? '' : 's' ); user_login_attempt_record(false, $tokenInfo['user_id'], $ipAddress, $userAgent); break; } user_login_attempt_record(true, $tokenInfo['user_id'], $ipAddress, $userAgent); $sessionKey = user_session_create($tokenInfo['user_id'], $ipAddress, $userAgent); if (empty($sessionKey)) { $notices[] = "Something broke while creating a session for you, please tell an administrator or developer about this!"; break; } user_auth_tfa_token_invalidate($tokenInfo['tfa_token']); user_session_start($tokenInfo['user_id'], $sessionKey); $cookieLife = strtotime(user_session_current('session_expires')); $cookieValue = base64url_encode(user_session_cookie_pack($tokenInfo['user_id'], $sessionKey)); setcookie('msz_auth', $cookieValue, $cookieLife, '/', '', true, true); if (!is_local_url($redirect)) { $redirect = url('index'); } header("Location: {$redirect}"); return; } echo tpl_render('auth.twofactor', [ 'twofactor_notices' => $notices, 'twofactor_redirect' => RequestVar::get()->redirect->value('string') ?? url('index'), 'twofactor_attempts_remaining' => $remainingAttempts, 'twofactor_token' => $tokenInfo['tfa_token'], ]);