You are here

public function ResponseCspSubscriber::onKernelResponse in Content-Security-Policy 8

Add Content-Security-Policy header to response.

Parameters

\Symfony\Component\HttpKernel\Event\FilterResponseEvent $event: The Response event.

File

src/EventSubscriber/ResponseCspSubscriber.php, line 89

Class

ResponseCspSubscriber
Class ResponseSubscriber.

Namespace

Drupal\csp\EventSubscriber

Code

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;
      }

      // This is a directive with a simple array of values.
      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:

          // Initialize to an empty value so that any alter subscribers can
          // tell that this directive was enabled.
          $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);
    }
  }
}