diff --git a/src/DependencyInjection/services.php b/src/DependencyInjection/services.php index 3287727..41213d8 100644 --- a/src/DependencyInjection/services.php +++ b/src/DependencyInjection/services.php @@ -13,6 +13,7 @@ use Freddie\Hub\Hub; use Freddie\Hub\HubControllerInterface; use Freddie\Hub\HubInterface; +use Freddie\Hub\Middleware\CorsMiddleware; use Freddie\Hub\Middleware\HttpExceptionConverterMiddleware; use Freddie\Hub\Middleware\TokenExtractorMiddleware; use Freddie\Hub\Transport\TransportFactory; @@ -111,6 +112,7 @@ $services ->set(App::class) ->args([ + service(CorsMiddleware::class), service(HttpExceptionConverterMiddleware::class), service(TokenExtractorMiddleware::class), ]); @@ -124,6 +126,12 @@ $services ->set(Factory::class); + $services + ->set(CorsMiddleware::class) + ->args([ + param('env(string:default::CORS_ORIGINS)') + ]); + $services ->set(Configuration::class) ->factory(service(ConfigurationFactory::class)) diff --git a/src/Hub/Middleware/CorsMiddleware.php b/src/Hub/Middleware/CorsMiddleware.php new file mode 100644 index 0000000..05cf984 --- /dev/null +++ b/src/Hub/Middleware/CorsMiddleware.php @@ -0,0 +1,35 @@ +corsOrigin ?? $this->getOrigin($request); + + return $response->withAddedHeader('Access-Control-Allow-Origin', $corsOrigin) + ->withAddedHeader('Access-Control-Allow-Headers', '*') + ->withAddedHeader('Access-Control-Allow-Methods', '*') + ->withAddedHeader('Access-Control-Allow-Credentials', 'true') + ->withStatus(Response::STATUS_OK); + } + + private function getOrigin(ServerRequestInterface $request): string + { + return $request->getHeaderLine('Origin') ?: 'null'; + } +} diff --git a/tests/Unit/Hub/Middleware/CorsMiddlewareTest.php b/tests/Unit/Hub/Middleware/CorsMiddlewareTest.php new file mode 100644 index 0000000..9e8c1d2 --- /dev/null +++ b/tests/Unit/Hub/Middleware/CorsMiddlewareTest.php @@ -0,0 +1,48 @@ + $expectedResponse); + $request = new ServerRequest('POST', './well-known/mercure'); + + // When + $response = handle($app, $request); + + // Then + expect($response->getHeaderLine('Access-Control-Allow-Origin'))->toBe($corsOrigins) + ->and($response->getHeaderLine('Access-Control-Allow-Methods'))->toBe('*') + ->and($response->getHeaderLine('Access-Control-Allow-Headers'))->toBe('*') + ->and($response->getHeaderLine('Access-Control-Allow-Credentials'))->toBe('true'); +}); + +it('decorates response with CORS mechanism with default corsOrigin setup', function () { + // Given + $corsOrigins = null; + $expectedResponse = new Response(400); + $app = new App(new CorsMiddleware($corsOrigins), fn () => $expectedResponse); + $request = new ServerRequest('POST', './well-known/mercure'); + + // When + $response = handle($app, $request); + + // Then + expect($response->getHeaderLine('Access-Control-Allow-Origin'))->toBe('null') + ->and($response->getHeaderLine('Access-Control-Allow-Methods'))->toBe('*') + ->and($response->getHeaderLine('Access-Control-Allow-Headers'))->toBe('*') + ->and($response->getHeaderLine('Access-Control-Allow-Credentials'))->toBe('true'); +});