misuzu/public-legacy/auth/twofactor.php

109 lines
3.5 KiB
PHP
Raw Normal View History

2022-09-13 13:14:49 +00:00
<?php
namespace Misuzu;
use RuntimeException;
use Misuzu\TOTPGenerator;
use Misuzu\Auth\AuthTokenCookie;
2022-09-13 13:14:49 +00:00
$authInfo = $msz->getAuthInfo();
if($authInfo->isLoggedIn()) {
2022-09-13 13:14:49 +00:00
url_redirect('index');
return;
}
$users = $msz->getUsersContext()->getUsers();
$sessions = $msz->getSessions();
$tfaSessions = $msz->getTFASessions();
$loginAttempts = $msz->getLoginAttempts();
$ipAddress = $_SERVER['REMOTE_ADDR'];
$countryCode = $_SERVER['COUNTRY_CODE'] ?? 'XX';
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
2022-09-13 13:14:49 +00:00
$twofactor = !empty($_POST['twofactor']) && is_array($_POST['twofactor']) ? $_POST['twofactor'] : [];
$notices = [];
$remainingAttempts = $loginAttempts->countRemainingAttempts($ipAddress);
2022-09-13 13:14:49 +00:00
2023-07-27 12:44:50 +00:00
$tokenString = !empty($_GET['token']) && is_string($_GET['token']) ? $_GET['token'] : (
!empty($twofactor['token']) && is_string($twofactor['token']) ? $twofactor['token'] : ''
);
2022-09-13 13:14:49 +00:00
2023-07-27 12:44:50 +00:00
$tokenUserId = $tfaSessions->getTokenUserId($tokenString);
if(empty($tokenUserId)) {
2022-09-13 13:14:49 +00:00
url_redirect('auth-login');
return;
}
$userInfo = $users->getUser($tokenUserId, 'id');
2022-09-13 13:14:49 +00:00
// checking user_totp_key specifically because there's a fringe chance that
// there's a token present, but totp is actually disabled
2023-07-29 20:18:41 +00:00
if(!$userInfo->hasTOTPKey()) {
2022-09-13 13:14:49 +00:00
url_redirect('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;
}
2023-07-28 20:06:12 +00:00
$clientInfo = ClientInfo::fromRequest();
$totp = new TOTPGenerator($userInfo->getTOTPKey());
2023-07-28 20:06:12 +00:00
2023-07-29 20:18:41 +00:00
if(!in_array($twofactor['code'], $totp->generateRange())) {
2022-09-13 13:14:49 +00:00
$notices[] = sprintf(
"Invalid two factor code, %d attempt%s remaining",
$remainingAttempts - 1,
$remainingAttempts === 2 ? '' : 's'
);
2023-07-28 20:06:12 +00:00
$loginAttempts->recordAttempt(false, $ipAddress, $countryCode, $userAgent, $clientInfo, $userInfo);
2022-09-13 13:14:49 +00:00
break;
}
2023-07-28 20:06:12 +00:00
$loginAttempts->recordAttempt(true, $ipAddress, $countryCode, $userAgent, $clientInfo, $userInfo);
2023-07-27 12:44:50 +00:00
$tfaSessions->deleteToken($tokenString);
2022-09-13 13:14:49 +00:00
try {
2023-07-28 20:06:12 +00:00
$sessionInfo = $sessions->createSession($userInfo, $ipAddress, $countryCode, $userAgent, $clientInfo);
} catch(RuntimeException $ex) {
2022-09-13 13:14:49 +00:00
$notices[] = "Something broke while creating a session for you, please tell an administrator or developer about this!";
break;
}
$tokenBuilder = $authInfo->getTokenInfo()->toBuilder();
$tokenBuilder->setUserId($userInfo);
$tokenBuilder->setSessionToken($sessionInfo);
$tokenBuilder->removeImpersonatedUserId();
$tokenInfo = $tokenBuilder->toInfo();
AuthTokenCookie::apply($tokenPacker->pack($tokenInfo));
2022-09-13 13:14:49 +00:00
2023-07-28 20:06:12 +00:00
if(!is_local_url($redirect))
2022-09-13 13:14:49 +00:00
$redirect = url('index');
redirect($redirect);
return;
}
Template::render('auth.twofactor', [
'twofactor_notices' => $notices,
'twofactor_redirect' => !empty($_GET['redirect']) && is_string($_GET['redirect']) ? $_GET['redirect'] : url('index'),
'twofactor_attempts_remaining' => $remainingAttempts,
2023-07-27 12:44:50 +00:00
'twofactor_token' => $tokenString,
2022-09-13 13:14:49 +00:00
]);