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

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\PlatformRequest;
  6. use Shopware\Core\SalesChannelRequest;
  7. use Shopware\Storefront\Framework\Csrf\Exception\InvalidCsrfTokenException;
  8. use Shopware\Storefront\Framework\Routing\StorefrontRouteScope;
  9. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  10. use Symfony\Component\HttpFoundation\Request;
  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\Service\ResetInterface;
  16. use Symfony\Contracts\Translation\TranslatorInterface;
  17. class CsrfRouteListener implements EventSubscriberInterfaceResetInterface
  18. {
  19.     /**
  20.      * @var bool
  21.      */
  22.     protected $csrfEnabled;
  23.     /**
  24.      * @var string
  25.      */
  26.     protected $csrfMode;
  27.     private CsrfTokenManagerInterface $csrfTokenManager;
  28.     /**
  29.      * Used to track if the csrf token has already been check for the request
  30.      */
  31.     private bool $csrfChecked false;
  32.     /**
  33.      * @var TranslatorInterface
  34.      */
  35.     private $translator;
  36.     /**
  37.      * @internal
  38.      */
  39.     public function __construct(
  40.         CsrfTokenManagerInterface $csrfTokenManager,
  41.         bool $csrfEnabled,
  42.         string $csrfMode,
  43.         TranslatorInterface $translator
  44.     ) {
  45.         $this->csrfTokenManager $csrfTokenManager;
  46.         $this->csrfEnabled $csrfEnabled;
  47.         $this->translator $translator;
  48.         $this->csrfMode $csrfMode;
  49.     }
  50.     public static function getSubscribedEvents(): array
  51.     {
  52.         return [
  53.             KernelEvents::CONTROLLER => [
  54.                 ['csrfCheck'KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_CONTEXT_RESOLVE_PRE],
  55.             ],
  56.         ];
  57.     }
  58.     public function csrfCheck(ControllerEvent $event): void
  59.     {
  60.         if (!$this->csrfEnabled || $this->csrfChecked === true) {
  61.             return;
  62.         }
  63.         $request $event->getRequest();
  64.         if ($request->attributes->get(SalesChannelRequest::ATTRIBUTE_CSRF_PROTECTEDtrue) === false) {
  65.             return;
  66.         }
  67.         if ($request->getMethod() !== Request::METHOD_POST) {
  68.             return;
  69.         }
  70.         /** @var RouteScope|array $scopes */
  71.         $scopes $request->attributes->get(PlatformRequest::ATTRIBUTE_ROUTE_SCOPE, []);
  72.         if ($scopes instanceof RouteScope) {
  73.             $scopes $scopes->getScopes();
  74.         }
  75.         // Only check csrf token on storefront routes
  76.         if (!\in_array(StorefrontRouteScope::ID$scopestrue)) {
  77.             return;
  78.         }
  79.         $this->validateCsrfToken($request);
  80.     }
  81.     public function validateCsrfToken(Request $request): void
  82.     {
  83.         $this->csrfChecked true;
  84.         $submittedCSRFToken = (string) $request->request->get('_csrf_token');
  85.         if ($this->csrfMode === CsrfModes::MODE_TWIG) {
  86.             $intent = (string) $request->attributes->get('_route');
  87.         } else {
  88.             $intent 'ajax';
  89.         }
  90.         $csrfCookies = (array) $request->cookies->get('csrf');
  91.         if (
  92.             (!isset($csrfCookies[$intent]) || $csrfCookies[$intent] !== $submittedCSRFToken)
  93.             && !$this->csrfTokenManager->isTokenValid(new CsrfToken($intent$submittedCSRFToken))
  94.         ) {
  95.             $session $request->getSession();
  96.             /* @see https://github.com/symfony/symfony/issues/41765 */
  97.             if (method_exists($session'getFlashBag')) {
  98.                 if ($request->isXmlHttpRequest()) {
  99.                     $session->getFlashBag()->add('danger'$this->translator->trans('error.message-403-ajax'));
  100.                 } else {
  101.                     $session->getFlashBag()->add('danger'$this->translator->trans('error.message-403'));
  102.                 }
  103.             }
  104.             throw new InvalidCsrfTokenException();
  105.         }
  106.     }
  107.     public function reset(): void
  108.     {
  109.         $this->csrfChecked false;
  110.     }
  111. }