src/EventSubscriber/ApiRequestSubscriber.php line 68

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\EventSubscriber;
  4. use App\Checker\RateLimiterChecker;
  5. use App\Entity\Admin\SourceInterface;
  6. use App\Entity\Device\DeviceInterface;
  7. use App\Entity\Franchise\FranchiseInterface;
  8. use App\Entity\Security\Manager;
  9. use App\Entity\Security\ShopManager;
  10. use App\Entity\Security\UserInterface;
  11. use App\Exception\Device\InvalidDeviceTokenException;
  12. use App\Exception\Global\SourceMandatoryException;
  13. use App\Helper\Response\DeviceResponseInterface;
  14. use App\Helper\Response\FranchiseResponseInterface;
  15. use App\Helper\Response\ResponseInterface as CustomResponseInterface;
  16. use App\Helper\Response\ShopResponseInterface;
  17. use App\Repository\Franchise\FranchiseRepository;
  18. use App\Repository\Shop\DeviceRepository;
  19. use App\Repository\Shop\ShopRepository;
  20. use App\Verifier\Shop\LicenceVerifier;
  21. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use Symfony\Component\HttpKernel\Event\RequestEvent;
  24. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  25. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  26. use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
  27. use Symfony\Component\Security\Core\Security;
  28. class ApiRequestSubscriber implements EventSubscriberInterface
  29. {
  30.     public const API_VERSION_200 = '2.0.0';
  31.     public const API_VERSIONS = [
  32.         self::API_VERSION_200,
  33.     ];
  34.     private array $authorizedRoutes = [
  35.         'api_login_check',
  36.         'api_users_request_request_password_collection',
  37.         'api_users_check_password_reset_token_collection',
  38.         'api_users_reset_password_collection',
  39.         'api_entrypoint',
  40.         'api_doc',
  41.         'foxorders_api_',
  42.         'foxorders_api_doc',
  43.     ];
  44.     public function __construct(
  45.         private $devicePinDev,
  46.         private Security $security,
  47.         private RateLimiterChecker $rateLimiterChecker,
  48.         private DeviceRepository $deviceRepository,
  49.         private FranchiseRepository $franchiseRepository,
  50.         private ShopRepository $shopRepository,
  51.         private LicenceVerifier $licenceVerifier,
  52.     ) {
  53.     }
  54.     public static function getSubscribedEvents(): array
  55.     {
  56.         return [
  57.             RequestEvent::class => ['onKernelRequest', 6],
  58.         ];
  59.     }
  60.     public function onKernelRequest(RequestEvent $event)
  61.     {
  62.         $request = $event->getRequest();
  63.         $route = $request->attributes->get('_route');
  64.         $source = $request->headers->get('source');
  65.         $version = $request->headers->get('version');
  66.         $franchiseToken = $request->headers->get('franchise-token');
  67.         $devicePinDev = $request->headers->get('device-pin-dev');
  68.         $shopToken = $request->headers->get('shop-token');
  69.         $identifier = $request->headers->get('device-token');
  70.         $isValidSource = $request->attributes->get('source-valid');
  71.         $isApiRoute = null !== $route && str_contains($route, 'api_') && false === str_starts_with($route, 'foxorders_documentation');
  72.         $user = $this->security->getUser();
  73.         if (false === $isApiRoute) {
  74.             return true;
  75.         }
  76.         $accountType = $request->headers->get('account-type', UserInterface::ACCOUNT_TYPE_STAFF);
  77.         if (false === \in_array($accountType, UserInterface::ACCOUNT_TYPES, true)) {
  78.             return true;
  79.         }
  80.         $request->headers->set('account-type', $accountType);
  81.         if (true === \in_array($route, $this->authorizedRoutes, true)) {
  82.             return true;
  83.         }
  84.         $this->rateLimiterChecker->checkRate();
  85.         if (null === $user) {
  86.             throw new AccessDeniedHttpException(Response::$statusTexts[Response::HTTP_FORBIDDEN]);
  87.         }
  88.         if (null === $source) {
  89.             throw new SourceMandatoryException();
  90.         }
  91.         if (null === $version) {
  92.             throw new BadRequestHttpException(CustomResponseInterface::API_VERSION_MANDATORY);
  93.         }
  94.         if (false === \in_array($version, self::API_VERSIONS, true)) {
  95.             throw new BadRequestHttpException(CustomResponseInterface::API_VERSION_INVALID);
  96.         }
  97.         if (false === $isValidSource) {
  98.             throw new BadRequestHttpException(CustomResponseInterface::SOURCE_INVALID);
  99.         }
  100.         $franchise = $shop = $device = null;
  101.         if ($user instanceof Manager) {
  102.             $franchise = $user->getFranchise();
  103.         } elseif ($user instanceof ShopManager) {
  104.             $shop = $user->getShop();
  105.             $device = $user->getDevice();
  106.             $franchise = $shop->getFranchise();
  107.             $shopToken = $shop->getToken();
  108.             $request->headers->set('shop-token', $shopToken);
  109.         }
  110.         $franchiseToken = $franchise?->getToken() ?? $franchiseToken;
  111.         if (null === $franchiseToken && !\in_array($route, FranchiseInterface::ENDPOINTS_WITHOUT_TOKEN, true)) {
  112.             throw new BadRequestHttpException(FranchiseResponseInterface::FRANCHISE_TOKEN_REQUIRED);
  113.         }
  114.         if (null !== $franchise) {
  115.             $request->headers->set('franchise-token', $franchise->getToken());
  116.         }
  117.         if (null === $franchise && null !== $franchiseToken) {
  118.             $franchise = $this->franchiseRepository->findOneBy(['token' => $franchiseToken]);
  119.             if (null === $franchise) {
  120.                 throw new BadRequestHttpException(FranchiseResponseInterface::FRANCHISE_TOKEN_INVALID);
  121.             }
  122.         }
  123.         if (null === $shop && null !== $shopToken && null !== $franchiseToken) {
  124.             if (false === $this->shopRepository->isMatchedShopTokenFranchiseToken($franchiseToken, $shopToken)) {
  125.                 throw new BadRequestHttpException(ShopResponseInterface::SHOP_TOKEN_INVALID);
  126.             }
  127.         }
  128.         if (null !== $franchise && FranchiseInterface::STATUS_DISABLED === $franchise->getStatus()) {
  129.             throw new AccessDeniedHttpException(CustomResponseInterface::BLOCKED_ACCOUNT);
  130.         }
  131.         if (false === $this->licenceVerifier->verify()) {
  132.             throw new UnauthorizedHttpException('Unauthorized access', CustomResponseInterface::ACCESS_DENIED);
  133.         }
  134.         if (SourceInterface::SOURCE_FOXORDERS_FRONT === $source && null !== $shopToken) {
  135.             $device = $this->deviceRepository->defaultDevice($shopToken);
  136.             if (null === $device) {
  137.                 throw new InvalidDeviceTokenException();
  138.             }
  139.             $request->headers->set('device-token', $device->getToken());
  140.             return true;
  141.         }
  142.         if ($this->devicePinDev === $devicePinDev) {
  143.             return;
  144.         }
  145.         if (false === \in_array($source, SourceInterface::DEVICE_SOURCES, true) || true === \in_array($route, DeviceInterface::WHITELISTED_DEVICE_ENDPOINTS, true)) {
  146.             return true;
  147.         }
  148.         // if (null === $identifier || '' === trim($identifier)) {
  149.         //     throw new UnauthorizedHttpException('Unauthorized access', DeviceResponseInterface::UNRECOGNIZED_DEVICE);
  150.         // }
  151.         // $device = $this->deviceRepository->findOneByFranchiseTokenAndIdentifier($franchiseToken, $identifier);
  152.         // if (null === $device) {
  153.         //     throw new UnauthorizedHttpException('Unauthorized access', DeviceResponseInterface::UNRECOGNIZED_DEVICE);
  154.         // }
  155.         // $request->headers->set('device-token', $device->getToken());
  156.         if (null !== $identifier && '' !== trim($identifier)) {
  157.             $device = $this->deviceRepository->findOneByFranchiseTokenAndIdentifier($franchiseToken, $identifier);
  158.             if (null !== $device) {
  159.                 $request->headers->set('device-token', $device->getToken());
  160.             }
  161.         }
  162.     }
  163. }