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

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Storefront\Framework\Csrf;
  3. use Shopware\Core\Framework\Feature;
  4. use Shopware\Core\Framework\Log\Package;
  5. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  6. use Shopware\Core\Framework\Routing\KernelListenerPriorities;
  7. use Shopware\Core\PlatformRequest;
  8. use Shopware\Core\SalesChannelRequest;
  9. use Shopware\Storefront\Framework\Csrf\Exception\InvalidCsrfTokenException;
  10. use Shopware\Storefront\Framework\Routing\StorefrontRouteScope;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  14. use Symfony\Component\HttpKernel\KernelEvents;
  15. use Symfony\Component\Security\Csrf\CsrfToken;
  16. use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
  17. use Symfony\Contracts\Service\ResetInterface;
  18. use Symfony\Contracts\Translation\TranslatorInterface;
  19. /**
  20.  * @deprecated tag:v6.5.0 - reason:becomes-internal - will be removed
  21.  */
  22. #[Package('storefront')]
  23. class CsrfRouteListener implements EventSubscriberInterfaceResetInterface
  24. {
  25.     /**
  26.      * @deprecated tag:v6.5.0 - reason:visibility-change - Will become private and natively typed to bool
  27.      *
  28.      * @var bool
  29.      */
  30.     protected $csrfEnabled;
  31.     /**
  32.      * @deprecated tag:v6.5.0 - reason:visibility-change - Will become private and natively typed to string
  33.      *
  34.      * @var string
  35.      */
  36.     protected $csrfMode;
  37.     private CsrfTokenManagerInterface $csrfTokenManager;
  38.     /**
  39.      * Used to track if the csrf token has already been check for the request
  40.      */
  41.     private bool $csrfChecked false;
  42.     private TranslatorInterface $translator;
  43.     /**
  44.      * @internal
  45.      */
  46.     public function __construct(
  47.         CsrfTokenManagerInterface $csrfTokenManager,
  48.         bool $csrfEnabled,
  49.         string $csrfMode,
  50.         TranslatorInterface $translator
  51.     ) {
  52.         $this->csrfTokenManager $csrfTokenManager;
  53.         $this->csrfEnabled $csrfEnabled;
  54.         $this->translator $translator;
  55.         $this->csrfMode $csrfMode;
  56.     }
  57.     public static function getSubscribedEvents(): array
  58.     {
  59.         if (Feature::isActive('v6.5.0.0')) {
  60.             return [];
  61.         }
  62.         return [
  63.             KernelEvents::CONTROLLER => [
  64.                 ['csrfCheck'KernelListenerPriorities::KERNEL_CONTROLLER_EVENT_CONTEXT_RESOLVE_PRE],
  65.             ],
  66.         ];
  67.     }
  68.     public function csrfCheck(ControllerEvent $event): void
  69.     {
  70.         if (Feature::isActive('v6.5.0.0')) {
  71.             return;
  72.         }
  73.         Feature::triggerDeprecationOrThrow(
  74.             'v6.5.0.0',
  75.             Feature::deprecatedClassMessage(__CLASS__'v6.5.0.0')
  76.         );
  77.         if (!$this->csrfEnabled || $this->csrfChecked === true) {
  78.             return;
  79.         }
  80.         $request $event->getRequest();
  81.         if ($request->attributes->get(SalesChannelRequest::ATTRIBUTE_CSRF_PROTECTEDtrue) === false) {
  82.             return;
  83.         }
  84.         if ($request->getMethod() !== Request::METHOD_POST) {
  85.             return;
  86.         }
  87.         /** @var RouteScope|list<string> $scopes */
  88.         $scopes $request->attributes->get(PlatformRequest::ATTRIBUTE_ROUTE_SCOPE, []);
  89.         if ($scopes instanceof RouteScope) {
  90.             $scopes $scopes->getScopes();
  91.         }
  92.         // Only check csrf token on storefront routes
  93.         if (!\in_array(StorefrontRouteScope::ID$scopestrue)) {
  94.             return;
  95.         }
  96.         $this->validateCsrfToken($request);
  97.     }
  98.     /**
  99.      * @deprecated tag:v6.5.0 - reason:visibility-change - method will become private in v6.5.0
  100.      */
  101.     public function validateCsrfToken(Request $request): void
  102.     {
  103.         Feature::triggerDeprecationOrThrow(
  104.             'v6.5.0.0',
  105.             Feature::deprecatedClassMessage(__CLASS__'v6.5.0.0')
  106.         );
  107.         $this->csrfChecked true;
  108.         $submittedCSRFToken = (string) $request->request->get('_csrf_token');
  109.         if ($this->csrfMode === CsrfModes::MODE_TWIG) {
  110.             $intent = (string) $request->attributes->get('_route');
  111.         } else {
  112.             $intent 'ajax';
  113.         }
  114.         $csrfCookies = (array) $request->cookies->get('csrf');
  115.         if (
  116.             (!isset($csrfCookies[$intent]) || $csrfCookies[$intent] !== $submittedCSRFToken)
  117.             && !$this->csrfTokenManager->isTokenValid(new CsrfToken($intent$submittedCSRFToken))
  118.         ) {
  119.             $session $request->getSession();
  120.             /* @see https://github.com/symfony/symfony/issues/41765 */
  121.             if (method_exists($session'getFlashBag')) {
  122.                 if ($request->isXmlHttpRequest()) {
  123.                     $session->getFlashBag()->add('danger'$this->translator->trans('error.message-403-ajax'));
  124.                 } else {
  125.                     $session->getFlashBag()->add('danger'$this->translator->trans('error.message-403'));
  126.                 }
  127.             }
  128.             throw new InvalidCsrfTokenException();
  129.         }
  130.     }
  131.     public function reset(): void
  132.     {
  133.         $this->csrfChecked false;
  134.     }
  135. }