2022-09-13 13:14:49 +00:00
|
|
|
<?php
|
|
|
|
namespace Misuzu;
|
|
|
|
|
2023-07-22 15:02:41 +00:00
|
|
|
use RuntimeException;
|
2023-08-02 22:12:47 +00:00
|
|
|
use Misuzu\TOTPGenerator;
|
2023-08-03 01:35:08 +00:00
|
|
|
use Misuzu\Auth\AuthTokenCookie;
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2024-12-02 02:28:08 +00:00
|
|
|
if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext))
|
|
|
|
die('Script must be called through the Misuzu route dispatcher.');
|
|
|
|
|
2024-11-30 04:09:29 +00:00
|
|
|
if($msz->authInfo->isLoggedIn) {
|
|
|
|
Tools::redirect($msz->urls->format('index'));
|
2022-09-13 13:14:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-05 18:33:03 +00:00
|
|
|
$ipAddress = $_SERVER['REMOTE_ADDR'];
|
2023-07-11 00:25:43 +00:00
|
|
|
$countryCode = $_SERVER['COUNTRY_CODE'] ?? 'XX';
|
2023-07-22 16:37:57 +00:00
|
|
|
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
|
2022-09-13 13:14:49 +00:00
|
|
|
$twofactor = !empty($_POST['twofactor']) && is_array($_POST['twofactor']) ? $_POST['twofactor'] : [];
|
|
|
|
$notices = [];
|
2023-07-22 16:37:57 +00:00
|
|
|
|
2024-11-30 04:09:29 +00:00
|
|
|
$remainingAttempts = $msz->authCtx->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
|
|
|
|
2024-11-30 04:09:29 +00:00
|
|
|
$tokenUserId = $msz->authCtx->tfaSessions->getTokenUserId($tokenString);
|
2023-07-27 12:44:50 +00:00
|
|
|
if(empty($tokenUserId)) {
|
2024-11-30 04:09:29 +00:00
|
|
|
Tools::redirect($msz->urls->format('auth-login'));
|
2022-09-13 13:14:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-11-30 04:09:29 +00:00
|
|
|
$userInfo = $msz->usersCtx->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
|
2024-11-30 04:09:29 +00:00
|
|
|
if(!$userInfo->hasTOTP) {
|
|
|
|
Tools::redirect($msz->urls->format('auth-login'));
|
2022-09-13 13:14:49 +00:00
|
|
|
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();
|
2024-11-30 04:09:29 +00:00
|
|
|
$totp = new TOTPGenerator($userInfo->totpKey);
|
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'
|
|
|
|
);
|
2024-11-30 04:09:29 +00:00
|
|
|
$msz->authCtx->loginAttempts->recordAttempt(false, $ipAddress, $countryCode, $userAgent, $clientInfo, $userInfo);
|
2022-09-13 13:14:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-11-30 04:09:29 +00:00
|
|
|
$msz->authCtx->loginAttempts->recordAttempt(true, $ipAddress, $countryCode, $userAgent, $clientInfo, $userInfo);
|
|
|
|
$msz->authCtx->tfaSessions->deleteToken($tokenString);
|
2022-09-13 13:14:49 +00:00
|
|
|
|
|
|
|
try {
|
2024-11-30 04:09:29 +00:00
|
|
|
$sessionInfo = $msz->authCtx->sessions->createSession($userInfo, $ipAddress, $countryCode, $userAgent, $clientInfo);
|
2023-07-22 15:02:41 +00:00
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
2024-11-30 04:09:29 +00:00
|
|
|
$tokenBuilder = $msz->authInfo->tokenInfo->toBuilder();
|
2023-08-03 01:35:08 +00:00
|
|
|
$tokenBuilder->setUserId($userInfo);
|
|
|
|
$tokenBuilder->setSessionToken($sessionInfo);
|
|
|
|
$tokenBuilder->removeImpersonatedUserId();
|
|
|
|
$tokenInfo = $tokenBuilder->toInfo();
|
|
|
|
|
2024-12-02 02:28:08 +00:00
|
|
|
AuthTokenCookie::apply($msz->authCtx->createAuthTokenPacker()->pack($tokenInfo));
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-09-08 20:40:48 +00:00
|
|
|
if(!Tools::isLocalURL($redirect))
|
2024-11-30 04:09:29 +00:00
|
|
|
$redirect = $msz->urls->format('index');
|
2022-09-13 13:14:49 +00:00
|
|
|
|
2023-09-08 20:40:48 +00:00
|
|
|
Tools::redirect($redirect);
|
2022-09-13 13:14:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Template::render('auth.twofactor', [
|
|
|
|
'twofactor_notices' => $notices,
|
2024-11-30 04:09:29 +00:00
|
|
|
'twofactor_redirect' => !empty($_GET['redirect']) && is_string($_GET['redirect']) ? $_GET['redirect'] : $msz->urls->format('index'),
|
2022-09-13 13:14:49 +00:00
|
|
|
'twofactor_attempts_remaining' => $remainingAttempts,
|
2023-07-27 12:44:50 +00:00
|
|
|
'twofactor_token' => $tokenString,
|
2022-09-13 13:14:49 +00:00
|
|
|
]);
|