src/Framework/Security/ContentSecurityPolicy/EventSubscriber/ContentSecurityPolicyListener.php line 47

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Framework\Security\ContentSecurityPolicy\EventSubscriber;
  4. use App\Framework\Security\ContentSecurityPolicy\Computer\PageScriptCSPComputer;
  5. use App\Framework\Security\ContentSecurityPolicy\Computer\ResponseNonceComputer;
  6. use App\Framework\Security\ContentSecurityPolicy\DirectivesSet;
  7. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  8. use Symfony\Component\HttpKernel\Event\RequestEvent;
  9. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  10. use Symfony\Component\HttpKernel\HttpKernelInterface;
  11. class ContentSecurityPolicyListener implements EventSubscriberInterface
  12. {
  13.     private DirectivesSet $directiveSet;
  14.     private ?string $nonce null;
  15.     public function __construct(
  16.         private readonly PageScriptCSPComputer $pageScriptCSPComputer
  17.     ) {
  18.         $this->directiveSet = new DirectivesSet();
  19.     }
  20.     public function resetDirectiveSet(): void
  21.     {
  22.         $this->directiveSet = new DirectivesSet();
  23.     }
  24.     public function addCSPHeader(ResponseEvent $event): void
  25.     {
  26.         if (HttpKernelInterface::MAIN_REQUEST !== $event->getRequestType()) {
  27.             return;
  28.         }
  29.         $event->getResponse()->headers->set(
  30.             'Content-Security-Policy',
  31.             $this->directiveSet->buildHeaderValue($this->getNonce())
  32.         );
  33.     }
  34.     public function addNonceToScripts(ResponseEvent $event): void
  35.     {
  36.         $event->setResponse(ResponseNonceComputer::computeNoncesToResponseContent($event->getResponse(), $this->getNonce()));
  37.     }
  38.     public function calculateAddedScripts(RequestEvent $event): void
  39.     {
  40.         if (HttpKernelInterface::MAIN_REQUEST !== $event->getRequestType()) {
  41.             return;
  42.         }
  43.         $hashes $this->pageScriptCSPComputer->computeShaSet();
  44.         $this->directiveSet->addShaSet('script-src'$hashes);
  45.     }
  46.     public function calculateNonce(RequestEvent $event): void
  47.     {
  48.         if (HttpKernelInterface::MAIN_REQUEST !== $event->getRequestType()) {
  49.             return;
  50.         }
  51.         $this->getNonce();
  52.     }
  53.     public function getNonce(): string
  54.     {
  55.         if (null === $this->nonce) {
  56.             $this->nonce base64_encode(random_bytes(16));
  57.         }
  58.         return $this->nonce;
  59.     }
  60.     public static function getSubscribedEvents(): array
  61.     {
  62.         return [
  63.             RequestEvent::class => [
  64.                 ['resetDirectiveSet', -7],
  65.                 ['calculateNonce', -8],
  66.                 ['calculateAddedScripts', -9],
  67.             ],
  68.             ResponseEvent::class => [
  69.                 ['addNonceToScripts'],
  70.                 ['addCSPHeader'1],
  71.             ],
  72.         ];
  73.     }
  74. }