97 lines
3.3 KiB
PHP
97 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Grav\Plugin\Api\Middleware;
|
|
|
|
use Grav\Common\Config\Config;
|
|
use Grav\Framework\Psr7\Response;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
|
|
class CorsMiddleware
|
|
{
|
|
public function __construct(
|
|
protected readonly Config $config,
|
|
) {}
|
|
|
|
public function processRequest(ServerRequestInterface $request): ServerRequestInterface
|
|
{
|
|
// Nothing to modify on the request, CORS is response-side
|
|
return $request;
|
|
}
|
|
|
|
public function addHeaders(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
|
|
{
|
|
if (!$this->config->get('plugins.api.cors.enabled', true)) {
|
|
return $response;
|
|
}
|
|
|
|
$origin = $request->getHeaderLine('Origin');
|
|
if (!$origin) {
|
|
return $response;
|
|
}
|
|
|
|
$allowedOrigins = (array) $this->config->get('plugins.api.cors.origins', ['*']);
|
|
|
|
if (in_array('*', $allowedOrigins, true)) {
|
|
$response = $response->withHeader('Access-Control-Allow-Origin', '*');
|
|
} elseif (in_array($origin, $allowedOrigins, true)) {
|
|
$response = $response
|
|
->withHeader('Access-Control-Allow-Origin', $origin)
|
|
->withHeader('Vary', 'Origin');
|
|
} else {
|
|
return $response;
|
|
}
|
|
|
|
$credentials = $this->config->get('plugins.api.cors.credentials', false);
|
|
if ($credentials) {
|
|
$response = $response->withHeader('Access-Control-Allow-Credentials', 'true');
|
|
}
|
|
|
|
$exposeHeaders = (array) $this->config->get('plugins.api.cors.expose_headers', []);
|
|
// Always expose X-Invalidates so the client can read cache invalidation tags
|
|
if (!in_array('X-Invalidates', $exposeHeaders)) {
|
|
$exposeHeaders[] = 'X-Invalidates';
|
|
}
|
|
$response = $response->withHeader('Access-Control-Expose-Headers', implode(', ', $exposeHeaders));
|
|
|
|
return $response;
|
|
}
|
|
|
|
public function createPreflightResponse(): ResponseInterface
|
|
{
|
|
$headers = [];
|
|
|
|
$allowedOrigins = (array) $this->config->get('plugins.api.cors.origins', ['*']);
|
|
$origin = $_SERVER['HTTP_ORIGIN'] ?? '*';
|
|
|
|
if (in_array('*', $allowedOrigins, true)) {
|
|
$headers['Access-Control-Allow-Origin'] = '*';
|
|
} elseif (in_array($origin, $allowedOrigins, true)) {
|
|
$headers['Access-Control-Allow-Origin'] = $origin;
|
|
$headers['Vary'] = 'Origin';
|
|
}
|
|
|
|
$methods = (array) $this->config->get('plugins.api.cors.methods', ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS']);
|
|
$headers['Access-Control-Allow-Methods'] = implode(', ', $methods);
|
|
|
|
$allowHeaders = (array) $this->config->get('plugins.api.cors.headers', []);
|
|
if ($allowHeaders) {
|
|
$headers['Access-Control-Allow-Headers'] = implode(', ', $allowHeaders);
|
|
}
|
|
|
|
$maxAge = $this->config->get('plugins.api.cors.max_age', 86400);
|
|
$headers['Access-Control-Max-Age'] = (string) $maxAge;
|
|
|
|
$credentials = $this->config->get('plugins.api.cors.credentials', false);
|
|
if ($credentials) {
|
|
$headers['Access-Control-Allow-Credentials'] = 'true';
|
|
}
|
|
|
|
$headers['Content-Length'] = '0';
|
|
|
|
return new Response(204, $headers);
|
|
}
|
|
}
|