init
This commit is contained in:
110
backend/vendor/nelmio/cors-bundle/CHANGELOG.md
vendored
Normal file
110
backend/vendor/nelmio/cors-bundle/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
Newer changelog entries can be found in the [GitHub Releases](https://github.com/nelmio/NelmioCorsBundle/releases)
|
||||
|
||||
### 2.3.0 (2023-02-15)
|
||||
|
||||
* Downgraded `CacheableResponseVaryListener`'s priority from 0 to -10 to ensure it runs after FrameworkExtraBundle listeners have set their cache headers (#179)
|
||||
* Added optional logging support if you inject a Logger into the CorsListener you can get debug info about the whole CORS decision process (#173)
|
||||
* Added support for setting `expose_headers` to a wildcard `'*'` which exposes all headers, this works as long as allow_credentials is not enabled as per the spec (#132)
|
||||
* Added `skip_same_as_origin` flag (default to true which is the old behavior) to allow opting out of skipping the CORS headers in the response if the Origin matches the application's hostname (#178)
|
||||
* Fixed ProviderMock having an invalid return type (#169)
|
||||
* Dropped support for Symfony 4.3 and 5.0 to 5.3
|
||||
|
||||
### 2.2.0 (2021-12-01)
|
||||
|
||||
* Added support for Symfony 6
|
||||
|
||||
### 2.1.1 (2021-04-20)
|
||||
|
||||
* Fixed response for unauthorized headers containing a reflected XSS (https://github.com/nelmio/NelmioCorsBundle/pull/163)
|
||||
|
||||
### 2.1.0 (2020-07-22)
|
||||
|
||||
* Added `Vary: Origin` header to cacheable responses to make sure proxies cache them correctly
|
||||
|
||||
### 2.0.1 (2019-11-15)
|
||||
|
||||
* Reverted CorsListener priority change as it was interfering with normal operations. The priority is back at 250.
|
||||
|
||||
### 2.0.0 (2019-11-12)
|
||||
|
||||
* BC Break: Downgraded CorsListener priority from 250 to 28, this should not affect anyone but could be a source in case of strange bugs
|
||||
* BC Break: Removed support for Symfony <4.3
|
||||
* BC Break: Removed support for PHP <7.1
|
||||
* Added support for Symfony 5
|
||||
* Added support for configuration via env vars
|
||||
* Changed the code to avoid mutating the EventDispatcher at runtime
|
||||
* Changed the code to avoid returning `Access-Control-Allow-Origin: null` headers to mark blocked requests
|
||||
|
||||
### 1.5.6 (2019-06-17)
|
||||
|
||||
* Fixed preflight request handler hijacking regular non-CORS OPTIONS requests.
|
||||
|
||||
### 1.5.5 (2019-02-27)
|
||||
|
||||
* Compatibility with Symfony 4.1
|
||||
* Fixed preflight responses to always include `Origin` in the `Vary` HTTP header
|
||||
|
||||
### 1.5.4 (2017-12-11)
|
||||
|
||||
* Compatibility with Symfony 4
|
||||
|
||||
### 1.5.3 (2017-04-24)
|
||||
|
||||
* Fixed regression in 1.5.2
|
||||
|
||||
### 1.5.2 (2017-04-21)
|
||||
|
||||
* Fixed bundle initialization in case paths is empty
|
||||
|
||||
### 1.5.1 (2017-01-22)
|
||||
|
||||
* Fixed `forced_allow_origin_value` to always set the header regardless of CORS, so that requests can properly be cached even if they are not always accessed via CORS
|
||||
|
||||
### 1.5.0 (2016-12-30)
|
||||
|
||||
* Added an `forced_allow_origin_value` option to force the value that is returned, in case you cache responses and can not have the allowed origin automatically set to the Origin header
|
||||
* Fixed `Access-Control-Allow-Headers` being sent even when it was empty
|
||||
* Fixed listener priority down to 250 (This **may be BREAKING** depending on what you do with your own listeners, but should be fine in most cases, just watch out).
|
||||
|
||||
### 1.4.1 (2015-12-09)
|
||||
|
||||
* Fixed requirements to allow Symfony3
|
||||
|
||||
### 1.4.0 (2015-01-13)
|
||||
|
||||
* Added an `origin_regex` option to allow defining origins based on regular expressions
|
||||
|
||||
### 1.3.3 (2014-12-10)
|
||||
|
||||
* Fixed a security regression in 1.3.2 that allowed GET requests to be executed from any domain
|
||||
|
||||
### 1.3.2 (2014-09-18)
|
||||
|
||||
* Removed 403 responses on non-OPTIONS requests that have an invalid origin header
|
||||
|
||||
### 1.3.1 (2014-07-21)
|
||||
|
||||
* Fixed path key normalization to allow dashes in paths
|
||||
* Fixed HTTP method case folding to support clients that send non-uppercased method names
|
||||
|
||||
### 1.3.0 (2014-02-06)
|
||||
|
||||
* Added support for host-based configuration of the bundle
|
||||
|
||||
### 1.2.0 (2013-10-29)
|
||||
|
||||
* Bumped symfony dependency to 2.1.0+
|
||||
* Fixed invalid trigger of the CORS check when the Origin header is present on same-host requests
|
||||
* Fixed fatal error when `allow_methods` was not configured for a given path
|
||||
|
||||
### 1.1.1 (2013-08-14)
|
||||
|
||||
* Fixed issue when `allow_origin` is set to `*` and `allow_credentials` to `true`.
|
||||
|
||||
### 1.1.0 (2013-07-29)
|
||||
|
||||
* Added ability to set a wildcard on accept_headers
|
||||
|
||||
### 1.0.0 (2013-01-07)
|
||||
|
||||
* Initial release
|
||||
55
backend/vendor/nelmio/cors-bundle/DependencyInjection/Compiler/CorsConfigurationProviderPass.php
vendored
Normal file
55
backend/vendor/nelmio/cors-bundle/DependencyInjection/Compiler/CorsConfigurationProviderPass.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace Nelmio\CorsBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Compiler pass for the nelmio_cors.configuration.provider tag.
|
||||
*/
|
||||
class CorsConfigurationProviderPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('nelmio_cors.options_resolver')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$resolverDefinition = $container->getDefinition('nelmio_cors.options_resolver');
|
||||
|
||||
$optionsProvidersByPriority = [];
|
||||
foreach ($container->findTaggedServiceIds('nelmio_cors.options_provider') as $taggedServiceId => $tagAttributes) {
|
||||
foreach ($tagAttributes as $attribute) {
|
||||
$priority = isset($attribute['priority']) ? (int) $attribute['priority'] : 0;
|
||||
$optionsProvidersByPriority[$priority][] = new Reference($taggedServiceId);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($optionsProvidersByPriority) > 0) {
|
||||
$resolverDefinition->setArguments(
|
||||
[$this->sortProviders($optionsProvidersByPriority)]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a two-dimensions array of providers, indexed by priority, into a flat array of Reference objects
|
||||
* @param array<int, list<Reference>> $providersByPriority
|
||||
* @return Reference[]
|
||||
*/
|
||||
protected function sortProviders(array $providersByPriority): array
|
||||
{
|
||||
ksort($providersByPriority);
|
||||
|
||||
return call_user_func_array('array_merge', $providersByPriority);
|
||||
}
|
||||
}
|
||||
216
backend/vendor/nelmio/cors-bundle/DependencyInjection/Configuration.php
vendored
Normal file
216
backend/vendor/nelmio/cors-bundle/DependencyInjection/Configuration.php
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\CorsBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class Configuration implements ConfigurationInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getConfigTreeBuilder(): TreeBuilder
|
||||
{
|
||||
$treeBuilder = new TreeBuilder('nelmio_cors');
|
||||
|
||||
$rootNode = $treeBuilder->getRootNode();
|
||||
$rootNode
|
||||
->children()
|
||||
->arrayNode('defaults')
|
||||
->addDefaultsIfNotSet()
|
||||
->append($this->getAllowCredentials(true))
|
||||
->append($this->getAllowOrigin())
|
||||
->append($this->getAllowHeaders())
|
||||
->append($this->getAllowMethods())
|
||||
->append($this->getAllowPrivateNetwork(true))
|
||||
->append($this->getExposeHeaders())
|
||||
->append($this->getMaxAge())
|
||||
->append($this->getHosts())
|
||||
->append($this->getOriginRegex(true))
|
||||
->append($this->getForcedAllowOriginValue())
|
||||
->append($this->getSkipSameAsOrigin(true))
|
||||
->end()
|
||||
|
||||
->arrayNode('paths')
|
||||
->useAttributeAsKey('path')
|
||||
->normalizeKeys(false)
|
||||
->prototype('array')
|
||||
->append($this->getAllowCredentials())
|
||||
->append($this->getAllowOrigin())
|
||||
->append($this->getAllowHeaders())
|
||||
->append($this->getAllowMethods())
|
||||
->append($this->getAllowPrivateNetwork())
|
||||
->append($this->getExposeHeaders())
|
||||
->append($this->getMaxAge())
|
||||
->append($this->getHosts())
|
||||
->append($this->getOriginRegex())
|
||||
->append($this->getForcedAllowOriginValue())
|
||||
->append($this->getSkipSameAsOrigin())
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
|
||||
private function getSkipSameAsOrigin(bool $withDefaultValue = false): BooleanNodeDefinition
|
||||
{
|
||||
$node = new BooleanNodeDefinition('skip_same_as_origin');
|
||||
|
||||
if ($withDefaultValue) {
|
||||
$node->defaultTrue();
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getAllowCredentials(bool $withDefaultValue = false): BooleanNodeDefinition
|
||||
{
|
||||
$node = new BooleanNodeDefinition('allow_credentials');
|
||||
|
||||
if ($withDefaultValue) {
|
||||
$node->defaultFalse();
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getAllowOrigin(): ArrayNodeDefinition
|
||||
{
|
||||
$node = new ArrayNodeDefinition('allow_origin');
|
||||
|
||||
$node
|
||||
->beforeNormalization()
|
||||
->always(function ($v) {
|
||||
if ($v === '*') {
|
||||
return ['*'];
|
||||
}
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->prototype('scalar')->end()
|
||||
;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getAllowHeaders(): ArrayNodeDefinition
|
||||
{
|
||||
$node = new ArrayNodeDefinition('allow_headers');
|
||||
|
||||
$node
|
||||
->beforeNormalization()
|
||||
->always(function ($v) {
|
||||
if ($v === '*') {
|
||||
return ['*'];
|
||||
}
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->prototype('scalar')->end();
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getAllowMethods(): ArrayNodeDefinition
|
||||
{
|
||||
$node = new ArrayNodeDefinition('allow_methods');
|
||||
|
||||
$node->prototype('scalar')->end();
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getAllowPrivateNetwork(bool $withDefaultValue = false): BooleanNodeDefinition
|
||||
{
|
||||
$node = new BooleanNodeDefinition('allow_private_network');
|
||||
|
||||
if ($withDefaultValue) {
|
||||
$node->defaultFalse();
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getExposeHeaders(): ArrayNodeDefinition
|
||||
{
|
||||
$node = new ArrayNodeDefinition('expose_headers');
|
||||
|
||||
$node
|
||||
->beforeNormalization()
|
||||
->always(function ($v) {
|
||||
if ($v === '*') {
|
||||
return ['*'];
|
||||
}
|
||||
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->prototype('scalar')->end();
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getMaxAge(): ScalarNodeDefinition
|
||||
{
|
||||
$node = new ScalarNodeDefinition('max_age');
|
||||
|
||||
$node
|
||||
->defaultValue(0)
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
return !is_numeric($v);
|
||||
})
|
||||
->thenInvalid('max_age must be an integer (seconds)')
|
||||
->end()
|
||||
;
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getHosts(): ArrayNodeDefinition
|
||||
{
|
||||
$node = new ArrayNodeDefinition('hosts');
|
||||
|
||||
$node->prototype('scalar')->end();
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getOriginRegex(bool $withDefaultValue = false): BooleanNodeDefinition
|
||||
{
|
||||
$node = new BooleanNodeDefinition('origin_regex');
|
||||
|
||||
if ($withDefaultValue) {
|
||||
$node->defaultFalse();
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getForcedAllowOriginValue(): ScalarNodeDefinition
|
||||
{
|
||||
$node = new ScalarNodeDefinition('forced_allow_origin_value');
|
||||
$node->defaultNull();
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
||||
88
backend/vendor/nelmio/cors-bundle/DependencyInjection/NelmioCorsExtension.php
vendored
Normal file
88
backend/vendor/nelmio/cors-bundle/DependencyInjection/NelmioCorsExtension.php
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\CorsBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\Extension;
|
||||
use Symfony\Component\DependencyInjection\Loader;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class NelmioCorsExtension extends Extension
|
||||
{
|
||||
public const DEFAULTS = [
|
||||
'allow_origin' => [],
|
||||
'allow_credentials' => false,
|
||||
'allow_headers' => [],
|
||||
'allow_private_network' => false,
|
||||
'expose_headers' => [],
|
||||
'allow_methods' => [],
|
||||
'max_age' => 0,
|
||||
'hosts' => [],
|
||||
'origin_regex' => false,
|
||||
'skip_same_as_origin' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$defaults = array_merge(self::DEFAULTS, $config['defaults']);
|
||||
|
||||
if ($defaults['allow_credentials'] && in_array('*', $defaults['expose_headers'], true)) {
|
||||
throw new \UnexpectedValueException('nelmio_cors expose_headers cannot contain a wildcard (*) when allow_credentials is enabled.');
|
||||
}
|
||||
|
||||
// normalize array('*') to true
|
||||
if (in_array('*', $defaults['allow_origin'])) {
|
||||
$defaults['allow_origin'] = true;
|
||||
}
|
||||
if (in_array('*', $defaults['allow_headers'])) {
|
||||
$defaults['allow_headers'] = true;
|
||||
} else {
|
||||
$defaults['allow_headers'] = array_map('strtolower', $defaults['allow_headers']);
|
||||
}
|
||||
$defaults['allow_methods'] = array_map('strtoupper', $defaults['allow_methods']);
|
||||
|
||||
if ($config['paths']) {
|
||||
foreach ($config['paths'] as $path => $opts) {
|
||||
$opts = array_filter($opts);
|
||||
if (isset($opts['allow_origin']) && in_array('*', $opts['allow_origin'])) {
|
||||
$opts['allow_origin'] = true;
|
||||
}
|
||||
if (isset($opts['allow_headers']) && in_array('*', $opts['allow_headers'])) {
|
||||
$opts['allow_headers'] = true;
|
||||
} elseif (isset($opts['allow_headers'])) {
|
||||
$opts['allow_headers'] = array_map('strtolower', $opts['allow_headers']);
|
||||
}
|
||||
if (isset($opts['allow_methods'])) {
|
||||
$opts['allow_methods'] = array_map('strtoupper', $opts['allow_methods']);
|
||||
}
|
||||
|
||||
$config['paths'][$path] = $opts;
|
||||
}
|
||||
}
|
||||
|
||||
$container->setParameter('nelmio_cors.map', $config['paths']);
|
||||
$container->setParameter('nelmio_cors.defaults', $defaults);
|
||||
|
||||
$locator = new FileLocator(__DIR__.'/../Resources/config');
|
||||
$loader = new Loader\PhpFileLoader($container, $locator);
|
||||
$loader->load('services.php');
|
||||
}
|
||||
}
|
||||
24
backend/vendor/nelmio/cors-bundle/EventListener/CacheableResponseVaryListener.php
vendored
Normal file
24
backend/vendor/nelmio/cors-bundle/EventListener/CacheableResponseVaryListener.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Nelmio\CorsBundle\EventListener;
|
||||
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
|
||||
/**
|
||||
* When a response is cacheable the `Vary` header has to include `Origin`.
|
||||
*/
|
||||
final class CacheableResponseVaryListener
|
||||
{
|
||||
public function onResponse(ResponseEvent $event): void
|
||||
{
|
||||
$response = $event->getResponse();
|
||||
|
||||
if (!$response->isCacheable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!\in_array('Origin', $response->getVary(), true)) {
|
||||
$response->setVary(array_merge(['Origin'], $response->getVary()));
|
||||
}
|
||||
}
|
||||
}
|
||||
342
backend/vendor/nelmio/cors-bundle/EventListener/CorsListener.php
vendored
Normal file
342
backend/vendor/nelmio/cors-bundle/EventListener/CorsListener.php
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\CorsBundle\EventListener;
|
||||
|
||||
use Nelmio\CorsBundle\Options\ResolverInterface;
|
||||
use Nelmio\CorsBundle\Options\ProviderInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\NullLogger;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\Event\ResponseEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
/**
|
||||
* Adds CORS headers and handles pre-flight requests
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
* @phpstan-import-type CorsCompleteOptions from ProviderInterface
|
||||
*/
|
||||
class CorsListener
|
||||
{
|
||||
public const SHOULD_ALLOW_ORIGIN_ATTR = '_nelmio_cors_should_allow_origin';
|
||||
public const SHOULD_FORCE_ORIGIN_ATTR = '_nelmio_cors_should_force_origin';
|
||||
|
||||
/**
|
||||
* Simple headers as defined in the spec should always be accepted
|
||||
* @var list<string>
|
||||
* @deprecated
|
||||
*/
|
||||
protected static $simpleHeaders = self::SIMPLE_HEADERS;
|
||||
|
||||
protected const SIMPLE_HEADERS = [
|
||||
'accept',
|
||||
'accept-language',
|
||||
'content-language',
|
||||
'origin',
|
||||
];
|
||||
|
||||
/** @var ResolverInterface */
|
||||
protected $configurationResolver;
|
||||
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
public function __construct(ResolverInterface $configurationResolver, ?LoggerInterface $logger = null)
|
||||
{
|
||||
$this->configurationResolver = $configurationResolver;
|
||||
|
||||
if (null === $logger) {
|
||||
$logger = new NullLogger();
|
||||
}
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function onKernelRequest(RequestEvent $event): void
|
||||
{
|
||||
if (HttpKernelInterface::MAIN_REQUEST !== $event->getRequestType()) {
|
||||
$this->logger->debug('Not a master type request, skipping CORS checks.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
|
||||
// @phpstan-ignore booleanNot.alwaysFalse (an invalid overridden configuration resolver may not be trustworthy)
|
||||
if (!$options = $this->configurationResolver->getOptions($request)) {
|
||||
$this->logger->debug('Could not get options for request, skipping CORS checks.');
|
||||
return;
|
||||
}
|
||||
|
||||
// if the "forced_allow_origin_value" option is set, add a listener which will set or override the "Access-Control-Allow-Origin" header
|
||||
if (!empty($options['forced_allow_origin_value'])) {
|
||||
$this->logger->debug(sprintf(
|
||||
"The 'forced_allow_origin_value' option is set to '%s', adding a listener to set or override the 'Access-Control-Allow-Origin' header.",
|
||||
$options['forced_allow_origin_value']
|
||||
));
|
||||
|
||||
$request->attributes->set(self::SHOULD_FORCE_ORIGIN_ATTR, true);
|
||||
}
|
||||
|
||||
// skip if not a CORS request
|
||||
if (!$request->headers->has('Origin')) {
|
||||
$this->logger->debug("Request does not have 'Origin' header, skipping CORS.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($options['skip_same_as_origin'] && $request->headers->get('Origin') === $request->getSchemeAndHttpHost()) {
|
||||
$this->logger->debug("The 'Origin' header of the request equals the scheme and host the request was sent to, skipping CORS.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// perform preflight checks
|
||||
if ('OPTIONS' === $request->getMethod() &&
|
||||
($request->headers->has('Access-Control-Request-Method') ||
|
||||
$request->headers->has('Access-Control-Request-Private-Network'))
|
||||
) {
|
||||
$this->logger->debug("Request is a preflight check, setting event response now.");
|
||||
|
||||
$event->setResponse($this->getPreflightResponse($request, $options));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->checkOrigin($request, $options)) {
|
||||
$this->logger->debug("Origin check failed.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logger->debug("Origin is allowed, proceed with adding CORS response headers.");
|
||||
|
||||
$request->attributes->set(self::SHOULD_ALLOW_ORIGIN_ATTR, true);
|
||||
}
|
||||
|
||||
public function onKernelResponse(ResponseEvent $event): void
|
||||
{
|
||||
if (HttpKernelInterface::MAIN_REQUEST !== $event->getRequestType()) {
|
||||
$this->logger->debug("Not a master type request, skip adding CORS response headers.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $event->getRequest();
|
||||
|
||||
$shouldAllowOrigin = $request->attributes->getBoolean(self::SHOULD_ALLOW_ORIGIN_ATTR);
|
||||
$shouldForceOrigin = $request->attributes->getBoolean(self::SHOULD_FORCE_ORIGIN_ATTR);
|
||||
|
||||
if (!$shouldAllowOrigin && !$shouldForceOrigin) {
|
||||
$this->logger->debug("The origin should not be allowed and not be forced, skip adding CORS response headers.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// @phpstan-ignore booleanNot.alwaysFalse (an invalid overridden configuration resolver may not be trustworthy)
|
||||
if (!$options = $this->configurationResolver->getOptions($request)) {
|
||||
$this->logger->debug("Could not resolve options for request, skip adding CORS response headers.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($shouldAllowOrigin) {
|
||||
$response = $event->getResponse();
|
||||
// add CORS response headers
|
||||
$origin = $request->headers->get('Origin');
|
||||
|
||||
$this->logger->debug(sprintf("Setting 'Access-Control-Allow-Origin' response header to '%s'.", $origin));
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Origin', $origin);
|
||||
|
||||
if ($options['allow_credentials']) {
|
||||
$this->logger->debug("Setting 'Access-Control-Allow-Credentials' to 'true'.");
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Credentials', 'true');
|
||||
}
|
||||
if ($options['expose_headers']) {
|
||||
$headers = strtolower(implode(', ', $options['expose_headers']));
|
||||
|
||||
$this->logger->debug(sprintf("Setting 'Access-Control-Expose-Headers' response header to '%s'.", $headers));
|
||||
|
||||
$response->headers->set('Access-Control-Expose-Headers', $headers);
|
||||
}
|
||||
}
|
||||
|
||||
if ($shouldForceOrigin) {
|
||||
assert(isset($options['forced_allow_origin_value']));
|
||||
$this->logger->debug(sprintf("Setting 'Access-Control-Allow-Origin' response header to '%s'.", $options['forced_allow_origin_value']));
|
||||
|
||||
$event->getResponse()->headers->set('Access-Control-Allow-Origin', $options['forced_allow_origin_value']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param CorsCompleteOptions $options
|
||||
*/
|
||||
protected function getPreflightResponse(Request $request, array $options): Response
|
||||
{
|
||||
$response = new Response();
|
||||
$response->setVary(['Origin']);
|
||||
|
||||
if ($options['allow_credentials']) {
|
||||
$this->logger->debug("Setting 'Access-Control-Allow-Credentials' response header to 'true'.");
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Credentials', 'true');
|
||||
}
|
||||
if ($options['allow_methods']) {
|
||||
$methods = implode(', ', $options['allow_methods']);
|
||||
|
||||
$this->logger->debug(sprintf("Setting 'Access-Control-Allow-Methods' response header to '%s'.", $methods));
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Methods', $methods);
|
||||
}
|
||||
if ($options['allow_headers']) {
|
||||
$headers = $this->isWildcard($options, 'allow_headers')
|
||||
? $request->headers->get('Access-Control-Request-Headers')
|
||||
: implode(', ', $options['allow_headers']); // @phpstan-ignore argument.type (isWildcard guarantees this is an array but PHPStan does not know)
|
||||
|
||||
if ($headers) {
|
||||
$this->logger->debug(sprintf("Setting 'Access-Control-Allow-Headers' response header to '%s'.", $headers));
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Headers', $headers);
|
||||
}
|
||||
}
|
||||
if ($options['max_age']) {
|
||||
$this->logger->debug(sprintf("Setting 'Access-Control-Max-Age' response header to '%d'.", $options['max_age']));
|
||||
|
||||
$response->headers->set('Access-Control-Max-Age', (string) $options['max_age']);
|
||||
}
|
||||
|
||||
if (!$this->checkOrigin($request, $options)) {
|
||||
$this->logger->debug("Removing 'Access-Control-Allow-Origin' response header.");
|
||||
|
||||
$response->headers->remove('Access-Control-Allow-Origin');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$origin = $request->headers->get('Origin');
|
||||
|
||||
$this->logger->debug(sprintf("Setting 'Access-Control-Allow-Origin' response header to '%s'", $origin));
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Origin', $origin);
|
||||
|
||||
// check private network access
|
||||
if ($request->headers->has('Access-Control-Request-Private-Network')
|
||||
&& strtolower((string) $request->headers->get('Access-Control-Request-Private-Network')) === 'true'
|
||||
) {
|
||||
if ($options['allow_private_network']) {
|
||||
$this->logger->debug("Setting 'Access-Control-Allow-Private-Network' response header to 'true'.");
|
||||
|
||||
$response->headers->set('Access-Control-Allow-Private-Network', 'true');
|
||||
} else {
|
||||
$response->setStatusCode(400);
|
||||
$response->setContent('Private Network Access is not allowed.');
|
||||
}
|
||||
}
|
||||
|
||||
// check request method
|
||||
$method = strtoupper((string) $request->headers->get('Access-Control-Request-Method'));
|
||||
if (!in_array($method, $options['allow_methods'], true)) {
|
||||
$this->logger->debug(sprintf("Method '%s' is not allowed.", $method));
|
||||
|
||||
$response->setStatusCode(405);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* We have to allow the header in the case-set as we received it by the client.
|
||||
* Firefox f.e. sends the LINK method as "Link", and we have to allow it like this or the browser will deny the
|
||||
* request.
|
||||
*/
|
||||
if (!in_array($request->headers->get('Access-Control-Request-Method'), $options['allow_methods'], true)) {
|
||||
$options['allow_methods'][] = (string) $request->headers->get('Access-Control-Request-Method');
|
||||
$response->headers->set('Access-Control-Allow-Methods', implode(', ', $options['allow_methods']));
|
||||
}
|
||||
|
||||
// check request headers
|
||||
$headers = $request->headers->get('Access-Control-Request-Headers');
|
||||
if ($headers && !$this->isWildcard($options, 'allow_headers')) {
|
||||
$headers = strtolower(trim($headers));
|
||||
$splitHeaders = preg_split('{, *}', $headers);
|
||||
if (false === $splitHeaders) {
|
||||
throw new \RuntimeException('Failed splitting '.$headers);
|
||||
}
|
||||
foreach ($splitHeaders as $header) {
|
||||
if (in_array($header, self::SIMPLE_HEADERS, true)) {
|
||||
continue;
|
||||
}
|
||||
if (!in_array($header, $options['allow_headers'], true)) { // @phpstan-ignore argument.type (isWildcard guarantees this is an array but PHPStan does not know)
|
||||
$sanitizedMessage = htmlentities('Unauthorized header '.$header, ENT_QUOTES, 'UTF-8');
|
||||
$response->setStatusCode(400);
|
||||
$response->setContent($sanitizedMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CorsCompleteOptions $options
|
||||
*/
|
||||
protected function checkOrigin(Request $request, array $options): bool
|
||||
{
|
||||
// check origin
|
||||
$origin = (string) $request->headers->get('Origin');
|
||||
|
||||
if ($this->isWildcard($options, 'allow_origin')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($options['origin_regex'] === true) {
|
||||
// origin regex matching
|
||||
foreach ($options['allow_origin'] as $originRegexp) { // @phpstan-ignore foreach.nonIterable (isWildcard guarantees this is an array but PHPStan does not know)
|
||||
$this->logger->debug(sprintf("Matching origin regex '%s' to origin '%s'.", $originRegexp, $origin));
|
||||
|
||||
if (preg_match('{'.$originRegexp.'}i', $origin)) {
|
||||
$this->logger->debug(sprintf("Origin regex '%s' matches origin '%s'.", $originRegexp, $origin));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// old origin matching
|
||||
if (in_array($origin, $options['allow_origin'], true)) { // @phpstan-ignore argument.type (isWildcard guarantees this is an array but PHPStan does not know)
|
||||
$this->logger->debug(sprintf("Origin '%s' is allowed.", $origin));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->debug(sprintf("Origin '%s' is not allowed.", $origin));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param CorsCompleteOptions $options
|
||||
* @phpstan-param key-of<CorsCompleteOptions> $option
|
||||
*/
|
||||
private function isWildcard(array $options, string $option): bool
|
||||
{
|
||||
$result = $options[$option] === true || (is_array($options[$option]) && in_array('*', $options[$option], true));
|
||||
|
||||
$this->logger->debug(sprintf("Option '%s' is %s a wildcard.", $option, $result ? '' : 'not'));
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
19
backend/vendor/nelmio/cors-bundle/LICENSE
vendored
Normal file
19
backend/vendor/nelmio/cors-bundle/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2011 Nelmio
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
27
backend/vendor/nelmio/cors-bundle/NelmioCorsBundle.php
vendored
Normal file
27
backend/vendor/nelmio/cors-bundle/NelmioCorsBundle.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\CorsBundle;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class NelmioCorsBundle extends Bundle
|
||||
{
|
||||
public function build(ContainerBuilder $container): void
|
||||
{
|
||||
parent::build($container);
|
||||
$container->addCompilerPass(new DependencyInjection\Compiler\CorsConfigurationProviderPass());
|
||||
}
|
||||
}
|
||||
72
backend/vendor/nelmio/cors-bundle/Options/ConfigProvider.php
vendored
Normal file
72
backend/vendor/nelmio/cors-bundle/Options/ConfigProvider.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\CorsBundle\Options;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Nelmio\CorsBundle\DependencyInjection\NelmioCorsExtension;
|
||||
|
||||
/**
|
||||
* Default CORS configuration provider.
|
||||
*
|
||||
* Uses the bundle's semantic configuration.
|
||||
* Default settings are the lowest priority one, and can be relied upon.
|
||||
*
|
||||
* @phpstan-import-type CorsCompleteOptions from ProviderInterface
|
||||
* @phpstan-import-type CorsOptionsPerPath from ProviderInterface
|
||||
*/
|
||||
class ConfigProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var CorsOptionsPerPath
|
||||
*/
|
||||
protected $paths;
|
||||
/**
|
||||
* @var array<string, bool|array<string>|int>
|
||||
* @phpstan-var CorsCompleteOptions
|
||||
*/
|
||||
protected $defaults;
|
||||
|
||||
/**
|
||||
* @param CorsOptionsPerPath $paths
|
||||
* @param array<string, bool|array<string>|int> $defaults
|
||||
* @phpstan-param CorsCompleteOptions $defaults
|
||||
*/
|
||||
public function __construct(array $paths, ?array $defaults = null)
|
||||
{
|
||||
$this->defaults = $defaults === null ? NelmioCorsExtension::DEFAULTS : $defaults;
|
||||
$this->paths = $paths;
|
||||
}
|
||||
|
||||
public function getOptions(Request $request): array
|
||||
{
|
||||
$uri = $request->getPathInfo() ?: '/';
|
||||
foreach ($this->paths as $pathRegexp => $options) {
|
||||
if (preg_match('{'.$pathRegexp.'}i', $uri)) {
|
||||
$options = array_merge($this->defaults, $options);
|
||||
|
||||
// skip if the host is not matching
|
||||
if (count($options['hosts']) > 0) {
|
||||
foreach ($options['hosts'] as $hostRegexp) {
|
||||
if (preg_match('{'.$hostRegexp.'}i', $request->getHost())) {
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->defaults;
|
||||
}
|
||||
}
|
||||
46
backend/vendor/nelmio/cors-bundle/Options/ProviderInterface.php
vendored
Normal file
46
backend/vendor/nelmio/cors-bundle/Options/ProviderInterface.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\CorsBundle\Options;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* CORS configuration provider interface.
|
||||
*
|
||||
* Can override CORS options for a particular path.
|
||||
*
|
||||
* @phpstan-type CorsOptions array{hosts?: list<string>, allow_credentials?: bool, allow_origin?: bool|list<string>, allow_headers?: bool|list<string>, allow_private_network?: bool, origin_regex?: bool, allow_methods?: list<string>, expose_headers?: list<string>, max_age?: int, forced_allow_origin_value?: string, skip_same_as_origin?: bool}
|
||||
* @phpstan-type CorsCompleteOptions array{hosts: list<string>, allow_credentials: bool, allow_origin: bool|list<string>, allow_headers: bool|list<string>, allow_private_network: bool, origin_regex: bool, allow_methods: list<string>, expose_headers: list<string>, max_age: int, forced_allow_origin_value?: string, skip_same_as_origin: bool}
|
||||
* @phpstan-type CorsOptionsPerPath array<string, CorsOptions>
|
||||
*/
|
||||
interface ProviderInterface
|
||||
{
|
||||
/**
|
||||
* Returns CORS options for $request.
|
||||
*
|
||||
* Any valid CORS option will overwrite those of the previous ones.
|
||||
* The method must at least return an empty array.
|
||||
*
|
||||
* All keys of the bundle's semantical configuration are valid:
|
||||
* - bool allow_credentials
|
||||
* - bool allow_origin
|
||||
* - bool allow_headers
|
||||
* - bool allow_private_network
|
||||
* - bool origin_regex
|
||||
* - array allow_methods
|
||||
* - array expose_headers
|
||||
* - int max_age
|
||||
*
|
||||
* @return array<string, bool|array<string>|int> CORS options
|
||||
* @phpstan-return CorsOptions
|
||||
*/
|
||||
public function getOptions(Request $request): array;
|
||||
}
|
||||
48
backend/vendor/nelmio/cors-bundle/Options/Resolver.php
vendored
Normal file
48
backend/vendor/nelmio/cors-bundle/Options/Resolver.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace Nelmio\CorsBundle\Options;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* CORS options resolver.
|
||||
*
|
||||
* Uses Cors providers to resolve options for an HTTP request
|
||||
*/
|
||||
class Resolver implements ResolverInterface
|
||||
{
|
||||
/**
|
||||
* CORS configuration providers, indexed by numerical priority
|
||||
* @var list<ProviderInterface>
|
||||
*/
|
||||
private $providers;
|
||||
|
||||
/**
|
||||
* @param list<ProviderInterface> $providers
|
||||
*/
|
||||
public function __construct(array $providers = [])
|
||||
{
|
||||
$this->providers = $providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the options for $request based on {@see $providers} data
|
||||
*/
|
||||
public function getOptions(Request $request): array
|
||||
{
|
||||
$options = [];
|
||||
foreach ($this->providers as $provider) {
|
||||
$options[] = $provider->getOptions($request);
|
||||
}
|
||||
|
||||
// @phpstan-ignore return.type (the default ConfigProvider will ensure default array is always setting every key)
|
||||
return array_merge(...$options);
|
||||
}
|
||||
}
|
||||
27
backend/vendor/nelmio/cors-bundle/Options/ResolverInterface.php
vendored
Normal file
27
backend/vendor/nelmio/cors-bundle/Options/ResolverInterface.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Nelmio\CorsBundle\Options;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type CorsCompleteOptions from ProviderInterface
|
||||
*/
|
||||
interface ResolverInterface
|
||||
{
|
||||
/**
|
||||
* Returns CORS options for a request's path
|
||||
*
|
||||
* @return array<string, bool|array<string>|int> CORS options
|
||||
* @phpstan-return CorsCompleteOptions
|
||||
*/
|
||||
public function getOptions(Request $request): array;
|
||||
}
|
||||
37
backend/vendor/nelmio/cors-bundle/README.md
vendored
Normal file
37
backend/vendor/nelmio/cors-bundle/README.md
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# NelmioCorsBundle
|
||||
|
||||
## About
|
||||
|
||||
The NelmioCorsBundle allows you to send [Cross-Origin Resource Sharing](http://enable-cors.org/)
|
||||
headers with ACL-style per-URL configuration.
|
||||
|
||||
## Features
|
||||
|
||||
* Handles CORS preflight OPTIONS requests
|
||||
* Adds CORS headers to your responses
|
||||
* Configured at the PHP/application level. This is convenient but it also means
|
||||
that any request serving static files and not going through Symfony will not
|
||||
have the CORS headers added, so if you need to serve CORS for static files you
|
||||
probably should rather configure these headers in your web server
|
||||
|
||||
## Installation
|
||||
|
||||
Require the `nelmio/cors-bundle` package in your composer.json and update your dependencies:
|
||||
|
||||
```bash
|
||||
composer require nelmio/cors-bundle
|
||||
```
|
||||
|
||||
The bundle should be automatically enabled by [Symfony Flex][1]. If you don't use
|
||||
Flex, you'll need to enable it manually as explained [in the docs][2].
|
||||
|
||||
## Usage
|
||||
|
||||
See [the documentation][2] for usage instructions.
|
||||
|
||||
## License
|
||||
|
||||
Released under the MIT License, see LICENSE.
|
||||
|
||||
[1]: https://symfony.com/doc/current/setup/flex.html
|
||||
[2]: https://symfony.com/bundles/NelmioCorsBundle/current/index.html
|
||||
68
backend/vendor/nelmio/cors-bundle/Resources/config/services.php
vendored
Normal file
68
backend/vendor/nelmio/cors-bundle/Resources/config/services.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the NelmioCorsBundle.
|
||||
*
|
||||
* (c) Nelmio <hello@nelm.io>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Nelmio\CorsBundle\EventListener\CacheableResponseVaryListener;
|
||||
use Nelmio\CorsBundle\EventListener\CorsListener;
|
||||
use Nelmio\CorsBundle\Options\ConfigProvider;
|
||||
use Nelmio\CorsBundle\Options\Resolver;
|
||||
|
||||
return function (ContainerConfigurator $container): void {
|
||||
$parameters = $container->parameters();
|
||||
$parameters
|
||||
->set('nelmio_cors.cors_listener.class', CorsListener::class)
|
||||
->set('nelmio_cors.options_resolver.class', Resolver::class)
|
||||
->set('nelmio_cors.options_provider.config.class', ConfigProvider::class)
|
||||
;
|
||||
|
||||
$services = $container->services();
|
||||
$services
|
||||
->set('nelmio_cors.cors_listener', param('nelmio_cors.cors_listener.class'))
|
||||
->args([
|
||||
service('nelmio_cors.options_resolver'),
|
||||
])
|
||||
->tag('kernel.event_listener', [
|
||||
'event' => 'kernel.request',
|
||||
'method' => 'onKernelRequest',
|
||||
'priority' => 250,
|
||||
])
|
||||
->tag('kernel.event_listener', [
|
||||
'event' => 'kernel.response',
|
||||
'method' => 'onKernelResponse',
|
||||
'priority' => 0,
|
||||
])
|
||||
;
|
||||
|
||||
$services
|
||||
->set('nelmio_cors.options_resolver', param('nelmio_cors.options_resolver.class'))
|
||||
;
|
||||
|
||||
$services
|
||||
->set('nelmio_cors.options_provider.config', param('nelmio_cors.options_provider.config.class'))
|
||||
->args([
|
||||
param('nelmio_cors.map'),
|
||||
param('nelmio_cors.defaults'),
|
||||
])
|
||||
->tag('nelmio_cors.options_provider', [
|
||||
'priority' => -1,
|
||||
])
|
||||
;
|
||||
|
||||
$services
|
||||
->set('nelmio_cors.cacheable_response_vary_listener', CacheableResponseVaryListener::class)
|
||||
->tag('kernel.event_listener', [
|
||||
'event' => 'kernel.response',
|
||||
'method' => 'onResponse',
|
||||
'priority' => -15,
|
||||
])
|
||||
;
|
||||
};
|
||||
164
backend/vendor/nelmio/cors-bundle/Resources/doc/index.rst
vendored
Normal file
164
backend/vendor/nelmio/cors-bundle/Resources/doc/index.rst
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
NelmioCorsBundle
|
||||
================
|
||||
|
||||
The NelmioCorsBundle allows you to send `Cross-Origin Resource Sharing`_
|
||||
headers with ACL-style per-URL configuration.
|
||||
|
||||
If you need it, check `this flow chart image`_ to have a global overview of
|
||||
entire CORS workflow.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Require the ``nelmio/cors-bundle`` package in your composer.json and update
|
||||
your dependencies:
|
||||
|
||||
.. code-block:: terminal
|
||||
|
||||
$ composer require nelmio/cors-bundle
|
||||
|
||||
The bundle should be automatically enabled by `Symfony Flex`_. If you don't use
|
||||
Flex, you'll need to manually enable the bundle by adding the following line in
|
||||
the ``config/bundles.php`` file of your project::
|
||||
|
||||
<?php
|
||||
// config/bundles.php
|
||||
|
||||
return [
|
||||
// ...
|
||||
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
|
||||
// ...
|
||||
];
|
||||
|
||||
If you don't have a ``config/bundles.php`` file in your project, chances are that
|
||||
you're using an older Symfony version. In this case, you should have an
|
||||
``app/AppKernel.php`` file instead. Edit such file::
|
||||
|
||||
<?php
|
||||
// app/AppKernel.php
|
||||
|
||||
// ...
|
||||
class AppKernel extends Kernel
|
||||
{
|
||||
public function registerBundles()
|
||||
{
|
||||
$bundles = [
|
||||
// ...
|
||||
|
||||
new Nelmio\CorsBundle\NelmioCorsBundle(),
|
||||
];
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Symfony Flex generates a default configuration in ``config/packages/nelmio_cors.yaml``.
|
||||
|
||||
The options defined under ``defaults`` are the default values applied to all
|
||||
the ``paths`` that match, unless overridden in a specific URL configuration.
|
||||
If you want them to apply to everything, you must define a path with ``^/``.
|
||||
|
||||
This example config contains all the possible config values with their default
|
||||
values shown in the ``defaults`` key. In paths, you see that we allow CORS
|
||||
requests from any origin on ``/api/``. One custom header and some HTTP methods
|
||||
are defined as allowed as well. Preflight requests can be cached for 3600
|
||||
seconds.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
nelmio_cors:
|
||||
defaults:
|
||||
allow_credentials: false
|
||||
allow_origin: []
|
||||
allow_headers: []
|
||||
allow_methods: []
|
||||
allow_private_network: false
|
||||
expose_headers: []
|
||||
max_age: 0
|
||||
hosts: []
|
||||
origin_regex: false
|
||||
forced_allow_origin_value: ~
|
||||
skip_same_as_origin: true
|
||||
paths:
|
||||
'^/api/':
|
||||
allow_origin: ['*']
|
||||
allow_headers: ['X-Custom-Auth']
|
||||
allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
|
||||
max_age: 3600
|
||||
'^/':
|
||||
origin_regex: true
|
||||
allow_origin: ['^http://localhost:[0-9]+']
|
||||
allow_headers: ['X-Custom-Auth']
|
||||
allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
|
||||
max_age: 3600
|
||||
hosts: ['^api\.']
|
||||
|
||||
``allow_origin`` and ``allow_headers`` can be set to ``*`` to accept any value,
|
||||
the allowed methods however have to be explicitly listed. ``paths`` must
|
||||
contain at least one item.
|
||||
|
||||
``expose_headers`` can be set to ``*`` to accept any value as long as
|
||||
``allow_credentials`` and ``allow_private_network`` are ``false`` `as per the specification`_.
|
||||
|
||||
If ``origin_regex`` is set, ``allow_origin`` must be a list of regular
|
||||
expressions matching allowed origins. Remember to use ``^`` and ``$`` to
|
||||
clearly define the boundaries of the regex.
|
||||
|
||||
By default, the ``Access-Control-Allow-Origin`` response header value is the
|
||||
``Origin`` request header value (if it matches the rules you've defined with
|
||||
``allow_origin``), so it should be fine for most of use cases. If it's not, you
|
||||
can override this behavior by setting the exact value you want using
|
||||
``forced_allow_origin_value``.
|
||||
|
||||
Be aware that even if you set ``forced_allow_origin_value`` to ``*``, if you
|
||||
also set ``allow_origin`` to ``http://example.com``, only this specific domain
|
||||
will be allowed to access your resources.
|
||||
|
||||
.. note::
|
||||
|
||||
If you allow POST methods and have `HTTP method overriding`_ enabled in the
|
||||
framework, it will enable the API users to perform ``PUT`` and ``DELETE``
|
||||
requests as well.
|
||||
|
||||
Cookbook
|
||||
--------
|
||||
|
||||
How to ignore preflight requests on New Relic?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
On specific architectures with a mostly authenticated API, preflight request can
|
||||
represent a huge part of the traffic.
|
||||
|
||||
In such cases, you may not need to monitor on New Relic this traffic which is by
|
||||
the way categorized automatically as ``unknown`` by New Relic.
|
||||
|
||||
A request listener can be written to ignore preflight requests::
|
||||
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
|
||||
class PreflightIgnoreOnNewRelicListener
|
||||
{
|
||||
public function onKernelResponse(FilterResponseEvent $event)
|
||||
{
|
||||
if (!extension_loaded('newrelic')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('OPTIONS' === $event->getRequest()->getMethod()) {
|
||||
newrelic_ignore_transaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Register this listener, and *voilà!*
|
||||
|
||||
.. _`Cross-Origin Resource Sharing`: http://enable-cors.org/
|
||||
.. _`this flow chart image`: http://www.html5rocks.com/static/images/cors_server_flowchart.png
|
||||
.. _`Symfony Flex`: https://symfony.com/doc/current/setup/flex.html
|
||||
.. _`as per the specification`: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
|
||||
.. _`HTTP method overriding`: http://symfony.com/doc/current/reference/configuration/framework.html#http-method-override
|
||||
5
backend/vendor/nelmio/cors-bundle/SECURITY.md
vendored
Normal file
5
backend/vendor/nelmio/cors-bundle/SECURITY.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report privately at j.boggiano@seld.be
|
||||
41
backend/vendor/nelmio/cors-bundle/composer.json
vendored
Normal file
41
backend/vendor/nelmio/cors-bundle/composer.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "nelmio/cors-bundle",
|
||||
"description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Symfony application",
|
||||
"keywords": ["cors", "crossdomain", "api"],
|
||||
"type": "symfony-bundle",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nelmio",
|
||||
"homepage": "http://nelm.io"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://github.com/nelmio/NelmioCorsBundle/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0 || ^8.0",
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8",
|
||||
"phpstan/phpstan": "^1.11.5",
|
||||
"phpstan/phpstan-phpunit": "^1.4",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.2.0",
|
||||
"phpstan/phpstan-symfony": "^1.4.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Nelmio\\CorsBundle\\": "" },
|
||||
"exclude-from-classmap": ["/Tests/"]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "@php vendor/bin/phpunit",
|
||||
"phpstan": "@php vendor/bin/phpstan"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user