withRouting( web: __DIR__.'/../routes/web.php', api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware): void { // The admin lives under /admin, so the framework's default "login" route // name does not exist here. $middleware->redirectGuestsTo(fn () => route('admin.login')); $middleware->redirectUsersTo(fn () => route('admin.overview')); // Bound new feature API bodies before global JSON input parsing. $middleware->prepend(FeatureRequestLimits::class); $middleware->prepend(MonitoringRequestLimits::class); $middleware->web(append: SecurityHeaders::class); $middleware->appendToGroup('web', UseLocale::class); $middleware->appendToGroup('web', CentralAdministration::class); // Invited with "two factor first": only the profile until it is on. $middleware->appendToGroup('web', RequireTwoFactorSetup::class); // Proxy trust is read by Laravel from config/trustedproxy.php after // environment/config loading, including when config is cached. // One-click unsubscribe is a POST from a mail provider's server, with // no session and no form. The signed URL is its credential. $middleware->validateCsrfTokens(except: ['unsubscribe/*', 'status/*/unsubscribe/*']); // The token check has to run before route-model binding, or a request // without a token gets a 404 that tells a stranger which ids exist. $middleware->prependToPriorityList(SubstituteBindings::class, ApiTokenAuth::class); $middleware->prependToPriorityList(ApiTokenAuth::class, ResolveStatusPage::class); $middleware->prependToPriorityList(ResolveStatusPage::class, UseLocale::class); $middleware->appendToPriorityList(ResolveStatusPage::class, EnsurePageCapability::class); }) ->withExceptions(function (Exceptions $exceptions): void { $exceptions->dontFlash(['setup_key', 'signal_token', 'telegram_token', 'url']); // A form posted after the session expired used to end on a bare "419 Page // Expired". Say what happened and put the person back at the door. $exceptions->render(function (TokenMismatchException $e, Request $request) { if ($request->expectsJson()) { return null; } return redirect()->route('admin.login')->with('status', 'Your session had expired, so that was not saved. Sign in and try again.'); }); $exceptions->shouldRenderJsonWhen( fn (Request $request) => $request->is('api/*') || $request->expectsJson(), ); })->create(); // Web installs keep the application outside a fixed hosting document root. $marker = dirname(__DIR__).'/.pharos-public'; if (is_file($marker) && ($public = realpath(trim(file_get_contents($marker)))) && is_dir($public)) { $app->usePublicPath($public); } return $app;