diff --git a/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php b/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php index 18589cb..6799589 100644 --- a/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php +++ b/src/Http/Middleware/EnsureFrontendRequestsAreStateful.php @@ -3,9 +3,6 @@ namespace Laravel\Sanctum\Http\Middleware; use Illuminate\Routing\Pipeline; -use Illuminate\Support\Collection; -use Illuminate\Support\Str; -use Laravel\Sanctum\Sanctum; class EnsureFrontendRequestsAreStateful { @@ -20,11 +17,16 @@ public function handle($request, $next) { $this->configureSecureCookieSessions(); - return (new Pipeline(app()))->send($request)->through( - static::fromFrontend($request) ? $this->frontendMiddleware() : [] - )->then(function ($request) use ($next) { - return $next($request); - }); + $middleware = FrontendRequestChecker::isFromFrontend($request) + ? $this->frontendMiddleware() + : []; + + return (new Pipeline(app())) + ->send($request) + ->through($middleware) + ->then(function ($request) use ($next) { + return $next($request); + }); } /** @@ -63,31 +65,4 @@ protected function frontendMiddleware() return $middleware; } - - /** - * Determine if the given request is from the first-party application frontend. - * - * @param \Illuminate\Http\Request $request - * @return bool - */ - public static function fromFrontend($request) - { - $domain = $request->headers->get('referer') ?: $request->headers->get('origin'); - - if (is_null($domain)) { - return false; - } - - $domain = Str::replaceFirst('https://', '', $domain); - $domain = Str::replaceFirst('http://', '', $domain); - $domain = Str::endsWith($domain, '/') ? $domain : "{$domain}/"; - - $stateful = array_filter(config('sanctum.stateful', [])); - - return Str::is(Collection::make($stateful)->map(function ($uri) use ($request) { - $uri = $uri === Sanctum::$currentRequestHostPlaceholder ? $request->getHttpHost() : $uri; - - return trim($uri).'/*'; - })->all(), $domain); - } } diff --git a/src/Http/Middleware/FrontendRequestChecker.php b/src/Http/Middleware/FrontendRequestChecker.php new file mode 100644 index 0000000..5aee917 --- /dev/null +++ b/src/Http/Middleware/FrontendRequestChecker.php @@ -0,0 +1,69 @@ +headers->get('referer') ?: $request->headers->get('origin'); + + if (is_null($domain)) { + return null; + } + + $domain = Str::of($domain)->after('://')->finish('/'); + + return (string) $domain; + } + + /** + * Get the stateful domain patterns. + * + * @param array $stateful + * @param \Illuminate\Http\Request $request + * @return array + */ + private static function getStatefulDomainPatterns(array $stateful, Request $request): array + { + return Collection::make($stateful)->map(function ($uri) use ($request) { + if ($uri === Sanctum::$currentRequestHostPlaceholder) { + return trim($request->getHttpHost()).'/*'; + } + + return trim($uri).'/*'; + })->all(); + } +} diff --git a/tests/Feature/DefaultConfigContainsAppUrlTest.php b/tests/Feature/DefaultConfigContainsAppUrlTest.php index 0bb6f60..dcd858b 100644 --- a/tests/Feature/DefaultConfigContainsAppUrlTest.php +++ b/tests/Feature/DefaultConfigContainsAppUrlTest.php @@ -3,7 +3,7 @@ namespace Laravel\Sanctum\Tests\Feature; use Illuminate\Http\Request; -use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful; +use Laravel\Sanctum\Http\Middleware\FrontendRequestChecker; use Orchestra\Testbench\Concerns\WithWorkbench; use Orchestra\Testbench\TestCase; @@ -52,6 +52,6 @@ public function test_request_from_app_url_is_stateful_with_default_config() $request->headers->set('referer', config('app.url')); - $this->assertTrue(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertTrue(FrontendRequestChecker::isFromFrontend($request)); } } diff --git a/tests/Feature/EnsureFrontendRequestsAreStatefulTest.php b/tests/Feature/EnsureFrontendRequestsAreStatefulTest.php index 311724e..1a3de42 100644 --- a/tests/Feature/EnsureFrontendRequestsAreStatefulTest.php +++ b/tests/Feature/EnsureFrontendRequestsAreStatefulTest.php @@ -3,7 +3,7 @@ namespace Laravel\Sanctum\Tests\Feature; use Illuminate\Http\Request; -use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful; +use Laravel\Sanctum\Http\Middleware\FrontendRequestChecker; use Laravel\Sanctum\Sanctum; use Orchestra\Testbench\Concerns\WithWorkbench; use Orchestra\Testbench\TestCase; @@ -22,22 +22,22 @@ public function test_request_referer_is_parsed_against_configuration() $request = Request::create('/'); $request->headers->set('referer', 'https://test.com'); - $this->assertTrue(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertTrue(FrontendRequestChecker::isFromFrontend($request)); $request = Request::create('/'); $request->headers->set('referer', 'https://wrong.com'); - $this->assertFalse(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertFalse(FrontendRequestChecker::isFromFrontend($request)); $request = Request::create('/'); $request->headers->set('referer', 'https://test.com.x'); - $this->assertFalse(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertFalse(FrontendRequestChecker::isFromFrontend($request)); $request = Request::create('/'); $request->headers->set('referer', 'https://foobar.test.com/'); - $this->assertTrue(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertTrue(FrontendRequestChecker::isFromFrontend($request)); } public function test_request_origin_fallback() @@ -45,19 +45,19 @@ public function test_request_origin_fallback() $request = Request::create('/'); $request->headers->set('origin', 'test.com'); - $this->assertTrue(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertTrue(FrontendRequestChecker::isFromFrontend($request)); $request = Request::create('/'); $request->headers->set('referer', null); $request->headers->set('origin', 'test.com'); - $this->assertTrue(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertTrue(FrontendRequestChecker::isFromFrontend($request)); $request = Request::create('/'); $request->headers->set('referer', ''); $request->headers->set('origin', 'test.com'); - $this->assertTrue(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertTrue(FrontendRequestChecker::isFromFrontend($request)); } public function test_same_domain_stateful() @@ -66,10 +66,10 @@ public function test_same_domain_stateful() $request->headers->set('origin', 'app-domain.com'); config(['sanctum.stateful' => []]); - $this->assertFalse(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertFalse(FrontendRequestChecker::isFromFrontend($request)); config(['sanctum.stateful' => [Sanctum::$currentRequestHostPlaceholder]]); - $this->assertTrue(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertTrue(FrontendRequestChecker::isFromFrontend($request)); } public function test_wildcard_matching() @@ -77,7 +77,7 @@ public function test_wildcard_matching() $request = Request::create('/'); $request->headers->set('referer', 'https://foo.test.com'); - $this->assertTrue(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertTrue(FrontendRequestChecker::isFromFrontend($request)); } public function test_requests_are_not_stateful_without_referer() @@ -86,6 +86,6 @@ public function test_requests_are_not_stateful_without_referer() $request = Request::create('/'); - $this->assertFalse(EnsureFrontendRequestsAreStateful::fromFrontend($request)); + $this->assertFalse(FrontendRequestChecker::isFromFrontend($request)); } }