getURLs(); $authInfo = $msz->getAuthInfo(); if($authInfo->isLoggedIn()) { Tools::redirect($urls->format('settings-account')); return; } $authCtx = $msz->getAuthContext(); $users = $msz->getUsersContext()->getUsers(); $recoveryTokens = $authCtx->getRecoveryTokens(); $loginAttempts = $authCtx->getLoginAttempts(); $reset = !empty($_POST['reset']) && is_array($_POST['reset']) ? $_POST['reset'] : []; $forgot = !empty($_POST['forgot']) && is_array($_POST['forgot']) ? $_POST['forgot'] : []; $userId = !empty($reset['user']) ? (int)$reset['user'] : ( !empty($_GET['user']) ? (int)$_GET['user'] : 0 ); if($userId > 0) try { $userInfo = $users->getUser((string)$userId, 'id'); } catch(RuntimeException $ex) { Tools::redirect($urls->format('auth-forgot')); return; } $notices = []; $ipAddress = $_SERVER['REMOTE_ADDR']; $siteIsPrivate = $cfg->getBoolean('private.enable'); $canResetPassword = $siteIsPrivate ? $cfg->getBoolean('private.allow_password_reset', true) : true; $remainingAttempts = $loginAttempts->countRemainingAttempts($ipAddress); while($canResetPassword) { if(!empty($reset) && $userId > 0) { if(!CSRF::validateRequest()) { $notices[] = 'Was unable to verify the request, please try again!'; break; } $verifyCode = !empty($reset['verification']) && is_string($reset['verification']) ? $reset['verification'] : ''; try { $tokenInfo = $recoveryTokens->getToken(verifyCode: $verifyCode); } catch(RuntimeException $ex) { unset($tokenInfo); } if(empty($tokenInfo) || !$tokenInfo->isValid() || $tokenInfo->getUserId() !== (string)$userInfo->getId()) { $notices[] = 'Invalid verification code!'; break; } $password = !empty($reset['password']) && is_array($reset['password']) ? $reset['password'] : []; $passwordNew = !empty($password['new']) && is_string($password['new']) ? $password['new'] : ''; $passwordConfirm = !empty($password['confirm']) && is_string($password['confirm']) ? $password['confirm'] : ''; if(empty($passwordNew) || empty($passwordConfirm) || $passwordNew !== $passwordConfirm) { $notices[] = "Password confirmation failed!"; break; } $passwordValidation = $users->validatePassword($passwordNew); if($passwordValidation !== '') { $notices[] = $users->validatePasswordText($passwordValidation); break; } // also disables two factor auth to prevent getting locked out of account entirely // this behaviour should really be replaced with recovery keys... $users->updateUser($userInfo, password: $passwordNew, totpKey: ''); $msz->createAuditLog('PASSWORD_RESET', [], $userInfo); $recoveryTokens->invalidateToken($tokenInfo); Tools::redirect($urls->format('auth-login', ['redirect' => '/'])); return; } if(!empty($forgot)) { if(!CSRF::validateRequest()) { $notices[] = 'Was unable to verify the request, please try again!'; break; } if(empty($forgot['email']) || !is_string($forgot['email'])) { $notices[] = "You didn't supply an e-mail address."; break; } if($remainingAttempts < 1) { $notices[] = "There are too many failed login attempts from your IP address, please try again later."; break; } try { $forgotUser = $users->getUser($forgot['email'], 'email'); } catch(RuntimeException $ex) { unset($forgotUser); } if(empty($forgotUser) || $forgotUser->isDeleted()) { $notices[] = "This e-mail address is not registered with us."; break; } try { $tokenInfo = $recoveryTokens->getToken(userInfo: $forgotUser, remoteAddr: $ipAddress); } catch(RuntimeException $ex) { $tokenInfo = $recoveryTokens->createToken($forgotUser, $ipAddress); $recoveryMessage = Mailer::template('password-recovery', [ 'username' => $forgotUser->getName(), 'token' => $tokenInfo->getCode(), ]); $recoveryMail = Mailer::sendMessage( [$forgotUser->getEMailAddress() => $forgotUser->getName()], $recoveryMessage['subject'], $recoveryMessage['message'] ); if(!$recoveryMail) { $notices[] = "Failed to send reset email, please contact the administrator."; $recoveryTokens->invalidateToken($tokenInfo); break; } } Tools::redirect($urls->format('auth-reset', ['user' => $forgotUser->getId()])); return; } break; } Template::render(isset($userInfo) ? 'auth.password_reset' : 'auth.password_forgot', [ 'password_notices' => $notices, 'password_email' => !empty($forget['email']) && is_string($forget['email']) ? $forget['email'] : '', 'password_attempts_remaining' => $remainingAttempts, 'password_user' => $userInfo ?? null, 'password_verification' => $verifyCode ?? '', ]);