vendor/shopware/storefront/Framework/Csrf/CsrfRouteListener.php line 76

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Framework\Csrf;
  3. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  4. use Shopware\Core\Framework\Routing\KernelListenerPriorities;
  5. use Shopware\Core\SalesChannelRequest;
  6. use Shopware\Storefront\Framework\Csrf\Exception\InvalidCsrfTokenException;
  7. use Shopware\Storefront\Framework\Routing\StorefrontRouteScope;
  8. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpFoundation\Session\Session;
  11. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  12. use Symfony\Component\HttpKernel\KernelEvents;
  13. use Symfony\Component\Security\Csrf\CsrfToken;
  14. use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
  15. use Symfony\Contracts\Translation\TranslatorInterface;
  16. class CsrfRouteListener implements EventSubscriberInterface
  17. {
  18.     /**
  19.      * @var bool
  20.      */
  21.     protected $csrfEnabled;
  22.     /**
  23.      * @var string
  24.      */
  25.     protected $csrfMode;
  26.     /**
  27.      * @var CsrfTokenManagerInterface
  28.      */
  29.     private $csrfTokenManager;
  30.     /**
  31.      * Used to track if the csrf token has already been check for the request
  32.      *
  33.      * @var bool
  34.      */
  35.     private $csrfChecked false;
  36.     /**
  37.      * @var Session
  38.      */
  39.     private $session;
  40.     /**
  41.      * @var TranslatorInterface
  42.      */
  43.     private $translator;
  44.     public function __construct(
  45.         CsrfTokenManagerInterface $csrfTokenManager,
  46.         bool $csrfEnabled,
  47.         string $csrfMode,
  48.         Session $session,
  49.         TranslatorInterface $translator
  50.     ) {
  51.         $this->csrfTokenManager $csrfTokenManager;
  52.         $this->csrfEnabled $csrfEnabled;
  53.         $this->session $session;
  54.         $this->translator $translator;
  55.         $this->csrfMode $csrfMode;
  56.     }
  57.     public static function getSubscribedEvents(): array
  58.     {
  59.         return [
  60.             KernelEvents::CONTROLLER => [
  61.                 ['csrfCheck'KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_CONTEXT_RESOLVE_PRE],
  62.             ],
  63.         ];
  64.     }
  65.     public function csrfCheck(ControllerEvent $event): void
  66.     {
  67.         if (!$this->csrfEnabled || $this->csrfChecked === true) {
  68.             return;
  69.         }
  70.         $request $event->getRequest();
  71.         if ($request->attributes->get(SalesChannelRequest::ATTRIBUTE_CSRF_PROTECTEDtrue) === false) {
  72.             return;
  73.         }
  74.         if ($request->getMethod() !== Request::METHOD_POST) {
  75.             return;
  76.         }
  77.         /** @var RouteScope|null $routeScope */
  78.         $routeScope $request->attributes->get('_routeScope');
  79.         // Only check csrf token on storefront routes
  80.         if ($routeScope === null || !$routeScope->hasScope(StorefrontRouteScope::ID)) {
  81.             return;
  82.         }
  83.         $this->validateCsrfToken($request);
  84.     }
  85.     public function validateCsrfToken(Request $request): void
  86.     {
  87.         $this->csrfChecked true;
  88.         $submittedCSRFToken $request->request->get('_csrf_token');
  89.         if ($this->csrfMode === CsrfModes::MODE_TWIG) {
  90.             $intent $request->attributes->get('_route');
  91.         } else {
  92.             $intent 'ajax';
  93.         }
  94.         $csrfCookies $request->cookies->get('csrf', []);
  95.         if (
  96.             (!isset($csrfCookies[$intent]) || $csrfCookies[$intent] !== $submittedCSRFToken)
  97.             && !$this->csrfTokenManager->isTokenValid(new CsrfToken($intent$submittedCSRFToken))
  98.         ) {
  99.             if ($request->isXmlHttpRequest()) {
  100.                 $this->session->getFlashBag()->add('danger'$this->translator->trans('error.message-403-ajax'));
  101.             } else {
  102.                 $this->session->getFlashBag()->add('danger'$this->translator->trans('error.message-403'));
  103.             }
  104.             throw new InvalidCsrfTokenException();
  105.         }
  106.     }
  107. }