From 3a9bb2852e17c84a8f8927ce05c5a5b06eb89294 Mon Sep 17 00:00:00 2001 From: tadhgboyle Date: Sun, 8 Jun 2025 18:58:47 -0700 Subject: [PATCH 1/7] Add middleware system --- .../classes/Middleware/AbstractMiddleware.php | 6 ++ core/classes/Middleware/MiddlewareHandler.php | 44 +++++++++++++ core/classes/Middleware/MiddlewareType.php | 7 ++ core/includes/maintenance.php | 53 --------------- core/init.php | 64 ++----------------- core/templates/frontend_init.php | 39 +---------- .../classes/Events/RequestMiddlewareEvent.php | 34 ++++++++++ ...EnsureUserIntegrationsLinkedMiddleware.php | 25 ++++++++ .../Frontend/GlobalWarningsMiddleware.php | 23 +++++++ .../Global/BannedUserMiddleware.php | 36 +++++++++++ .../Global/MaintenanceModeMiddleware.php | 54 ++++++++++++++++ .../Middleware/Global/TFAMiddleware.php | 62 ++++++++++++++++++ modules/Core/module.php | 9 +++ modules/Core/pages/maintenance.php | 60 +++++++++++++++++ 14 files changed, 368 insertions(+), 148 deletions(-) create mode 100644 core/classes/Middleware/AbstractMiddleware.php create mode 100644 core/classes/Middleware/MiddlewareHandler.php create mode 100644 core/classes/Middleware/MiddlewareType.php delete mode 100644 core/includes/maintenance.php create mode 100644 modules/Core/classes/Events/RequestMiddlewareEvent.php create mode 100644 modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php create mode 100644 modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php create mode 100644 modules/Core/classes/Middleware/Global/BannedUserMiddleware.php create mode 100644 modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php create mode 100644 modules/Core/classes/Middleware/Global/TFAMiddleware.php create mode 100644 modules/Core/pages/maintenance.php diff --git a/core/classes/Middleware/AbstractMiddleware.php b/core/classes/Middleware/AbstractMiddleware.php new file mode 100644 index 0000000000..38fd0f08ee --- /dev/null +++ b/core/classes/Middleware/AbstractMiddleware.php @@ -0,0 +1,6 @@ +[] + */ + private array $middleware = []; + + /** + * Register a middleware class. + * + * @param class-string $class + */ + public function register(string $class): void + { + $this->middleware[] = $class; + } + + /** + * Get all registered middleware classes. + * + * @return class-string[] + */ + public function getMiddleware(): array + { + return $this->middleware; + } + + public function call(MiddlewareType $type, Container $container) + { + $middlewareClasses = $this->getMiddleware(); + + foreach ($middlewareClasses as $class) { + $middleware = $container->get($class); + + if ($middleware->type() === $type) { + $container->call([$middleware, 'handle']); + } + } + } +} diff --git a/core/classes/Middleware/MiddlewareType.php b/core/classes/Middleware/MiddlewareType.php new file mode 100644 index 0000000000..bc075f01f6 --- /dev/null +++ b/core/classes/Middleware/MiddlewareType.php @@ -0,0 +1,7 @@ +get('errors', 'maintenance_title'); -require_once ROOT_PATH . '/core/templates/frontend_init.php'; - -if (!$user->isLoggedIn()) { - $template->getEngine()->addVariables( - [ - 'LOGIN' => $language->get('general', 'sign_in'), - 'LOGIN_LINK' => URL::build('/login'), - ] - ); -} - -// Assign template variables -$template->getEngine()->addVariables( - [ - 'MAINTENANCE_TITLE' => $language->get('errors', 'maintenance_title'), - 'MAINTENANCE_MESSAGE' => Output::getPurified(Settings::get('maintenance_message', 'Maintenance mode is enabled.')), - 'RETRY' => $language->get('errors', 'maintenance_retry'), - ] -); - -// Load modules + template -Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template); - -$template->onPageLoad(); - -// Display template -$template->displayTemplate('maintenance'); diff --git a/core/init.php b/core/init.php index 70ab4cd5d4..2a6c7a078b 100644 --- a/core/init.php +++ b/core/init.php @@ -82,6 +82,11 @@ */ $container = new \DI\Container(); + + $container->set(\Symfony\Component\HttpFoundation\Request::class, function () { + return \Symfony\Component\HttpFoundation\Request::createFromGlobals(); + }); + $container->set(Cache::class, function () { return new Cache([ 'name' => 'nameless', @@ -357,30 +362,8 @@ } } - // Maintenance mode? - if (Settings::get('maintenance') === '1') { - // Enabled - // Admins only beyond this point - if (!$user->isLoggedIn() || !$user->canViewStaffCP()) { - // Maintenance mode - if (isset($_GET['route']) && ( - rtrim($_GET['route'], '/') === '/login' - || rtrim($_GET['route'], '/') === '/forgot_password' - || str_contains($_GET['route'], '/api/') - || str_contains($_GET['route'], 'queries') - || str_contains($_GET['route'], 'oauth/') - || str_contains($_GET['route'], 'store/listener') - )) { - // Can continue as normal - } else { - require(ROOT_PATH . '/core/includes/maintenance.php'); - die; - } - } else { - // Display notice to admin stating maintenance mode is enabled - define('BYPASS_MAINTENANCE', true); - } - } + // Execute middleware events + MiddlewareHandler::getInstance()->call(MiddlewareType::Global, $container); // Webhooks $hook_array = []; @@ -424,21 +407,6 @@ Debugging::setCanViewDetailedError($user->hasPermission('admincp.errors')); Debugging::setCanGenerateDebugLink($user->hasPermission('admincp.core.debugging')); - // Ensure a user is not banned - if ($user->data()->isbanned == 1) { - $user->logout(); - Session::flash('home_error', $language->get('user', 'you_have_been_banned')); - Redirect::to(URL::build('/')); - } - - // Is the IP address banned? - $ip_bans = DB::getInstance()->get('ip_bans', ['ip', $ip])->results(); - if (count($ip_bans)) { - $user->logout(); - Session::flash('home_error', $language->get('user', 'you_have_been_banned')); - Redirect::to(URL::build('/')); - } - // Update user last IP and last online if (filter_var($ip, FILTER_VALIDATE_IP)) { $user->update([ @@ -488,24 +456,6 @@ } } - // Does their group have TFA forced? - foreach ($user->getGroups() as $group) { - if ($group->force_tfa) { - $forced = true; - break; - } - } - - if (isset($forced) && $forced) { - // Do they have TFA configured? - if (!$user->data()->tfa_enabled && rtrim($_GET['route'], '/') != '/logout') { - if (!str_contains($_SERVER['REQUEST_URI'], 'do=enable_tfa') && !isset($_SERVER['HTTP_X_REQUESTED_WITH'])) { - Session::put('force_tfa_alert', $language->get('admin', 'force_tfa_alert')); - Redirect::to(URL::build('/user/settings', 'do=enable_tfa')); - } - } - } - $user_integrations = []; foreach ($user->getIntegrations() as $integrationUser) { $user_integrations[$integrationUser->getIntegration()->getName()] = [ diff --git a/core/templates/frontend_init.php b/core/templates/frontend_init.php index b1bc78bd12..bd914167a0 100644 --- a/core/templates/frontend_init.php +++ b/core/templates/frontend_init.php @@ -40,18 +40,7 @@ } } -// Check if any integrations is required before user can continue -if ($user->isLoggedIn() && defined('PAGE') && PAGE != 'cc_connections' && PAGE != 'oauth' && !(PAGE == 'cc_settings' && $_GET['do'] == 'enable_tfa')) { - foreach (Integrations::getInstance()->getEnabledIntegrations() as $integration) { - if ($integration->data()->required && $integration->allowLinking()) { - $integrationUser = $user->getIntegration($integration->getName()); - if ($integrationUser === null || !$integrationUser->isVerified()) { - Session::flash('connections_error', $language->get('user', 'integration_required_to_continue')); - Redirect::to(URL::build('/user/connections')); - } - } - } -} +MiddlewareHandler::getInstance()->call(MiddlewareType::Frontend, $container); if (defined('PAGE') && PAGE != 404) { // Auto unset signin tfa variables if set @@ -88,32 +77,6 @@ $template->getEngine()->addVariable('OG_IMAGE', rtrim(URL::getSelfURL(), '/') . Output::getClean($og_image)); } -// User related actions -if ($user->isLoggedIn()) { - // Warnings - $warnings = DB::getInstance()->get('infractions', ['punished', $user->data()->id])->results(); - if (count($warnings)) { - foreach ($warnings as $warning) { - if ($warning->revoked == 0 && $warning->acknowledged == 0) { - $template->getEngine()->addVariables([ - 'GLOBAL_WARNING_TITLE' => $language->get('user', 'you_have_received_a_warning'), - 'GLOBAL_WARNING_REASON' => Output::getClean($warning->reason), - 'GLOBAL_WARNING_ACKNOWLEDGE' => $language->get('user', 'acknowledge'), - 'GLOBAL_WARNING_ACKNOWLEDGE_LINK' => URL::build('/user/acknowledge/' . urlencode($warning->id)), - ]); - break; - } - } - } - - // Does the account need verifying? - // Get default group ID - $cache->setCache('default_group'); - $default_group = $cache->fetch('default_group', function () { - return Group::find(1, 'default_group')->id; - }); -} - // Page metadata if (isset($_GET['route']) && $_GET['route'] != '/') { $route = rtrim($_GET['route'], '/'); diff --git a/modules/Core/classes/Events/RequestMiddlewareEvent.php b/modules/Core/classes/Events/RequestMiddlewareEvent.php new file mode 100644 index 0000000000..a9e5c75bf0 --- /dev/null +++ b/modules/Core/classes/Events/RequestMiddlewareEvent.php @@ -0,0 +1,34 @@ +user = $user; + $this->request = $request; + } + + public static function description(): string + { + return 'Request middleware processing event'; + } + + public static function internal(): bool + { + return true; + } +} diff --git a/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php b/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php new file mode 100644 index 0000000000..19d54f3bd8 --- /dev/null +++ b/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php @@ -0,0 +1,25 @@ +isLoggedIn() && defined('PAGE') && PAGE != 'cc_connections' && PAGE != 'oauth' && !(PAGE == 'cc_settings' && $_GET['do'] == 'enable_tfa')) { + foreach (Integrations::getInstance()->getEnabledIntegrations() as $integration) { + if ($integration->data()->required && $integration->allowLinking()) { + $integrationUser = $user->getIntegration($integration->getName()); + if ($integrationUser === null || !$integrationUser->isVerified()) { + Session::flash('connections_error', $language->get('user', 'integration_required_to_continue')); + Redirect::to(URL::build('/user/connections')); + } + } + } + } + } +} diff --git a/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php b/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php new file mode 100644 index 0000000000..1f9a9f645c --- /dev/null +++ b/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php @@ -0,0 +1,23 @@ +query('SELECT * FROM nl2_integrations WHERE punished = ? AND revoked = 0 AND acknowledged = 0', [$user->data()->id])->results(); + foreach ($warnings as $warning) { + $template->getEngine()->addVariables([ + 'GLOBAL_WARNING_TITLE' => $language->get('user', 'you_have_received_a_warning'), + 'GLOBAL_WARNING_REASON' => Output::getClean($warning->reason), + 'GLOBAL_WARNING_ACKNOWLEDGE' => $language->get('user', 'acknowledge'), + 'GLOBAL_WARNING_ACKNOWLEDGE_LINK' => URL::build('/user/acknowledge/' . urlencode($warning->id)), + ]); + break; + } + } +} diff --git a/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php new file mode 100644 index 0000000000..930d47fcdb --- /dev/null +++ b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php @@ -0,0 +1,36 @@ +isLoggedIn() || !$user->data()->isbanned) { + return; + } + + if (!DB::getInstance()->get('ip_bans', ['ip', HttpUtils::getRemoteAddress()])->exists()) { + return; + } + + $user->logout(); + + Session::flash('home_error', $language->get('user', 'you_have_been_banned')); + Redirect::to(URL::build('/')); + } +} diff --git a/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php b/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php new file mode 100644 index 0000000000..c8f8f6a22d --- /dev/null +++ b/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php @@ -0,0 +1,54 @@ +isLoggedIn() && $user->canViewStaffCP()) { + // Display notice to admin stating maintenance mode is enabled + define('BYPASS_MAINTENANCE', true); + return; + } + + $route = $request->get('route'); + foreach (self::EXEMPTED_ROUTES as $exempted_route) { + if (str_starts_with($route, $exempted_route)) { + return; + } + } + + Redirect::to(URL::build('/maintenance')); + } +} diff --git a/modules/Core/classes/Middleware/Global/TFAMiddleware.php b/modules/Core/classes/Middleware/Global/TFAMiddleware.php new file mode 100644 index 0000000000..32b87f0e7d --- /dev/null +++ b/modules/Core/classes/Middleware/Global/TFAMiddleware.php @@ -0,0 +1,62 @@ +isLoggedIn()) { + return; + } + + // Allow access to exempted routes + $route = $request->get('route'); + foreach (self::EXEMPTED_ROUTES as $exempted_route) { + // Ideally we can use $request->getPathInfo(), but our routing allows a following slash + if (str_starts_with($route, $exempted_route)) { + return; + } + } + + // Skip if AJAX request, such as Alert or PM checks + if ($request->isXmlHttpRequest()) { + return; + } + + // Check if any of the user's groups have TFA forced + $forced_tfa = false; + foreach ($user->getGroups() as $group) { + if ($group->force_tfa) { + $forced_tfa = true; + break; + } + } + + // If TFA is forced and user doesn't have it enabled, redirect + if ($forced_tfa && !$user->data()->tfa_enabled) { + Session::put('force_tfa_alert', $language->get('user', 'force_tfa_alert')); + Redirect::to(URL::build('/user/settings', 'do=enable_tfa')); + } + } +} diff --git a/modules/Core/module.php b/modules/Core/module.php index d9be3ffc9e..713fbea172 100644 --- a/modules/Core/module.php +++ b/modules/Core/module.php @@ -51,6 +51,7 @@ public function __construct(Language $language, Pages $pages, User $user, Naviga $pages->add('Core', '/queries/tinymce_image_upload', 'queries/tinymce_image_upload.php'); $pages->add('Core', '/queries/reactions', 'queries/reactions.php'); $pages->add('Core', '/banner', 'pages/minecraft/banner.php'); + $pages->add('Core', '/maintenance', 'pages/maintenance.php'); $pages->add('Core', '/terms', 'pages/terms.php'); $pages->add('Core', '/privacy', 'pages/privacy.php'); $pages->add('Core', '/forgot_password', 'pages/forgot_password.php'); @@ -299,6 +300,7 @@ public function __construct(Language $language, Pages $pages, User $user, Naviga EventHandler::registerEvent(UserRegisteredEvent::class); EventHandler::registerEvent(UserValidatedEvent::class); EventHandler::registerEvent(UserWarnedEvent::class); + EventHandler::registerEvent(RequestMiddlewareEvent::class); // -- Pipelines EventHandler::registerEvent(PreCustomPageCreateEvent::class); @@ -452,6 +454,13 @@ public function __construct(Language $language, Pages $pages, User $user, Naviga EventHandler::registerListener(UserRegisteredEvent::class, DefaultUserNotificationPreferencesHook::class); + // -- Register middleware + MiddlewareHandler::getInstance()->register(MaintenanceModeMiddleware::class); + MiddlewareHandler::getInstance()->register(BannedUserMiddleware::class); + MiddlewareHandler::getInstance()->register(TFAMiddleware::class); + MiddlewareHandler::getInstance()->register(EnsureUserIntegrationsLinkedMiddleware::class); + MiddlewareHandler::getInstance()->register(GlobalWarningsMiddleware::class); + Email::addPlaceholder('[Sitename]', Output::getClean(SITE_NAME)); Email::addPlaceholder('[Greeting]', static fn(Language $viewing_language) => $viewing_language->get('emails', 'greeting')); Email::addPlaceholder('[Message]', static fn(Language $viewing_language, string $email) => $viewing_language->get('emails', $email . '_message')); diff --git a/modules/Core/pages/maintenance.php b/modules/Core/pages/maintenance.php new file mode 100644 index 0000000000..0a04efaca1 --- /dev/null +++ b/modules/Core/pages/maintenance.php @@ -0,0 +1,60 @@ +isLoggedIn() && $user->canViewStaffCP()) { + define('BYPASS_MAINTENANCE', true); + Redirect::back(); +} + +$pages = new Pages(); + +const PAGE = 'maintenance'; +$page_title = $language->get('errors', 'maintenance_title'); +require_once ROOT_PATH . '/core/templates/frontend_init.php'; + +if (!$user->isLoggedIn()) { + $template->getEngine()->addVariables([ + 'LOGIN' => $language->get('general', 'sign_in'), + 'LOGIN_LINK' => URL::build('/login'), + ]); +} + +// Assign template variables +$template->getEngine()->addVariables([ + 'MAINTENANCE_TITLE' => $language->get('errors', 'maintenance_title'), + 'MAINTENANCE_MESSAGE' => Output::getPurified(Settings::get('maintenance_message', 'Maintenance mode is enabled.')), + 'RETRY' => $language->get('errors', 'maintenance_retry'), +]); + +// Load modules + template +Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template); + +$template->onPageLoad(); + +// Display template +$template->displayTemplate('maintenance'); From debfc48c21932d80daf44f819d6bcd3691f45ae2 Mon Sep 17 00:00:00 2001 From: tadhgboyle Date: Sun, 8 Jun 2025 18:59:48 -0700 Subject: [PATCH 2/7] wip --- .../classes/Events/RequestMiddlewareEvent.php | 34 ------------------- modules/Core/module.php | 1 - 2 files changed, 35 deletions(-) delete mode 100644 modules/Core/classes/Events/RequestMiddlewareEvent.php diff --git a/modules/Core/classes/Events/RequestMiddlewareEvent.php b/modules/Core/classes/Events/RequestMiddlewareEvent.php deleted file mode 100644 index a9e5c75bf0..0000000000 --- a/modules/Core/classes/Events/RequestMiddlewareEvent.php +++ /dev/null @@ -1,34 +0,0 @@ -user = $user; - $this->request = $request; - } - - public static function description(): string - { - return 'Request middleware processing event'; - } - - public static function internal(): bool - { - return true; - } -} diff --git a/modules/Core/module.php b/modules/Core/module.php index 713fbea172..826354ad13 100644 --- a/modules/Core/module.php +++ b/modules/Core/module.php @@ -300,7 +300,6 @@ public function __construct(Language $language, Pages $pages, User $user, Naviga EventHandler::registerEvent(UserRegisteredEvent::class); EventHandler::registerEvent(UserValidatedEvent::class); EventHandler::registerEvent(UserWarnedEvent::class); - EventHandler::registerEvent(RequestMiddlewareEvent::class); // -- Pipelines EventHandler::registerEvent(PreCustomPageCreateEvent::class); From 5c98ca69dccfe2f272323f5c316d1761cd4c2fe7 Mon Sep 17 00:00:00 2001 From: tadhgboyle Date: Sun, 8 Jun 2025 19:00:23 -0700 Subject: [PATCH 3/7] wip --- .../Frontend/EnsureUserIntegrationsLinkedMiddleware.php | 2 +- .../classes/Middleware/Frontend/GlobalWarningsMiddleware.php | 2 +- modules/Core/classes/Middleware/Global/BannedUserMiddleware.php | 2 +- .../classes/Middleware/Global/MaintenanceModeMiddleware.php | 2 +- modules/Core/classes/Middleware/Global/TFAMiddleware.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php b/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php index 19d54f3bd8..e358757aa3 100644 --- a/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php +++ b/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php @@ -7,7 +7,7 @@ public function type(): MiddlewareType return MiddlewareType::Frontend; } - public function execute(User $user, Language $language): void + public function handle(User $user, Language $language): void { // Check if any integrations is required before user can continue if ($user->isLoggedIn() && defined('PAGE') && PAGE != 'cc_connections' && PAGE != 'oauth' && !(PAGE == 'cc_settings' && $_GET['do'] == 'enable_tfa')) { diff --git a/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php b/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php index 1f9a9f645c..61e548fbb6 100644 --- a/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php +++ b/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php @@ -7,7 +7,7 @@ public function type(): MiddlewareType return MiddlewareType::Frontend; } - public function execute(User $user, Language $language, TemplateBase $template): void + public function handle(User $user, Language $language, TemplateBase $template): void { $warnings = DB::getInstance()->query('SELECT * FROM nl2_integrations WHERE punished = ? AND revoked = 0 AND acknowledged = 0', [$user->data()->id])->results(); foreach ($warnings as $warning) { diff --git a/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php index 930d47fcdb..6043209585 100644 --- a/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php +++ b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php @@ -18,7 +18,7 @@ public function type(): MiddlewareType return MiddlewareType::Global; } - public function execute(User $user, Language $language): void + public function handle(User $user, Language $language): void { if (!$user->isLoggedIn() || !$user->data()->isbanned) { return; diff --git a/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php b/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php index c8f8f6a22d..924e17e3a6 100644 --- a/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php +++ b/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php @@ -28,7 +28,7 @@ public function type(): MiddlewareType return MiddlewareType::Global; } - public function execute(User $user, Request $request): void + public function handle(User $user, Request $request): void { // Check if maintenance mode is enabled if (!Settings::get('maintenance')) { diff --git a/modules/Core/classes/Middleware/Global/TFAMiddleware.php b/modules/Core/classes/Middleware/Global/TFAMiddleware.php index 32b87f0e7d..d539dc2f8a 100644 --- a/modules/Core/classes/Middleware/Global/TFAMiddleware.php +++ b/modules/Core/classes/Middleware/Global/TFAMiddleware.php @@ -23,7 +23,7 @@ public function type(): MiddlewareType return MiddlewareType::Global; } - public function execute(User $user, Request $request, Language $language): void + public function handle(User $user, Request $request, Language $language): void { // Only process for logged-in users if (!$user->isLoggedIn()) { From cfe0fc405187944141b51e047c1559fd7d4bd4d4 Mon Sep 17 00:00:00 2001 From: tadhgboyle Date: Sun, 8 Jun 2025 19:04:14 -0700 Subject: [PATCH 4/7] wip --- core/templates/frontend_init.php | 6 ++++-- .../Middleware/Frontend/GlobalWarningsMiddleware.php | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/templates/frontend_init.php b/core/templates/frontend_init.php index bd914167a0..599f414f89 100644 --- a/core/templates/frontend_init.php +++ b/core/templates/frontend_init.php @@ -40,8 +40,6 @@ } } -MiddlewareHandler::getInstance()->call(MiddlewareType::Frontend, $container); - if (defined('PAGE') && PAGE != 404) { // Auto unset signin tfa variables if set if ( @@ -61,6 +59,10 @@ require(ROOT_PATH . '/custom/templates/DefaultRevamp/template.php'); } +$container->set(TemplateBase::class, $template); + +MiddlewareHandler::getInstance()->call(MiddlewareType::Frontend, $container); + // Basic template variables $template->getEngine()->addVariables([ 'CONFIG_PATH' => defined('CONFIG_PATH') ? CONFIG_PATH . '/' : '/', diff --git a/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php b/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php index 61e548fbb6..a6561df93f 100644 --- a/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php +++ b/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php @@ -9,7 +9,7 @@ public function type(): MiddlewareType public function handle(User $user, Language $language, TemplateBase $template): void { - $warnings = DB::getInstance()->query('SELECT * FROM nl2_integrations WHERE punished = ? AND revoked = 0 AND acknowledged = 0', [$user->data()->id])->results(); + $warnings = DB::getInstance()->query('SELECT * FROM nl2_infractions WHERE punished = ? AND revoked = 0 AND acknowledged = 0', [$user->data()->id])->results(); foreach ($warnings as $warning) { $template->getEngine()->addVariables([ 'GLOBAL_WARNING_TITLE' => $language->get('user', 'you_have_received_a_warning'), From fb47543dcabd16da539f18b0779e9e8ff889f598 Mon Sep 17 00:00:00 2001 From: tadhgboyle Date: Sun, 8 Jun 2025 19:20:22 -0700 Subject: [PATCH 5/7] wip --- core/init.php | 2 ++ .../Middleware/Global/BannedUserMiddleware.php | 16 ++++------------ modules/Core/language/en_UK.json | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/core/init.php b/core/init.php index 2a6c7a078b..2205754cc3 100644 --- a/core/init.php +++ b/core/init.php @@ -164,6 +164,8 @@ } } + $container->set(User::class, $user); + // Check if we're in a subdirectory if (isset($directories)) { if (empty($directories[0])) { diff --git a/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php index 6043209585..10f20ba58a 100644 --- a/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php +++ b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php @@ -1,7 +1,5 @@ isLoggedIn() || !$user->data()->isbanned) { - return; - } + if (($user->isLoggedIn() && $user->data()->isbanned) || DB::getInstance()->get('ip_bans', ['ip', HttpUtils::getRemoteAddress()])->exists()) { + $user->logout(); - if (!DB::getInstance()->get('ip_bans', ['ip', HttpUtils::getRemoteAddress()])->exists()) { - return; + Session::flash('home_error', $language->get('user', 'you_have_been_banned')); + Redirect::to(URL::build('/')); } - - $user->logout(); - - Session::flash('home_error', $language->get('user', 'you_have_been_banned')); - Redirect::to(URL::build('/')); } } diff --git a/modules/Core/language/en_UK.json b/modules/Core/language/en_UK.json index 81e1bba545..143f7ab009 100644 --- a/modules/Core/language/en_UK.json +++ b/modules/Core/language/en_UK.json @@ -248,7 +248,7 @@ "admin/force_https_help": "If enabled, all requests to your website will be redirected to https. You must have a valid SSL certificate active for this to work.", "admin/force_premium_accounts": "Force premium Minecraft accounts?", "admin/force_tfa": "Force Two Factor Authentication for group members?", - "admin/force_tfa_alert": "Your group requires you to have Two Factor Authentication enabled.", + "user/force_tfa_alert": "Your group requires you to have Two Factor Authentication enabled.", "admin/force_tfa_warning": "Please ensure you know what this does, or else you risk locking out yourself and all the group members.", "admin/edit_user_tfa_disabled": "Two factor authentication has successfully been disabled for this user.", "admin/disable_tfa": "Disable 2FA", From 10057981c497197f104dd8bfef9a23fa16c23dd5 Mon Sep 17 00:00:00 2001 From: tadhgboyle Date: Sun, 8 Jun 2025 19:29:32 -0700 Subject: [PATCH 6/7] wip --- core/classes/Middleware/AbstractMiddleware.php | 4 +++- core/classes/Middleware/MiddlewareHandler.php | 10 +++++++++- .../EnsureUserIntegrationsLinkedMiddleware.php | 5 +---- .../Frontend/GlobalWarningsMiddleware.php | 5 +---- .../Middleware/Global/BannedUserMiddleware.php | 5 ----- .../Global/MaintenanceModeMiddleware.php | 18 ++---------------- .../Middleware/Global/TFAMiddleware.php | 16 +--------------- 7 files changed, 17 insertions(+), 46 deletions(-) diff --git a/core/classes/Middleware/AbstractMiddleware.php b/core/classes/Middleware/AbstractMiddleware.php index 38fd0f08ee..e1009a289b 100644 --- a/core/classes/Middleware/AbstractMiddleware.php +++ b/core/classes/Middleware/AbstractMiddleware.php @@ -2,5 +2,7 @@ abstract class AbstractMiddleware { - abstract public function type(): MiddlewareType; + public MiddlewareType $type = MiddlewareType::Global; + + public array $exemptRoutes = []; } diff --git a/core/classes/Middleware/MiddlewareHandler.php b/core/classes/Middleware/MiddlewareHandler.php index 25b2abb613..668e5a6cbb 100644 --- a/core/classes/Middleware/MiddlewareHandler.php +++ b/core/classes/Middleware/MiddlewareHandler.php @@ -1,6 +1,7 @@ get($class); + $request = $container->get(Request::class); - if ($middleware->type() === $type) { + foreach ($middleware->exemptRoutes as $exemptedRoute) { + if (str_starts_with($request->get('route'), $exemptedRoute)) { + continue 2; // Skip this middleware if the route is exempted + } + } + + if ($middleware->type === $type) { $container->call([$middleware, 'handle']); } } diff --git a/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php b/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php index e358757aa3..902222f332 100644 --- a/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php +++ b/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php @@ -2,10 +2,7 @@ class EnsureUserIntegrationsLinkedMiddleware extends AbstractMiddleware { - public function type(): MiddlewareType - { - return MiddlewareType::Frontend; - } + public MiddlewareType $type = MiddlewareType::Frontend; public function handle(User $user, Language $language): void { diff --git a/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php b/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php index a6561df93f..c895782965 100644 --- a/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php +++ b/modules/Core/classes/Middleware/Frontend/GlobalWarningsMiddleware.php @@ -2,10 +2,7 @@ class GlobalWarningsMiddleware extends AbstractMiddleware { - public function type(): MiddlewareType - { - return MiddlewareType::Frontend; - } + public MiddlewareType $type = MiddlewareType::Frontend; public function handle(User $user, Language $language, TemplateBase $template): void { diff --git a/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php index 10f20ba58a..84ecd69718 100644 --- a/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php +++ b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php @@ -11,11 +11,6 @@ */ class BannedUserMiddleware extends AbstractMiddleware { - public function type(): MiddlewareType - { - return MiddlewareType::Global; - } - public function handle(User $user, Language $language): void { if (($user->isLoggedIn() && $user->data()->isbanned) || DB::getInstance()->get('ip_bans', ['ip', HttpUtils::getRemoteAddress()])->exists()) { diff --git a/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php b/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php index 924e17e3a6..2a87cf84dd 100644 --- a/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php +++ b/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php @@ -1,7 +1,5 @@ get('route'); - foreach (self::EXEMPTED_ROUTES as $exempted_route) { - if (str_starts_with($route, $exempted_route)) { - return; - } - } - Redirect::to(URL::build('/maintenance')); } } diff --git a/modules/Core/classes/Middleware/Global/TFAMiddleware.php b/modules/Core/classes/Middleware/Global/TFAMiddleware.php index d539dc2f8a..e08e5235cd 100644 --- a/modules/Core/classes/Middleware/Global/TFAMiddleware.php +++ b/modules/Core/classes/Middleware/Global/TFAMiddleware.php @@ -13,16 +13,11 @@ */ class TFAMiddleware extends AbstractMiddleware { - private const EXEMPTED_ROUTES = [ + public array $exemptRoutes = [ '/logout', '/user/settings' // Allow access to settings to enable TFA ]; - public function type(): MiddlewareType - { - return MiddlewareType::Global; - } - public function handle(User $user, Request $request, Language $language): void { // Only process for logged-in users @@ -30,15 +25,6 @@ public function handle(User $user, Request $request, Language $language): void return; } - // Allow access to exempted routes - $route = $request->get('route'); - foreach (self::EXEMPTED_ROUTES as $exempted_route) { - // Ideally we can use $request->getPathInfo(), but our routing allows a following slash - if (str_starts_with($route, $exempted_route)) { - return; - } - } - // Skip if AJAX request, such as Alert or PM checks if ($request->isXmlHttpRequest()) { return; From 94dd9fb382ced1b080dcfcc90669da64da9f5ed5 Mon Sep 17 00:00:00 2001 From: tadhgboyle Date: Sun, 8 Jun 2025 19:54:11 -0700 Subject: [PATCH 7/7] wip --- ...EnsureUserIntegrationsLinkedMiddleware.php | 24 ++++++++++++------- .../Global/BannedUserMiddleware.php | 2 +- .../Global/MaintenanceModeMiddleware.php | 2 +- .../Middleware/Global/TFAMiddleware.php | 2 +- modules/Core/pages/maintenance.php | 5 +--- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php b/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php index 902222f332..9d827f63f3 100644 --- a/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php +++ b/modules/Core/classes/Middleware/Frontend/EnsureUserIntegrationsLinkedMiddleware.php @@ -4,17 +4,25 @@ class EnsureUserIntegrationsLinkedMiddleware extends AbstractMiddleware { public MiddlewareType $type = MiddlewareType::Frontend; + public array $exemptRoutes = [ + '/user/connections', + '/oauth', + '/user/settings', + ]; + public function handle(User $user, Language $language): void { + if (!$user->isLoggedIn()) { + return; + } + // Check if any integrations is required before user can continue - if ($user->isLoggedIn() && defined('PAGE') && PAGE != 'cc_connections' && PAGE != 'oauth' && !(PAGE == 'cc_settings' && $_GET['do'] == 'enable_tfa')) { - foreach (Integrations::getInstance()->getEnabledIntegrations() as $integration) { - if ($integration->data()->required && $integration->allowLinking()) { - $integrationUser = $user->getIntegration($integration->getName()); - if ($integrationUser === null || !$integrationUser->isVerified()) { - Session::flash('connections_error', $language->get('user', 'integration_required_to_continue')); - Redirect::to(URL::build('/user/connections')); - } + foreach (Integrations::getInstance()->getEnabledIntegrations() as $integration) { + if ($integration->data()->required && $integration->allowLinking()) { + $integrationUser = $user->getIntegration($integration->getName()); + if ($integrationUser === null || !$integrationUser->isVerified()) { + Session::flash('connections_error', $language->get('user', 'integration_required_to_continue')); + Redirect::to(URL::build('/user/connections')); } } } diff --git a/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php index 84ecd69718..714673fe44 100644 --- a/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php +++ b/modules/Core/classes/Middleware/Global/BannedUserMiddleware.php @@ -5,7 +5,7 @@ * Handles user bans and IP bans enforcement. * * @package NamelessMC\Hooks - * @author AI Assistant + * @author Aberdeener * @version 2.3.0 * @license MIT */ diff --git a/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php b/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php index 2a87cf84dd..e093744808 100644 --- a/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php +++ b/modules/Core/classes/Middleware/Global/MaintenanceModeMiddleware.php @@ -5,7 +5,7 @@ * Redirects non-admin users when maintenance mode is enabled. * * @package NamelessMC\Hooks - * @author AI Assistant + * @author Aberdeener * @version 2.3.0 * @license MIT */ diff --git a/modules/Core/classes/Middleware/Global/TFAMiddleware.php b/modules/Core/classes/Middleware/Global/TFAMiddleware.php index e08e5235cd..e2f88117d6 100644 --- a/modules/Core/classes/Middleware/Global/TFAMiddleware.php +++ b/modules/Core/classes/Middleware/Global/TFAMiddleware.php @@ -7,7 +7,7 @@ * Enforces TFA requirements for users in groups that require it. * * @package NamelessMC\Hooks - * @author AI Assistant + * @author Aberdeener * @version 2.3.0 * @license MIT */ diff --git a/modules/Core/pages/maintenance.php b/modules/Core/pages/maintenance.php index 0a04efaca1..5aee82749f 100644 --- a/modules/Core/pages/maintenance.php +++ b/modules/Core/pages/maintenance.php @@ -1,10 +1,7 @@