diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index b20f9475..fad5f597 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -6,7 +6,10 @@ namespace App\Exceptions; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Throwable; class Handler extends ExceptionHandler @@ -30,6 +33,29 @@ class Handler extends ExceptionHandler $this->reportable(function (Throwable $e): void { // }); + + // A request on an untrusted host (see App\Http\Middleware\TrustHosts) + // otherwise renders as a bare "Bad request." 400. Show a message that + // says how to fix it instead. The framework has already converted the + // SuspiciousOperationException into a BadRequestHttpException by the time + // renderables run, so we match that and inspect the original. + $this->renderable(function (BadRequestHttpException $e, Request $request): ?Response { + $previous = $e->getPrevious(); + + if (! $previous instanceof SuspiciousOperationException + || ! str_starts_with($previous->getMessage(), 'Untrusted Host')) { + return null; // any other bad request keeps the default response + } + + $message = 'This hostname is not configured for this instance. ' + .'Set APP_URL, or add the host to TRUSTED_HOSTS.'; + + if ($request->expectsJson()) { + return response()->json(['message' => $message], 400); + } + + return response()->view('errors.untrusted-host', ['message' => $message], 400); + }); } public function render($request, Throwable $e): Response|RedirectResponse diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 029aacad..7ffd7f2f 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -48,8 +48,8 @@ class Kernel extends HttpKernel */ protected $middleware = [ ForceHttps::class, - TrustProxies::class, TrustHosts::class, + TrustProxies::class, HandleCors::class, PreventRequestsDuringMaintenance::class, ValidatePostSize::class, diff --git a/resources/views/errors/untrusted-host.blade.php b/resources/views/errors/untrusted-host.blade.php new file mode 100644 index 00000000..2da2cfde --- /dev/null +++ b/resources/views/errors/untrusted-host.blade.php @@ -0,0 +1,49 @@ +{{-- Self-contained on purpose: this page is rendered for a request on an + untrusted host, so it must not call url()/route()/asset(), which would + re-trigger Host validation and throw again. --}} + + +
+ + +
+ This hostname is not configured for this instance. Set
+ APP_URL, or add the host to TRUSTED_HOSTS.
+