ResponseCspSubscriber.php in Content-Security-Policy 8
File
src/EventSubscriber/ResponseCspSubscriber.php
View source
<?php
namespace Drupal\csp\EventSubscriber;
use Drupal\Component\Plugin\Exception\PluginException;
use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\csp\Csp;
use Drupal\csp\CspEvents;
use Drupal\csp\Event\PolicyAlterEvent;
use Drupal\csp\LibraryPolicyBuilder;
use Drupal\csp\ReportingHandlerPluginManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class ResponseCspSubscriber implements EventSubscriberInterface {
protected $configFactory;
protected $libraryPolicyBuilder;
private $reportingHandlerPluginManager;
private $eventDispatcher;
public function __construct(ConfigFactoryInterface $configFactory, LibraryPolicyBuilder $libraryPolicyBuilder, ReportingHandlerPluginManager $reportingHandlerPluginManager, EventDispatcherInterface $eventDispatcher) {
$this->configFactory = $configFactory;
$this->libraryPolicyBuilder = $libraryPolicyBuilder;
$this->reportingHandlerPluginManager = $reportingHandlerPluginManager;
$this->eventDispatcher = $eventDispatcher;
}
public static function getSubscribedEvents() {
$events[KernelEvents::RESPONSE] = [
'onKernelResponse',
];
return $events;
}
public function onKernelResponse(FilterResponseEvent $event) {
if (!$event
->isMasterRequest()) {
return;
}
$cspConfig = $this->configFactory
->get('csp.settings');
$libraryDirectives = $this->libraryPolicyBuilder
->getSources();
$response = $event
->getResponse();
if ($response instanceof CacheableResponseInterface) {
$response
->getCacheableMetadata()
->addCacheTags([
'config:csp.settings',
]);
}
foreach ([
'report-only',
'enforce',
] as $policyType) {
if (!$cspConfig
->get($policyType . '.enable')) {
continue;
}
$policy = new Csp();
$policy
->reportOnly($policyType == 'report-only');
foreach ($cspConfig
->get($policyType . '.directives') ?: [] as $directiveName => $directiveOptions) {
if (is_bool($directiveOptions)) {
$policy
->setDirective($directiveName, TRUE);
continue;
}
if (!isset($directiveOptions['base'])) {
$policy
->setDirective($directiveName, $directiveOptions);
continue;
}
switch ($directiveOptions['base']) {
case 'self':
$policy
->setDirective($directiveName, [
Csp::POLICY_SELF,
]);
break;
case 'none':
$policy
->setDirective($directiveName, [
Csp::POLICY_NONE,
]);
break;
case 'any':
$policy
->setDirective($directiveName, [
Csp::POLICY_ANY,
]);
break;
default:
$policy
->setDirective($directiveName, []);
}
if (!empty($directiveOptions['flags'])) {
$policy
->appendDirective($directiveName, array_map(function ($value) {
return "'" . $value . "'";
}, $directiveOptions['flags']));
}
if (!empty($directiveOptions['sources'])) {
$policy
->appendDirective($directiveName, $directiveOptions['sources']);
}
if (isset($libraryDirectives[$directiveName])) {
$policy
->appendDirective($directiveName, $libraryDirectives[$directiveName]);
}
}
$reportingPluginId = $cspConfig
->get($policyType . '.reporting.plugin');
if ($reportingPluginId) {
$reportingOptions = $cspConfig
->get($policyType . '.reporting.options') ?: [];
$reportingOptions += [
'type' => $policyType,
];
try {
$this->reportingHandlerPluginManager
->createInstance($reportingPluginId, $reportingOptions)
->alterPolicy($policy);
} catch (PluginException $e) {
watchdog_exception('csp', $e);
}
}
$this->eventDispatcher
->dispatch(CspEvents::POLICY_ALTER, new PolicyAlterEvent($policy, $response));
if ($headerValue = $policy
->getHeaderValue()) {
$response->headers
->set($policy
->getHeaderName(), $headerValue);
}
}
}
}