mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-23 18:03:17 +00:00
Use alchemy/symfony-cors instead of ApiCorsSubscriber
This commit is contained in:
@@ -40,7 +40,7 @@
|
|||||||
"alchemy/oauth2php": "1.0.0",
|
"alchemy/oauth2php": "1.0.0",
|
||||||
"alchemy/phlickr": "0.2.9",
|
"alchemy/phlickr": "0.2.9",
|
||||||
"alchemy/rest-bundle": "master@dev",
|
"alchemy/rest-bundle": "master@dev",
|
||||||
"alchemy/symfony-cors": "master@dev",
|
"alchemy/symfony-cors": "^0.1.0",
|
||||||
"alchemy/task-manager": "2.0.x-dev@dev",
|
"alchemy/task-manager": "2.0.x-dev@dev",
|
||||||
"alchemy/zippy": "0.2.x-dev@dev",
|
"alchemy/zippy": "0.2.x-dev@dev",
|
||||||
"beberlei/assert": "^2.3",
|
"beberlei/assert": "^2.3",
|
||||||
|
56
composer.lock
generated
56
composer.lock
generated
@@ -4,8 +4,8 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"hash": "9ad403d1241ac6e7c1d6a8ee1a88b562",
|
"hash": "060bc97259e610db725a2f75af4cccc0",
|
||||||
"content-hash": "afa161367fc67b099314aecbff0ab9d8",
|
"content-hash": "691d34f60fc60114d275eab15a3e9de5",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "alchemy-fr/tcpdf-clone",
|
"name": "alchemy-fr/tcpdf-clone",
|
||||||
@@ -15,6 +15,12 @@
|
|||||||
"url": "https://github.com/alchemy-fr/tcpdf-clone.git",
|
"url": "https://github.com/alchemy-fr/tcpdf-clone.git",
|
||||||
"reference": "2ba0248a7187f1626df6c128750650416267f0e7"
|
"reference": "2ba0248a7187f1626df6c128750650416267f0e7"
|
||||||
},
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/alchemy-fr/tcpdf-clone/zipball/2ba0248a7187f1626df6c128750650416267f0e7",
|
||||||
|
"reference": "2ba0248a7187f1626df6c128750650416267f0e7",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.0"
|
"php": ">=5.3.0"
|
||||||
},
|
},
|
||||||
@@ -61,6 +67,10 @@
|
|||||||
"qrcode",
|
"qrcode",
|
||||||
"tcpdf"
|
"tcpdf"
|
||||||
],
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/alchemy-fr/tcpdf-clone/tree/6.0.039",
|
||||||
|
"issues": "https://github.com/alchemy-fr/tcpdf-clone/issues"
|
||||||
|
},
|
||||||
"time": "2013-10-13 16:11:17"
|
"time": "2013-10-13 16:11:17"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -104,7 +114,7 @@
|
|||||||
"homepage": "http://www.lickmychip.com/"
|
"homepage": "http://www.lickmychip.com/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Nicolas Le Goff",
|
"name": "nlegoff",
|
||||||
"email": "legoff.n@gmail.com"
|
"email": "legoff.n@gmail.com"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -304,7 +314,7 @@
|
|||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/alchemy-fr/rest-bundle/zipball/7b1c88c02ab8c0d4e997fd61c13c8fd4c3ce5216",
|
"url": "https://api.github.com/repos/alchemy-fr/rest-bundle/zipball/a0e2c2b8a1d2c9c405fc9663b698f56a20831946",
|
||||||
"reference": "7b1c88c02ab8c0d4e997fd61c13c8fd4c3ce5216",
|
"reference": "7b1c88c02ab8c0d4e997fd61c13c8fd4c3ce5216",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
@@ -347,11 +357,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "alchemy/symfony-cors",
|
"name": "alchemy/symfony-cors",
|
||||||
"version": "dev-master",
|
"version": "0.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/alchemy-fr/symfony-cors",
|
"url": "https://github.com/alchemy-fr/symfony-cors",
|
||||||
"reference": "88f2d4089e252153946e283ac89631e78b4d73a5"
|
"reference": "8aafaff26e29fdd57358062d20724109a349def5"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"symfony/http-kernel": "^2.3.0|^3.0.0"
|
"symfony/http-kernel": "^2.3.0|^3.0.0"
|
||||||
@@ -361,6 +371,11 @@
|
|||||||
"silex/silex": "^1.0"
|
"silex/silex": "^1.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "0.1.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Alchemy\\Cors\\": "src/Component/",
|
"Alchemy\\Cors\\": "src/Component/",
|
||||||
@@ -383,7 +398,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "A library that adds CORS services to Silex/Symfony Applications",
|
"description": "A library that adds CORS services to Silex/Symfony Applications",
|
||||||
"time": "2015-10-12 11:04:31"
|
"time": "2015-11-20 17:55:08"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "alchemy/task-manager",
|
"name": "alchemy/task-manager",
|
||||||
@@ -1473,12 +1488,12 @@
|
|||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/igorw/evenement.git",
|
"url": "https://github.com/igorw/evenement.git",
|
||||||
"reference": "v1.0.0"
|
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/igorw/evenement/zipball/fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
|
"url": "https://api.github.com/repos/igorw/evenement/zipball/fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
|
||||||
"reference": "v1.0.0",
|
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1505,7 +1520,7 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"event-dispatcher"
|
"event-dispatcher"
|
||||||
],
|
],
|
||||||
"time": "2012-05-30 08:01:08"
|
"time": "2012-05-30 15:01:08"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "facebook/php-sdk",
|
"name": "facebook/php-sdk",
|
||||||
@@ -2631,7 +2646,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-develop": "0.7-dev"
|
"dev-develop": "0.6-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -3355,7 +3370,7 @@
|
|||||||
],
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Stephen Clay",
|
"name": "Steve Clay",
|
||||||
"email": "steve@mrclay.org",
|
"email": "steve@mrclay.org",
|
||||||
"homepage": "http://www.mrclay.org/",
|
"homepage": "http://www.mrclay.org/",
|
||||||
"role": "Developer"
|
"role": "Developer"
|
||||||
@@ -3541,21 +3556,21 @@
|
|||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/romainneutron/Imagine-Silex-Service-Provider.git",
|
"url": "https://github.com/romainneutron/Imagine-Silex-Service-Provider.git",
|
||||||
"reference": "0.1.2"
|
"reference": "a8a7862ae90419f2b23746cd8436c2310e4eb084"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/romainneutron/Imagine-Silex-Service-Provider/zipball/a8a7862ae90419f2b23746cd8436c2310e4eb084",
|
"url": "https://api.github.com/repos/romainneutron/Imagine-Silex-Service-Provider/zipball/a8a7862ae90419f2b23746cd8436c2310e4eb084",
|
||||||
"reference": "0.1.2",
|
"reference": "a8a7862ae90419f2b23746cd8436c2310e4eb084",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"imagine/imagine": "*",
|
"imagine/imagine": "*",
|
||||||
"php": ">=5.3.3",
|
"php": ">=5.3.3",
|
||||||
"silex/silex": ">=1.0,<2.0"
|
"silex/silex": "~1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"symfony/browser-kit": ">=2.0,<3.0"
|
"symfony/browser-kit": "~2.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -4189,7 +4204,9 @@
|
|||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Fabien Potencier",
|
"name": "Fabien Potencier",
|
||||||
"email": "fabien@symfony.com"
|
"email": "fabien@symfony.com",
|
||||||
|
"homepage": "http://fabien.potencier.org",
|
||||||
|
"role": "Lead Developer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
|
"description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
|
||||||
@@ -4318,7 +4335,7 @@
|
|||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/583b8eba0bcc0ac9aa8e7309e5313c068dbfbe30",
|
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/e9478830dd1d19ee598ecfb2a6b5e6a4f8f168c2",
|
||||||
"reference": "583b8eba0bcc0ac9aa8e7309e5313c068dbfbe30",
|
"reference": "583b8eba0bcc0ac9aa8e7309e5313c068dbfbe30",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
@@ -4823,7 +4840,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Phraseanet Team",
|
"name": "Phraseanet Team",
|
||||||
"email": "support@alchemy.fr",
|
"email": "info@alchemy.fr",
|
||||||
"homepage": "http://www.phraseanet.com/"
|
"homepage": "http://www.phraseanet.com/"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -6215,7 +6232,6 @@
|
|||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": {
|
"stability-flags": {
|
||||||
"alchemy/rest-bundle": 20,
|
"alchemy/rest-bundle": 20,
|
||||||
"alchemy/symfony-cors": 20,
|
|
||||||
"alchemy/task-manager": 20,
|
"alchemy/task-manager": 20,
|
||||||
"alchemy/zippy": 20,
|
"alchemy/zippy": 20,
|
||||||
"goodby/csv": 20,
|
"goodby/csv": 20,
|
||||||
|
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
namespace Alchemy\Phrasea;
|
namespace Alchemy\Phrasea;
|
||||||
|
|
||||||
|
use Alchemy\Cors\Options\DefaultProvider;
|
||||||
|
use Alchemy\CorsProvider\CorsServiceProvider;
|
||||||
use Alchemy\Geonames\GeonamesServiceProvider;
|
use Alchemy\Geonames\GeonamesServiceProvider;
|
||||||
use Alchemy\Phrasea\Application\Helper\AclAware;
|
use Alchemy\Phrasea\Application\Helper\AclAware;
|
||||||
use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware;
|
use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware;
|
||||||
@@ -267,6 +269,29 @@ class Application extends SilexApplication
|
|||||||
$this->register(new PluginServiceProvider());
|
$this->register(new PluginServiceProvider());
|
||||||
$this->register(new PhraseaEventServiceProvider());
|
$this->register(new PhraseaEventServiceProvider());
|
||||||
$this->register(new ContentNegotiationServiceProvider());
|
$this->register(new ContentNegotiationServiceProvider());
|
||||||
|
$this->register(new CorsServiceProvider(), [
|
||||||
|
'alchemy_cors.debug' => $this['debug'],
|
||||||
|
'alchemy_cors.cache_path' => function (Application $app) {
|
||||||
|
return rtrim($app['cache.path'], '/\\') . '/alchemy_cors.cache.php';
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
$this['phraseanet.api_cors.options_provider'] = function (Application $app) {
|
||||||
|
$paths = [];
|
||||||
|
|
||||||
|
if (isset($app['phraseanet.configuration']['api_cors'])) {
|
||||||
|
$config = $app['phraseanet.configuration']['api_cors'];
|
||||||
|
|
||||||
|
if (isset($config['enabled']) && $config['enabled']) {
|
||||||
|
unset($config['enabled']);
|
||||||
|
|
||||||
|
$paths['/api/v\d+/'] = $config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultProvider($paths, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
$this['alchemy_cors.options_providers'][] = 'phraseanet.api_cors.options_provider';
|
||||||
$this->register(new LocaleServiceProvider());
|
$this->register(new LocaleServiceProvider());
|
||||||
$this->setupEventDispatcher();
|
$this->setupEventDispatcher();
|
||||||
$this['phraseanet.exception_handler'] = $this->share(function ($app) {
|
$this['phraseanet.exception_handler'] = $this->share(function ($app) {
|
||||||
|
@@ -20,7 +20,6 @@ use Alchemy\Phrasea\ControllerProvider\MediaAccessor;
|
|||||||
use Alchemy\Phrasea\ControllerProvider\Minifier;
|
use Alchemy\Phrasea\ControllerProvider\Minifier;
|
||||||
use Alchemy\Phrasea\ControllerProvider\Permalink;
|
use Alchemy\Phrasea\ControllerProvider\Permalink;
|
||||||
use Alchemy\Phrasea\Core\Event\ApiResultEvent;
|
use Alchemy\Phrasea\Core\Event\ApiResultEvent;
|
||||||
use Alchemy\Phrasea\Core\Event\Subscriber\ApiCorsSubscriber;
|
|
||||||
use Alchemy\Phrasea\Core\Event\Subscriber\ApiExceptionHandlerSubscriber;
|
use Alchemy\Phrasea\Core\Event\Subscriber\ApiExceptionHandlerSubscriber;
|
||||||
use Alchemy\Phrasea\Core\Event\Subscriber\ApiOauth2ErrorsSubscriber;
|
use Alchemy\Phrasea\Core\Event\Subscriber\ApiOauth2ErrorsSubscriber;
|
||||||
use Alchemy\Phrasea\Core\PhraseaEvents;
|
use Alchemy\Phrasea\Core\PhraseaEvents;
|
||||||
@@ -30,6 +29,7 @@ use Monolog\Processor\WebProcessor;
|
|||||||
use Silex\Application as SilexApplication;
|
use Silex\Application as SilexApplication;
|
||||||
use Silex\Provider\WebProfilerServiceProvider;
|
use Silex\Provider\WebProfilerServiceProvider;
|
||||||
use Sorien\Provider\DoctrineProfilerServiceProvider;
|
use Sorien\Provider\DoctrineProfilerServiceProvider;
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) {
|
|||||||
));
|
));
|
||||||
}, PhraseaApplication::EARLY_EVENT);
|
}, PhraseaApplication::EARLY_EVENT);
|
||||||
|
|
||||||
$app->after(function(Request $request, Response $response) use ($app) {
|
$app->after(function(Request $request, Response $response) {
|
||||||
if ($request->getRequestFormat(Result::FORMAT_JSON) === Result::FORMAT_JSONP && !$response->isOk() && !$response->isServerError()) {
|
if ($request->getRequestFormat(Result::FORMAT_JSON) === Result::FORMAT_JSONP && !$response->isOk() && !$response->isServerError()) {
|
||||||
$response->setStatusCode(200);
|
$response->setStatusCode(200);
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$app['dispatcher'] = $app->share($app->extend('dispatcher', function ($dispatcher, PhraseaApplication $app) {
|
$app['dispatcher'] = $app->share($app->extend('dispatcher', function (EventDispatcherInterface $dispatcher, PhraseaApplication $app) {
|
||||||
$dispatcher->addSubscriber(new ApiOauth2ErrorsSubscriber($app['phraseanet.exception_handler'], $app['translator']));
|
$dispatcher->addSubscriber(new ApiOauth2ErrorsSubscriber($app['phraseanet.exception_handler'], $app['translator']));
|
||||||
|
|
||||||
return $dispatcher;
|
return $dispatcher;
|
||||||
@@ -156,7 +156,6 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) {
|
|||||||
$app->after(function (Request $request, Response $response) use ($app) {
|
$app->after(function (Request $request, Response $response) use ($app) {
|
||||||
$app['dispatcher']->dispatch(PhraseaEvents::API_RESULT, new ApiResultEvent($request, $response));
|
$app['dispatcher']->dispatch(PhraseaEvents::API_RESULT, new ApiResultEvent($request, $response));
|
||||||
});
|
});
|
||||||
$app['dispatcher']->addSubscriber(new ApiCorsSubscriber($app));
|
|
||||||
|
|
||||||
return $app;
|
return $app;
|
||||||
}, isset($environment) ? $environment : PhraseaApplication::ENV_PROD);
|
}, isset($environment) ? $environment : PhraseaApplication::ENV_PROD);
|
||||||
|
@@ -1,207 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of Phraseanet
|
|
||||||
*
|
|
||||||
* (c) 2005-2015 Alchemy
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Alchemy\Phrasea\Core\Event\Subscriber;
|
|
||||||
|
|
||||||
use Alchemy\Phrasea\Application;
|
|
||||||
use Symfony\Component\HttpKernel\KernelEvents;
|
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|
||||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
|
||||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
|
||||||
|
|
||||||
class ApiCorsSubscriber implements EventSubscriberInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Simple headers as defined in the spec should always be accepted
|
|
||||||
*/
|
|
||||||
protected static $simpleHeaders = [
|
|
||||||
'accept',
|
|
||||||
'accept-language',
|
|
||||||
'content-language',
|
|
||||||
'origin',
|
|
||||||
];
|
|
||||||
|
|
||||||
private $app;
|
|
||||||
private $options;
|
|
||||||
|
|
||||||
public function __construct(Application $app)
|
|
||||||
{
|
|
||||||
$this->app = $app;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getSubscribedEvents()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
KernelEvents::REQUEST => ['onKernelRequest', 128],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onKernelRequest(GetResponseEvent $event)
|
|
||||||
{
|
|
||||||
if (!$this->app['phraseanet.configuration']['api_cors']['enabled']) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$request = $event->getRequest();
|
|
||||||
|
|
||||||
if (!preg_match('{api/v(\d+)}i', $request->getPathInfo() ?: '/')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip if not a CORS request
|
|
||||||
if (!$request->headers->has('Origin') || $request->headers->get('Origin') == $request->getSchemeAndHttpHost()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$options = array_merge([
|
|
||||||
'allow_credentials'=> false,
|
|
||||||
'allow_origin'=> [],
|
|
||||||
'allow_headers'=> [],
|
|
||||||
'allow_methods'=> [],
|
|
||||||
'expose_headers'=> [],
|
|
||||||
'max_age'=> 0,
|
|
||||||
'hosts'=> [],
|
|
||||||
], $this->app['phraseanet.configuration']['api_cors']);
|
|
||||||
|
|
||||||
// skip if the host is not matching
|
|
||||||
if (!$this->checkHost($request, $options)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// perform preflight checks
|
|
||||||
if ('OPTIONS' === $request->getMethod()) {
|
|
||||||
$event->setResponse($this->getPreflightResponse($request, $options));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!$this->checkOrigin($request, $options)) {
|
|
||||||
$response = new Response('', 403, ['Access-Control-Allow-Origin' => 'null']);
|
|
||||||
$event->setResponse($response);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->app['dispatcher']->addListener(KernelEvents::RESPONSE, [$this, 'onKernelResponse']);
|
|
||||||
$this->options = $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onKernelResponse(FilterResponseEvent $event)
|
|
||||||
{
|
|
||||||
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $event->getResponse();
|
|
||||||
$request = $event->getRequest();
|
|
||||||
// add CORS response headers
|
|
||||||
$response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
|
|
||||||
if ($this->options['allow_credentials']) {
|
|
||||||
$response->headers->set('Access-Control-Allow-Credentials', 'true');
|
|
||||||
}
|
|
||||||
if ($this->options['expose_headers']) {
|
|
||||||
$response->headers->set('Access-Control-Expose-Headers', strtolower(implode(', ', $this->options['expose_headers'])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getPreflightResponse(Request $request, array $options)
|
|
||||||
{
|
|
||||||
$response = new Response();
|
|
||||||
|
|
||||||
if ($options['allow_credentials']) {
|
|
||||||
$response->headers->set('Access-Control-Allow-Credentials', 'true');
|
|
||||||
}
|
|
||||||
if ($options['allow_methods']) {
|
|
||||||
$response->headers->set('Access-Control-Allow-Methods', implode(', ', $options['allow_methods']));
|
|
||||||
}
|
|
||||||
if ($options['allow_headers']) {
|
|
||||||
$headers = in_array('*', $options['allow_headers'])
|
|
||||||
? $request->headers->get('Access-Control-Request-Headers')
|
|
||||||
: implode(', ', array_map('strtolower', $options['allow_headers']));
|
|
||||||
$response->headers->set('Access-Control-Allow-Headers', $headers);
|
|
||||||
}
|
|
||||||
if ($options['max_age']) {
|
|
||||||
$response->headers->set('Access-Control-Max-Age', $options['max_age']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->checkOrigin($request, $options)) {
|
|
||||||
$response->headers->set('Access-Control-Allow-Origin', 'null');
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
|
|
||||||
|
|
||||||
// check request method
|
|
||||||
if (!in_array(strtoupper($request->headers->get('Access-Control-Request-Method')), $options['allow_methods'], true)) {
|
|
||||||
$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'][] = $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 ($options['allow_headers'] !== true && $headers) {
|
|
||||||
$headers = trim(strtolower($headers));
|
|
||||||
foreach (preg_split('{, *}', $headers) as $header) {
|
|
||||||
if (in_array($header, self::$simpleHeaders, true)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!in_array($header, $options['allow_headers'], true)) {
|
|
||||||
$response->setStatusCode(400);
|
|
||||||
$response->setContent('Unauthorized header '.$header);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function checkOrigin(Request $request, array $options)
|
|
||||||
{
|
|
||||||
// check origin
|
|
||||||
$origin = $request->headers->get('Origin');
|
|
||||||
if (in_array('*', $options['allow_origin']) || in_array($origin, $options['allow_origin'])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function checkHost(Request $request, array $options)
|
|
||||||
{
|
|
||||||
if (count($options['hosts']) === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($options['hosts'] as $hostRegexp) {
|
|
||||||
if (preg_match('{'.$hostRegexp.'}i', $request->getHost())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,106 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Alchemy\Tests\Phrasea\Core\Event\Subscriber;
|
|
||||||
|
|
||||||
use Alchemy\Phrasea\Application;
|
|
||||||
use Symfony\Component\HttpKernel\Client;
|
|
||||||
use Alchemy\Phrasea\Core\Event\Subscriber\ApiCorsSubscriber;
|
|
||||||
|
|
||||||
class ApiCorsSubscriberTest extends \PHPUnit_Framework_TestCase
|
|
||||||
{
|
|
||||||
private $origin = 'http://dev.phrasea.net';
|
|
||||||
|
|
||||||
public function testHostRestriction()
|
|
||||||
{
|
|
||||||
$response = $this->request(['enabled' => true, 'hosts' => ['http://api.domain.com']]);
|
|
||||||
$this->assertArrayNotHasKey('access-control-allow-origin', $response->headers->all());
|
|
||||||
|
|
||||||
$response = $this->request(['enabled' => true, 'hosts' => ['localhost']]);
|
|
||||||
$this->assertArrayHasKey('access-control-allow-origin', $response->headers->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testExposeHeaders()
|
|
||||||
{
|
|
||||||
$response = $this->request(
|
|
||||||
['enabled' => true, 'allow_origin' => ['*'], 'expose_headers' => ['HTTP_X_CUSTOM']],
|
|
||||||
'GET'
|
|
||||||
);
|
|
||||||
$this->assertArrayHasKey('access-control-expose-headers', $response->headers->all());
|
|
||||||
$this->assertEquals('http_x_custom', $response->headers->get('access-control-expose-headers'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testAllowMethods()
|
|
||||||
{
|
|
||||||
$response = $this->request(
|
|
||||||
['enabled' => true, 'allow_origin' => ['*'], 'allow_methods' => ['GET', 'POST', 'PUT']],
|
|
||||||
'OPTIONS'
|
|
||||||
);
|
|
||||||
$this->assertArrayHasKey('access-control-allow-methods', $response->headers->all());
|
|
||||||
$this->assertEquals(implode(', ', ['GET', 'POST', 'PUT']), $response->headers->get('access-control-allow-methods'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testAllowHeaders()
|
|
||||||
{
|
|
||||||
$response = $this->request(
|
|
||||||
['enabled' => true, 'allow_origin' => ['*'], 'allow_headers' => ['HTTP_X_CUSTOM']],
|
|
||||||
'OPTIONS'
|
|
||||||
);
|
|
||||||
$this->assertArrayHasKey('access-control-allow-headers', $response->headers->all());
|
|
||||||
$this->assertEquals('http_x_custom', $response->headers->get('access-control-allow-headers'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCORSIsEnable()
|
|
||||||
{
|
|
||||||
$response = $this->request(['enabled' => true]);
|
|
||||||
$this->assertArrayHasKey('access-control-allow-origin', $response->headers->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCORSIsDisable()
|
|
||||||
{
|
|
||||||
$response = $this->request(['enabled' => false]);
|
|
||||||
$this->assertArrayNotHasKey('access-control-allow-origin', $response->headers->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testAllowOrigin()
|
|
||||||
{
|
|
||||||
$response = $this->request(['enabled' => true, 'allow_origin' => ['*']]);
|
|
||||||
$this->assertArrayHasKey('access-control-allow-origin', $response->headers->all());
|
|
||||||
$this->assertEquals($this->origin, $response->headers->get('access-control-allow-origin'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCredentialIsEnabled()
|
|
||||||
{
|
|
||||||
$response = $this->request(['enabled' => true, 'allow_credentials' => true, 'allow_origin' => ['*']]);
|
|
||||||
$this->assertArrayHasKey('access-control-allow-credentials', $response->headers->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $conf
|
|
||||||
* @param string $method
|
|
||||||
* @param array $extraHeaders
|
|
||||||
*
|
|
||||||
* @return \Symfony\Component\HttpFoundation\Response
|
|
||||||
*/
|
|
||||||
private function request(array $conf, $method = 'GET', array $extraHeaders = [])
|
|
||||||
{
|
|
||||||
$app = new Application(Application::ENV_TEST);
|
|
||||||
$app['phraseanet.configuration']['api_cors'] = $conf;
|
|
||||||
$app['dispatcher']->addSubscriber(new ApiCorsSubscriber($app));
|
|
||||||
$app->get('/api/v1/test-route', function () {
|
|
||||||
return '';
|
|
||||||
});
|
|
||||||
$client = new Client($app);
|
|
||||||
$client->request($method, '/api/v1/test-route',
|
|
||||||
[],
|
|
||||||
[],
|
|
||||||
array_merge(
|
|
||||||
$extraHeaders,
|
|
||||||
[
|
|
||||||
'HTTP_Origin' => $this->origin,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return $client->getResponse();
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user