From 261774910a9f48d56baa9593e08e1a159efde395 Mon Sep 17 00:00:00 2001 From: Choraimy Kroonstuiver <3661474+axlon@users.noreply.github.com> Date: Mon, 1 Apr 2024 15:40:39 +0200 Subject: [PATCH] [11.x] Fix `Middleware::trustHosts(subdomains: true)` (#50877) * Fix usage of config before its resolved * Allow trusting hosts via a callback * Remove unused import * Update TrustHosts.php --------- Co-authored-by: Taylor Otwell --- .../Foundation/Configuration/Middleware.php | 6 +-- src/Illuminate/Http/Middleware/TrustHosts.php | 39 +++++++++++++------ .../Configuration/MiddlewareTest.php | 15 ++++--- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/Illuminate/Foundation/Configuration/Middleware.php b/src/Illuminate/Foundation/Configuration/Middleware.php index e8916d552d44..cf58263d830a 100644 --- a/src/Illuminate/Foundation/Configuration/Middleware.php +++ b/src/Illuminate/Foundation/Configuration/Middleware.php @@ -608,15 +608,15 @@ public function trimStrings(array $except = []) /** * Indicate that the trusted host middleware should be enabled. * - * @param array|null $at + * @param array|(callable(): array)|null $at * @param bool $subdomains * @return $this */ - public function trustHosts(array $at = null, bool $subdomains = true) + public function trustHosts(array|callable $at = null, bool $subdomains = true) { $this->trustHosts = true; - if (is_array($at)) { + if (! is_null($at)) { TrustHosts::at($at, $subdomains); } diff --git a/src/Illuminate/Http/Middleware/TrustHosts.php b/src/Illuminate/Http/Middleware/TrustHosts.php index 13dd1f00b62c..8eae16d1cec0 100644 --- a/src/Illuminate/Http/Middleware/TrustHosts.php +++ b/src/Illuminate/Http/Middleware/TrustHosts.php @@ -17,10 +17,17 @@ class TrustHosts /** * The trusted hosts that have been configured to always be trusted. * - * @var array|null + * @var array|(callable(): array)|null */ protected static $alwaysTrust; + /** + * Indicates whether subdomains of the application URL should be trusted. + * + * @var bool|null + */ + protected static $subdomains; + /** * Create a new middleware instance. * @@ -39,9 +46,21 @@ public function __construct(Application $app) */ public function hosts() { - return is_array(static::$alwaysTrust) - ? static::$alwaysTrust - : [$this->allSubdomainsOfApplicationUrl()]; + if (is_null(static::$alwaysTrust)) { + return [$this->allSubdomainsOfApplicationUrl()]; + } + + $hosts = match (true) { + is_array(static::$alwaysTrust) => static::$alwaysTrust, + is_callable(static::$alwaysTrust) => call_user_func(static::$alwaysTrust), + default => [], + }; + + if (static::$subdomains) { + $hosts[] = $this->allSubdomainsOfApplicationUrl(); + } + + return $hosts; } /** @@ -63,19 +82,14 @@ public function handle(Request $request, $next) /** * Specify the hosts that should always be trusted. * - * @param array $hosts + * @param array|(callable(): array) $hosts * @param bool $subdomains * @return void */ - public static function at(array $hosts, bool $subdomains = true) + public static function at(array|callable $hosts, bool $subdomains = true) { - if ($subdomains) { - if ($host = parse_url(config('app.url'), PHP_URL_HOST)) { - $hosts[] = '^(.+\.)?'.preg_quote($host).'$'; - } - } - static::$alwaysTrust = $hosts; + static::$subdomains = $subdomains; } /** @@ -109,5 +123,6 @@ protected function allSubdomainsOfApplicationUrl() public static function flushState() { static::$alwaysTrust = null; + static::$subdomains = null; } } diff --git a/tests/Foundation/Configuration/MiddlewareTest.php b/tests/Foundation/Configuration/MiddlewareTest.php index 9012b4d5fa0c..8fde56c7a9c1 100644 --- a/tests/Foundation/Configuration/MiddlewareTest.php +++ b/tests/Foundation/Configuration/MiddlewareTest.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Foundation\Configuration; -use Illuminate\Config\Repository; use Illuminate\Container\Container; use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Foundation\Application; @@ -219,23 +218,29 @@ protected function allSubdomainsOfApplicationUrl() $configuration->trustHosts(); $this->assertEquals(['^(.+\.)?laravel\.test$'], $middleware->hosts()); - app()['config'] = Mockery::mock(Repository::class); - app()['config']->shouldReceive('get')->with('app.url', null)->times(3)->andReturn('http://laravel.test'); - $configuration->trustHosts(at: ['my.test']); $this->assertEquals(['my.test', '^(.+\.)?laravel\.test$'], $middleware->hosts()); - $configuration->trustHosts(at: ['my.test']); + $configuration->trustHosts(at: static fn () => ['my.test']); $this->assertEquals(['my.test', '^(.+\.)?laravel\.test$'], $middleware->hosts()); $configuration->trustHosts(at: ['my.test'], subdomains: false); $this->assertEquals(['my.test'], $middleware->hosts()); + $configuration->trustHosts(at: static fn () => ['my.test'], subdomains: false); + $this->assertEquals(['my.test'], $middleware->hosts()); + $configuration->trustHosts(at: []); $this->assertEquals(['^(.+\.)?laravel\.test$'], $middleware->hosts()); + $configuration->trustHosts(at: static fn () => []); + $this->assertEquals(['^(.+\.)?laravel\.test$'], $middleware->hosts()); + $configuration->trustHosts(at: [], subdomains: false); $this->assertEquals([], $middleware->hosts()); + + $configuration->trustHosts(at: static fn () => [], subdomains: false); + $this->assertEquals([], $middleware->hosts()); } public function testEncryptCookies()