vendor/ibexa/corporate-account/src/bundle/EventSubscriber/ApplicationRateLimitSubscriber.php line 60

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4.  * @license For full copyright and license information view LICENSE file distributed with this source code.
  5.  */
  6. declare(strict_types=1);
  7. namespace Ibexa\Bundle\CorporateAccount\EventSubscriber;
  8. use Ibexa\Contracts\Core\Repository\Events\Content\BeforeCreateContentEvent;
  9. use Ibexa\Contracts\Core\Repository\PermissionResolver;
  10. use Ibexa\Contracts\Core\Repository\Values\Content\ContentCreateStruct;
  11. use Ibexa\Contracts\Core\Repository\Values\User\UserReference;
  12. use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
  13. use Ibexa\Contracts\CorporateAccount\Exception\ApplicationRateLimitExceededException;
  14. use Ibexa\CorporateAccount\Configuration\CorporateAccountConfiguration;
  15. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  16. use Symfony\Component\HttpFoundation\RequestStack;
  17. use Symfony\Component\RateLimiter\RateLimiterFactory;
  18. /**
  19.  * @internal
  20.  */
  21. final class ApplicationRateLimitSubscriber implements EventSubscriberInterface
  22. {
  23.     private const RATE_LIMITER_KEY_PATTERN 'user_%d_ip_%s';
  24.     private RequestStack $requestStack;
  25.     private PermissionResolver $permissionResolver;
  26.     private CorporateAccountConfiguration $configuration;
  27.     private ConfigResolverInterface $configResolver;
  28.     private RateLimiterFactory $corporateAccountApplicationLimiter;
  29.     public function __construct(
  30.         RequestStack $requestStack,
  31.         PermissionResolver $permissionResolver,
  32.         ConfigResolverInterface $configResolver,
  33.         CorporateAccountConfiguration $configuration,
  34.         RateLimiterFactory $corporateAccountApplicationLimiter
  35.     ) {
  36.         $this->requestStack $requestStack;
  37.         $this->permissionResolver $permissionResolver;
  38.         $this->configResolver $configResolver;
  39.         $this->configuration $configuration;
  40.         $this->corporateAccountApplicationLimiter $corporateAccountApplicationLimiter;
  41.     }
  42.     public static function getSubscribedEvents(): array
  43.     {
  44.         return [
  45.             BeforeCreateContentEvent::class => ['onBeforeCreateContent'100],
  46.         ];
  47.     }
  48.     public function onBeforeCreateContent(BeforeCreateContentEvent $event): void
  49.     {
  50.         $contentCreateStruct $event->getContentCreateStruct();
  51.         $currentUser $this->permissionResolver->getCurrentUserReference();
  52.         if ($this->isApplicationCreateStruct($contentCreateStruct) && $this->isAnonymousUser($currentUser)) {
  53.             $mainRequest $this->requestStack->getMainRequest();
  54.             if ($mainRequest !== null) {
  55.                 $limiter $this->corporateAccountApplicationLimiter->create(
  56.                     sprintf(
  57.                         self::RATE_LIMITER_KEY_PATTERN,
  58.                         $currentUser->getUserId(),
  59.                         $mainRequest->getClientIp()
  60.                     )
  61.                 );
  62.                 if (!$limiter->consume()->isAccepted()) {
  63.                     throw new ApplicationRateLimitExceededException($limiter);
  64.                 }
  65.             }
  66.         }
  67.     }
  68.     private function isApplicationCreateStruct(ContentCreateStruct $contentCreateStruct): bool
  69.     {
  70.         return $contentCreateStruct->contentType->identifier
  71.             === $this->configuration->getApplicationContentTypeIdentifier();
  72.     }
  73.     private function isAnonymousUser(UserReference $userReference): bool
  74.     {
  75.         return $userReference->getUserId()
  76.             === $this->configResolver->getParameter('anonymous_user_id');
  77.     }
  78. }