src/EventSubscriber/ResponseEncryptingSubscriber.php line 91

Open in your IDE?
  1. <?php
  2. /**
  3.  * @license Silk Software House Sp. Z O. O.
  4.  */
  5. declare(strict_types=1);
  6. namespace App\EventSubscriber;
  7. use App\Decoder\Interfaces\DecoderInterface;
  8. use App\Entity\DeviceCommand;
  9. use App\Repository\RecipeToSyncRepository;
  10. use Psr\Log\LoggerInterface;
  11. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\HttpKernel\Event\ResponseEvent;
  14. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  15. use Symfony\Component\HttpKernel\KernelEvents;
  16. /**
  17.  * Class ResponseEncryptingSubscriber.
  18.  */
  19. class ResponseEncryptingSubscriber implements EventSubscriberInterface
  20. {
  21.     const MAX_BUFFER_SIZE 400;
  22.     /**
  23.      * Decoder.
  24.      *
  25.      * @var DecoderInterface
  26.      */
  27.     private $decoder;
  28.     /**
  29.      * Device ping path.
  30.      *
  31.      * @var string[]
  32.      */
  33.     private $encryptedPaths;
  34.     /**
  35.      * @var RecipeToSyncRepository
  36.      */
  37.     private $recipeToSyncRepository;
  38.     /**
  39.      * @var LoggerInterface
  40.      */
  41.     private $logger;
  42.     /**
  43.      * ResponseEncryptingSubscriber constructor.
  44.      *
  45.      * @param DecoderInterface $decoder
  46.      * @param string[]         $encryptedPaths Array of encrypted paths.
  47.      */
  48.     public function __construct(
  49.         DecoderInterface $decoder,
  50.         array $encryptedPaths,
  51.         RecipeToSyncRepository $recipeToSyncRepository,
  52.         LoggerInterface $logger
  53.     )
  54.     {
  55.         $this->decoder $decoder;
  56.         $this->encryptedPaths $encryptedPaths;
  57.         $this->recipeToSyncRepository $recipeToSyncRepository;
  58.         $this->logger $logger;
  59.     }
  60.     /**
  61.      * Get subscribed events.
  62.      *
  63.      * @return array
  64.      */
  65.     public static function getSubscribedEvents(): array
  66.     {
  67.         return [
  68.             KernelEvents::RESPONSE => [
  69.                 ['onKernelResponse', -9999],
  70.             ],
  71.         ];
  72.     }
  73.     /**
  74.      * On kernel response.
  75.      *
  76.      * @param ResponseEvent $event
  77.      *
  78.      * @throws AccessDeniedHttpException
  79.      */
  80.     public function onKernelResponse(ResponseEvent $event)
  81.     {
  82.         if (!$event->isMasterRequest() || !in_array($event->getRequest()->getPathInfo(), $this->encryptedPaths)) {
  83.             return;
  84.         }
  85.         $serial $event->getResponse()->headers->get('serial');
  86.         $payload json_decode($event->getResponse()->getContent(), true) ?? [];
  87.         $command $payload[DeviceCommand::COMMAND_KEY] ?? DeviceCommand::NO_COMMAND;
  88.         $plainContent $event->getResponse()->getContent();
  89.         if ($serial) {
  90.             $event->getResponse()->headers->remove('serial');
  91.         }
  92.         $encrypted $this->decoder->encrypt($plainContent$serial);
  93.         $response $event->getResponse();
  94.         $response->setContent($encrypted);
  95.         $response->headers->remove('Content-Type');
  96.         $response->headers->add(['Content-Type' => 'text/plain']);
  97.         if (strlen($encrypted) > self::MAX_BUFFER_SIZE) {
  98.             $this->logger->warning('Encrypted device response exceeds modem buffer.', [
  99.                 'path' => $event->getRequest()->getPathInfo(),
  100.                 'serial' => $serial,
  101.                 'command' => $command,
  102.                 'plain_length' => strlen($plainContent),
  103.                 'encrypted_length' => strlen($encrypted),
  104.                 'status' => $response->getStatusCode(),
  105.                 'payload' => $payload,
  106.             ]);
  107.             $response->setStatusCode(Response::HTTP_REQUEST_ENTITY_TOO_LARGE);
  108.             $contentWhereSizeFailed json_encode(['cmd' => DeviceCommand::NO_COMMAND]);
  109.             $response->setContent($this->decoder->encrypt($contentWhereSizeFailed$serial));
  110.         } elseif (
  111.             $response->getStatusCode() >= Response::HTTP_OK
  112.             && $response->getStatusCode() < Response::HTTP_MULTIPLE_CHOICES
  113.             && $command === DeviceCommand::SET_RECIPE
  114.             && !empty($serial)
  115.         ) {
  116.             $this->recipeToSyncRepository->findFirstBySerialNumberAndRemove($serial);
  117.         }
  118.         $event->setResponse($response);
  119.     }
  120. }