From 4a57e07a606413358f40ad296c04255ba4d75375 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 11 May 2026 02:03:43 -0400 Subject: [PATCH 1/9] refactor(base): modernize and tidy handleRequest() Signed-off-by: Josh --- lib/base.php | 217 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 126 insertions(+), 91 deletions(-) diff --git a/lib/base.php b/lib/base.php index b945ba3ee1d33..c6e5ba3252a68 100644 --- a/lib/base.php +++ b/lib/base.php @@ -34,6 +34,7 @@ use OCP\Util; use Psr\Log\LoggerInterface; use Symfony\Component\Routing\Exception\MethodNotAllowedException; +use Symfony\Component\Routing\Exception\ResourceNotFoundException; use function OCP\Log\logger; require_once 'public/Constants.php'; @@ -237,22 +238,15 @@ public static function checkInstalled(\OC\SystemConfig $systemConfig): void { } } - public static function checkMaintenanceMode(\OC\SystemConfig $systemConfig): void { - // Allow ajax update script to execute without being stopped - if (((bool)$systemConfig->getValue('maintenance', false)) && OC::$SUBURI !== '/core/ajax/update.php') { - // send http status 503 - http_response_code(503); - header('X-Nextcloud-Maintenance-Mode: 1'); - header('Retry-After: 120'); - - // render error page - $template = Server::get(ITemplateManager::class)->getTemplate('', 'update.user', 'guest'); - \OCP\Util::addScript('core', 'maintenance'); - \OCP\Util::addScript('core', 'common'); - \OCP\Util::addStyle('core', 'guest'); - $template->printPage(); - die(); - } + public static function renderMaintenanceMode(\OC\SystemConfig $systemConfig): void { + http_response_code(503); + header('X-Nextcloud-Maintenance-Mode: 1'); + header('Retry-After: 120'); + $template = Server::get(ITemplateManager::class)->getTemplate('', 'update.user', 'guest'); + Util::addScript('core', 'maintenance'); + Util::addScript('core', 'common'); + Util::addStyle('core', 'guest'); + $template->printPage(); } /** @@ -1071,106 +1065,110 @@ public static function registerShareHooks(\OC\SystemConfig $systemConfig): void } /** - * Handle the request + * Handle the incoming request: bootstrap auth/apps, enforce maintenance/upgrade checks, + * route the request, and fall back to default error or redirect responses. */ public static function handleRequest(): void { Server::get(\OCP\Diagnostics\IEventLogger::class)->start('handle_request', 'Handle request'); $systemConfig = Server::get(\OC\SystemConfig::class); + $installed = $systemConfig->getValue('installed', false); - // Check if Nextcloud is installed or in maintenance (update) mode - if (!$systemConfig->getValue('installed', false)) { + // Run setup if Nextcloud is not installed + if (!$installed) { Server::get(ISession::class)->clear(); - $controller = Server::get(\OC\Core\Controller\SetupController::class); - $controller->run($_POST); + $setup = Server::get(\OC\Core\Controller\SetupController::class); + $setup->run($_POST); exit(); } $request = Server::get(IRequest::class); $request->throwDecodingExceptionIfAny(); + $requestPath = $request->getRawPathInfo(); + if ($requestPath === '/heartbeat') { return; } - if (substr($requestPath, -3) !== '.js') { // we need these files during the upgrade - self::checkMaintenanceMode($systemConfig); - if (\OCP\Util::needUpgrade()) { - if (function_exists('opcache_reset')) { - opcache_reset(); - } - if (!((bool)$systemConfig->getValue('maintenance', false))) { - self::printUpgradePage($systemConfig); - exit(); - } + $maintenance = $systemConfig->getValue('maintenance', false); + // Needed during maintenance mode and upgrades + $bypassMaintenance = str_ends_with($requestPath, '.js') || OC::$SUBURI === '/core/ajax/update.php'; + + // Show "maintenance in progress" page if Nextcloud is undergoing maintenance and not a bypass URL + if ($maintenance && !$bypassMaintenance) { + self::renderMaintenancePage($systemConfig); + exit(); + } + + $upgrade = Util::needUpgrade(); + + if ($upgrade) + if (function_exists('opcache_reset')) { + opcache_reset(); + $maintenance = $systemConfig->getValue('maintenance', false); + } + // Show "upgrade" page if Nextcloud needs to be upgraded and not already in progress. + if ($upgrade && !maintenance) { + // NOTE: This is shown to the first web visitor to land after a code update... + // ...and will continue to be shown to subsequent visitors until the actual upgrade is + // triggered. + self::renderUpgradePage($systemConfig); + exit(); } } + // + // At this point the request is either: + // - a regular request (a logged in user doing something or a non-logged in user trying to do something) + // - a special request that gets to bypass maintenance mode + // + $appManager = Server::get(\OCP\App\IAppManager::class); - // Always load authentication apps $appManager->loadApps(['authentication']); $appManager->loadApps(['extended_authentication']); - // Load minimum set of apps - if (!\OCP\Util::needUpgrade() - && !((bool)$systemConfig->getValue('maintenance', false))) { - // For logged-in users: Load everything - if (Server::get(IUserSession::class)->isLoggedIn()) { - $appManager->loadApps(); - } else { - // For guests: Load only filesystem and logging - $appManager->loadApps(['filesystem', 'logging']); + $userSession = Server::get(IUserSession::class); + $loggedIn = $userSession->isLoggedIn(); + + self::loadRuntimeAppsForRequest($appManager, $loggedIn); + if (!$loggedIn) + if ($requestPath === '/apps/oauth2/api/v1/token') { // Don't try to login when a client is trying to get a OAuth token. // OAuth needs to support basic auth too, so the login is not valid // inside Nextcloud and the Login exception would ruin it. - if ($request->getRawPathInfo() !== '/apps/oauth2/api/v1/token') { - try { - self::handleLogin($request); - } catch (DisabledUserException $e) { - // Disabled users would not be seen as logged in and - // trying to log them in would fail, so the login - // exception is ignored for the themed stylesheets and - // images. - if ($request->getRawPathInfo() !== '/apps/theming/theme/default.css' - && $request->getRawPathInfo() !== '/apps/theming/theme/light.css' - && $request->getRawPathInfo() !== '/apps/theming/theme/dark.css' - && $request->getRawPathInfo() !== '/apps/theming/theme/light-highcontrast.css' - && $request->getRawPathInfo() !== '/apps/theming/theme/dark-highcontrast.css' - && $request->getRawPathInfo() !== '/apps/theming/theme/opendyslexic.css' - && $request->getRawPathInfo() !== '/apps/theming/image/background' - && $request->getRawPathInfo() !== '/apps/theming/image/logo' - && $request->getRawPathInfo() !== '/apps/theming/image/logoheader' - && !str_starts_with($request->getRawPathInfo(), '/apps/theming/favicon') - && !str_starts_with($request->getRawPathInfo(), '/apps/theming/icon')) { - throw $e; - } - } - } + continue; } - } - - if (!self::$CLI) { try { - if (!\OCP\Util::needUpgrade()) { - $appManager->loadApps(['filesystem', 'logging']); - $appManager->loadApps(); + // Try normal login + self::handleLogin($request); + $loggedIn = $userSession->isLoggedIn(); + self::loadRuntimeAppsForRequest($appManager, $loggedIn); + } catch (DisabledUserException $e) { + // Don’t prevent theming asset requests if user is merely disabled. + if (!self::themingAssetRequest($requestPath)) { + throw $e; } - Server::get(\OC\Route\Router::class)->match($request->getRawPathInfo()); - return; - } catch (Symfony\Component\Routing\Exception\ResourceNotFoundException $e) { - //header('HTTP/1.0 404 Not Found'); - } catch (Symfony\Component\Routing\Exception\MethodNotAllowedException $e) { - http_response_code(405); - return; } } - // Handle WebDAV - if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') { - // not allowed any more to prevent people - // mounting this root directly. - // Users need to mount remote.php/webdav instead. + // Try to route the request. + $router = Server::get(\OC\Route\Router::class); + // Note: User may (or may still not) be logged in. + try { + $router->match($request->getRawPathInfo()); + return; + } catch (ResourceNotFoundException $e) { + // ... + } catch (MethodNotAllowedException $e) { + http_response_code(405); + return; + } + + $webdav = isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND'; + if ($webdav) { + // Users need to mount remote.php/{webdav, dav} instead. http_response_code(405); return; } @@ -1182,31 +1180,30 @@ public static function handleRequest(): void { return; } - // Handle resources that can't be found - // This prevents browsers from redirecting to the default page and then - // attempting to parse HTML as CSS and similar. + // Handle requests for select resource types that are unavailable (regardless of reason) $destinationHeader = $request->getHeader('Sec-Fetch-Dest'); if (in_array($destinationHeader, ['font', 'script', 'style'])) { + // Prevents browsers from redirecting to the default endpoint and attempting + // to parse HTML as CSS, etc. http_response_code(404); return; } - // Redirect to the default app or login only as an entry point if ($requestPath === '') { - // Someone is logged in - $userSession = Server::get(IUserSession::class); + // Redirect to the default app if visitor is logged in if ($userSession->isLoggedIn()) { header('X-User-Id: ' . $userSession->getUser()?->getUID()); header('Location: ' . Server::get(IURLGenerator::class)->linkToDefaultPageUrl()); } else { - // Not handled and not logged in + // Redirect to the login page if visitor is not logged in header('Location: ' . Server::get(IURLGenerator::class)->linkToRouteAbsolute('core.login.showLoginForm')); } return; } + // Try to send visitor to the Nextcloud 404 page if at all possible try { - Server::get(\OC\Route\Router::class)->match('/error/404'); + $router->match('/error/404'); } catch (\Exception $e) { if (!$e instanceof MethodNotAllowedException) { logger('core')->emergency($e->getMessage(), ['exception' => $e]); @@ -1220,8 +1217,46 @@ public static function handleRequest(): void { } } + private static function themingAssetRequest(string $requestPath): bool { + if ($requestPath === '/apps/theming/theme/default.css' + || $requestPath === '/apps/theming/theme/light.css' + || $requestPath === '/apps/theming/theme/dark.css' + || $requestPath === '/apps/theming/theme/light-highcontrast.css' + || $requestPath === '/apps/theming/theme/dark-highcontrast.css' + || $requestPath === '/apps/theming/theme/opendyslexic.css' + || $requestPath === '/apps/theming/image/background' + || $requestPath === '/apps/theming/image/logo' + || $requestPath === '/apps/theming/image/logoheader' + || str_starts_with($requestPath, '/apps/theming/favicon') + || str_starts_with($requestPath, '/apps/theming/icon') + ) { + return true; + } + + return false; + } + + /** + * Load minimum set of apps required to handle the request. + */ + private static function loadRuntimeAppsForRequest(\OCP\App\IAppManager $appManager, bool $loggedIn): void { + // Always load authentication apps + $appManager->loadApps(['authentication']); + $appManager->loadApps(['extended_authentication']); + if ($loggedIn) { + // For logged-in users: Load everything + $appManager->loadApps(); + } else { + // For guests: Load only filesystem and logging + $appManager->loadApps(['filesystem', 'logging']); + } + } + /** - * Check login: apache auth, auth token, basic auth + * Attempt to authenticate the current request using supported login methods. + * + * Tries, in order: Apache auth, app API login, token login, cookie login, + * and basic auth. Federation requests are excluded. */ public static function handleLogin(OCP\IRequest $request): bool { if ($request->getHeader('X-Nextcloud-Federation')) { From 1423b8ce4721a03057fb5d3e649dcaa930b5e36b Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 11 May 2026 02:15:22 -0400 Subject: [PATCH 2/9] chore: fixup typo Signed-off-by: Josh --- lib/base.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/base.php b/lib/base.php index c6e5ba3252a68..fa80dcee3f945 100644 --- a/lib/base.php +++ b/lib/base.php @@ -1102,7 +1102,7 @@ public static function handleRequest(): void { $upgrade = Util::needUpgrade(); - if ($upgrade) + if ($upgrade) { if (function_exists('opcache_reset')) { opcache_reset(); $maintenance = $systemConfig->getValue('maintenance', false); From a5282c47e6c77dbfb4fffd6f51275d221bd9873f Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 11 May 2026 02:27:42 -0400 Subject: [PATCH 3/9] chore: fixup base typo Signed-off-by: Josh --- lib/base.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/base.php b/lib/base.php index fa80dcee3f945..c34b4c1723831 100644 --- a/lib/base.php +++ b/lib/base.php @@ -1133,7 +1133,7 @@ public static function handleRequest(): void { self::loadRuntimeAppsForRequest($appManager, $loggedIn); - if (!$loggedIn) + if (!$loggedIn) { if ($requestPath === '/apps/oauth2/api/v1/token') { // Don't try to login when a client is trying to get a OAuth token. // OAuth needs to support basic auth too, so the login is not valid From 17dea660a832b8a37119924c5b870fb48462bdaf Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 11 May 2026 09:00:35 -0400 Subject: [PATCH 4/9] chore: handle login bypass same as maintenance bypass Signed-off-by: Josh --- lib/base.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/base.php b/lib/base.php index c34b4c1723831..4e50c85158158 100644 --- a/lib/base.php +++ b/lib/base.php @@ -1130,16 +1130,14 @@ public static function handleRequest(): void { $userSession = Server::get(IUserSession::class); $loggedIn = $userSession->isLoggedIn(); + // Don't try to login when a client is trying to get a OAuth token. + // OAuth needs to support basic auth too, so the login is not valid + // inside Nextcloud and the Login exception would ruin it. + $bypassLogin = $requestPath === '/apps/oauth2/api/v1/token'; self::loadRuntimeAppsForRequest($appManager, $loggedIn); - if (!$loggedIn) { - if ($requestPath === '/apps/oauth2/api/v1/token') { - // Don't try to login when a client is trying to get a OAuth token. - // OAuth needs to support basic auth too, so the login is not valid - // inside Nextcloud and the Login exception would ruin it. - continue; - } + if (!$loggedIn && !$bypassLogin) { try { // Try normal login self::handleLogin($request); From 3edb7299263d1d6fbe04fba65ed1e1906bb8a8bc Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 11 May 2026 09:34:40 -0400 Subject: [PATCH 5/9] chore: fixup typos and further streamline upgrade path Signed-off-by: Josh --- lib/base.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/base.php b/lib/base.php index 4e50c85158158..77da801dda560 100644 --- a/lib/base.php +++ b/lib/base.php @@ -238,7 +238,7 @@ public static function checkInstalled(\OC\SystemConfig $systemConfig): void { } } - public static function renderMaintenanceMode(\OC\SystemConfig $systemConfig): void { + public static function renderMaintenancePage(\OC\SystemConfig $systemConfig): void { http_response_code(503); header('X-Nextcloud-Maintenance-Mode: 1'); header('Retry-After: 120'); @@ -252,7 +252,7 @@ public static function renderMaintenanceMode(\OC\SystemConfig $systemConfig): vo /** * Prints the upgrade page */ - private static function printUpgradePage(\OC\SystemConfig $systemConfig): void { + private static function renderUpgradePage(\OC\SystemConfig $systemConfig): void { $cliUpgradeLink = $systemConfig->getValue('upgrade.cli-upgrade-link', ''); $disableWebUpdater = $systemConfig->getValue('upgrade.disable-web', false); $tooBig = false; @@ -1102,19 +1102,16 @@ public static function handleRequest(): void { $upgrade = Util::needUpgrade(); + // Show "upgrade" page if Nextcloud needs to be upgraded and not in maintenance mode (i.e. already in progress). if ($upgrade) { if (function_exists('opcache_reset')) { opcache_reset(); - $maintenance = $systemConfig->getValue('maintenance', false); - } - // Show "upgrade" page if Nextcloud needs to be upgraded and not already in progress. - if ($upgrade && !maintenance) { - // NOTE: This is shown to the first web visitor to land after a code update... - // ...and will continue to be shown to subsequent visitors until the actual upgrade is - // triggered. - self::renderUpgradePage($systemConfig); - exit(); } + // NOTE: This is shown to the first web visitor to land after a code update... + // ...and will continue to be shown to subsequent visitors until the upgrade is + // triggered. + self::renderUpgradePage($systemConfig); + exit(); } // From e86a3212c43553870875994e9f2eb731533012a5 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 11 May 2026 10:36:07 -0400 Subject: [PATCH 6/9] chore(base): lint fixup + add note about auth app loading Signed-off-by: Josh --- lib/base.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/base.php b/lib/base.php index 77da801dda560..01dfa80d9f8d5 100644 --- a/lib/base.php +++ b/lib/base.php @@ -1091,7 +1091,7 @@ public static function handleRequest(): void { } $maintenance = $systemConfig->getValue('maintenance', false); - // Needed during maintenance mode and upgrades + // Needed during maintenance mode and upgrades $bypassMaintenance = str_ends_with($requestPath, '.js') || OC::$SUBURI === '/core/ajax/update.php'; // Show "maintenance in progress" page if Nextcloud is undergoing maintenance and not a bypass URL @@ -1122,9 +1122,6 @@ public static function handleRequest(): void { $appManager = Server::get(\OCP\App\IAppManager::class); - $appManager->loadApps(['authentication']); - $appManager->loadApps(['extended_authentication']); - $userSession = Server::get(IUserSession::class); $loggedIn = $userSession->isLoggedIn(); // Don't try to login when a client is trying to get a OAuth token. @@ -1139,6 +1136,7 @@ public static function handleRequest(): void { // Try normal login self::handleLogin($request); $loggedIn = $userSession->isLoggedIn(); + // More apps are available to logged in users self::loadRuntimeAppsForRequest($appManager, $loggedIn); } catch (DisabledUserException $e) { // Don’t prevent theming asset requests if user is merely disabled. @@ -1224,7 +1222,7 @@ private static function themingAssetRequest(string $requestPath): bool { || $requestPath === '/apps/theming/image/logoheader' || str_starts_with($requestPath, '/apps/theming/favicon') || str_starts_with($requestPath, '/apps/theming/icon') - ) { + ) { return true; } @@ -1236,6 +1234,7 @@ private static function themingAssetRequest(string $requestPath): bool { */ private static function loadRuntimeAppsForRequest(\OCP\App\IAppManager $appManager, bool $loggedIn): void { // Always load authentication apps + // Note: loadApps() is smart enough to skip any already loaded apps $appManager->loadApps(['authentication']); $appManager->loadApps(['extended_authentication']); if ($loggedIn) { From 5e3a042c9ec37b0d77f79b85ea174f85d661a65f Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 14 May 2026 09:47:37 -0400 Subject: [PATCH 7/9] docs(base): document real handleLogin contract/behavior The real contract is mostly side effects and possibly exceptions, which is important to have documented. Signed-off-by: Josh --- lib/base.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/base.php b/lib/base.php index 01dfa80d9f8d5..1e9f8cbac8b54 100644 --- a/lib/base.php +++ b/lib/base.php @@ -1249,8 +1249,21 @@ private static function loadRuntimeAppsForRequest(\OCP\App\IAppManager $appManag /** * Attempt to authenticate the current request using supported login methods. * - * Tries, in order: Apache auth, app API login, token login, cookie login, - * and basic auth. Federation requests are excluded. + * Tries, in order, Apache auth, App API auth, token auth, remembered-login + * cookies, and HTTP basic auth. On success, this updates the current user + * session as a side effect. Federation requests are skipped. + * + * Callers typically inspect the resulting session state afterward rather than + * relying on the return value alone. + * + * @return bool True if one of the supported login mechanisms authenticated the + * request; false if no session was established and no login + * exception was raised. + * + * @throws \OC\User\LoginException If an underlying login mechanism rejects or + * aborts the login flow. + * @throws \OC\User\DisabledUserException If authentication is rejected because + * the user account is disabled. */ public static function handleLogin(OCP\IRequest $request): bool { if ($request->getHeader('X-Nextcloud-Federation')) { From 96614f95a3cb774a4486602482a35e026c3ad193 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 14 May 2026 11:18:22 -0400 Subject: [PATCH 8/9] chore(base.php): ensure bypass gets correct apps + routing gets all apps Signed-off-by: Josh --- lib/base.php | 75 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/lib/base.php b/lib/base.php index 1e9f8cbac8b54..d4c65afa8d468 100644 --- a/lib/base.php +++ b/lib/base.php @@ -1090,7 +1090,8 @@ public static function handleRequest(): void { return; } - $maintenance = $systemConfig->getValue('maintenance', false); + $maintenance = (bool)$systemConfig->getValue('maintenance', false); + // Needed during maintenance mode and upgrades $bypassMaintenance = str_ends_with($requestPath, '.js') || OC::$SUBURI === '/core/ajax/update.php'; @@ -1103,7 +1104,7 @@ public static function handleRequest(): void { $upgrade = Util::needUpgrade(); // Show "upgrade" page if Nextcloud needs to be upgraded and not in maintenance mode (i.e. already in progress). - if ($upgrade) { + if ($upgrade && !$maintenance && !$bypassMaintenance) { if (function_exists('opcache_reset')) { opcache_reset(); } @@ -1115,29 +1116,37 @@ public static function handleRequest(): void { } // - // At this point the request is either: - // - a regular request (a logged in user doing something or a non-logged in user trying to do something) - // - a special request that gets to bypass maintenance mode + // At this point the request has passed the install/maintenance/upgrade gates + // or is using a path that is allowed to bypass them. // $appManager = Server::get(\OCP\App\IAppManager::class); - $userSession = Server::get(IUserSession::class); $loggedIn = $userSession->isLoggedIn(); - // Don't try to login when a client is trying to get a OAuth token. + + self::loadAuthenticationApps($appManager); + + if ($loggedIn) { + self::loadAppsForAuthenticatedRequests($appManager); + } else { + self::loadAppsForPreAuthenticationPhase($appManager); + } + + // Don't try to log in when a client is trying to get an OAuth token. // OAuth needs to support basic auth too, so the login is not valid // inside Nextcloud and the Login exception would ruin it. $bypassLogin = $requestPath === '/apps/oauth2/api/v1/token'; - self::loadRuntimeAppsForRequest($appManager, $loggedIn); - if (!$loggedIn && !$bypassLogin) { try { // Try normal login self::handleLogin($request); $loggedIn = $userSession->isLoggedIn(); - // More apps are available to logged in users - self::loadRuntimeAppsForRequest($appManager, $loggedIn); + + // A successful login expands the app set needed during request handling. + if ($loggedIn) { + self::loadAppsForAuthenticatedRequests($appManager); + } } catch (DisabledUserException $e) { // Don’t prevent theming asset requests if user is merely disabled. if (!self::themingAssetRequest($requestPath)) { @@ -1146,11 +1155,14 @@ public static function handleRequest(): void { } } + // Ensure the full app set is loaded before routing. + self::loadAppsForRouting($appManager); + // Try to route the request. $router = Server::get(\OC\Route\Router::class); // Note: User may (or may still not) be logged in. try { - $router->match($request->getRawPathInfo()); + $router->match($requestPath); return; } catch (ResourceNotFoundException $e) { // ... @@ -1228,22 +1240,39 @@ private static function themingAssetRequest(string $requestPath): bool { return false; } - + /** - * Load minimum set of apps required to handle the request. + * Load authentication apps before the session-dependent phase of request handling. */ - private static function loadRuntimeAppsForRequest(\OCP\App\IAppManager $appManager, bool $loggedIn): void { + private static function loadAuthenticationApps(\OCP\App\IAppManager $appManager): void { // Always load authentication apps - // Note: loadApps() is smart enough to skip any already loaded apps $appManager->loadApps(['authentication']); $appManager->loadApps(['extended_authentication']); - if ($loggedIn) { - // For logged-in users: Load everything - $appManager->loadApps(); - } else { - // For guests: Load only filesystem and logging - $appManager->loadApps(['filesystem', 'logging']); - } + } + + /** + * Load the baseline runtime apps needed before authentication has succeeded. + */ + private static function loadAppsForPreAuthenticationPhase(\OCP\App\IAppManager $appManager): void { + $appManager->loadApps(['filesystem', 'logging']); + } + + /** + * Load the full app set needed for authenticated requests. + */ + private static function loadAppsForAuthenticatedRequests(\OCP\App\IAppManager $appManager): void { + // Note: loadApps() is smart enough to skip any already loaded apps. + $appManager->loadApps(); + } + + /** + * Ensure the full app set is loaded before route matching so app routes and + * related runtime registrations are available. + */ + private static function loadAppsForRouting(\OCP\App\IAppManager $appManager): void { + // Preserve the historical routing-time load sequence. + $appManager->loadApps(['filesystem', 'logging']); + $appManager->loadApps(); } /** From 768b22a31fa8a51d1ff78fd0d9d4d68359b141f5 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 14 May 2026 12:45:06 -0400 Subject: [PATCH 9/9] chore(base.php): fixup for lint/cs Signed-off-by: Josh --- lib/base.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/base.php b/lib/base.php index d4c65afa8d468..19d4a60eaa8fb 100644 --- a/lib/base.php +++ b/lib/base.php @@ -1240,7 +1240,7 @@ private static function themingAssetRequest(string $requestPath): bool { return false; } - + /** * Load authentication apps before the session-dependent phase of request handling. */