custom/plugins/PickwareDhl/vendor/pickware/debug-bundle/src/ResponseExceptionListener/ResponseExceptionListenerDecorator.php line 55

Open in your IDE?
  1. <?php
  2. /*
  3.  * Copyright (c) Pickware GmbH. All rights reserved.
  4.  * This file is part of software that is released under a proprietary license.
  5.  * You must not copy, modify, distribute, make publicly available, or execute
  6.  * its contents or parts thereof without express permission by the copyright
  7.  * holder, unless otherwise permitted by law.
  8.  */
  9. declare(strict_types=1);
  10. namespace Pickware\DebugBundle\ResponseExceptionListener;
  11. use League\OAuth2\Server\Exception\OAuthServerException;
  12. use Psr\Log\LoggerInterface;
  13. use Shopware\Core\Framework\Api\EventListener\ResponseExceptionListener;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. use Symfony\Component\HttpFoundation\JsonResponse;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\HttpFoundation\Response;
  18. use Symfony\Component\HttpKernel\Event\ExceptionEvent;
  19. use Throwable;
  20. class ResponseExceptionListenerDecorator implements EventSubscriberInterface
  21. {
  22.     private ResponseExceptionListener $decoratedService;
  23.     private LoggerInterface $errorLogger;
  24.     private JwtValidator $jwtValidator;
  25.     /**
  26.      * We can't use a php type hint for the ResponseExceptionListener here since it does not implement an interface that
  27.      * contains the non-static methods, and it could be decorated by a different plugin as well.
  28.      *
  29.      * @param ResponseExceptionListener $decoratedService
  30.      */
  31.     public function __construct($decoratedServiceLoggerInterface $errorLoggerJwtValidator $jwtValidator)
  32.     {
  33.         $this->decoratedService $decoratedService;
  34.         $this->errorLogger $errorLogger;
  35.         $this->jwtValidator $jwtValidator;
  36.     }
  37.     /**
  38.      * Unfortunately, static methods can not be decorated, so we need to call the original method directly and hope that
  39.      * no other plugin wraps this method and changes its return value.
  40.      *
  41.      * @return array
  42.      */
  43.     public static function getSubscribedEvents()
  44.     {
  45.         return ResponseExceptionListener::getSubscribedEvents();
  46.     }
  47.     public function onKernelException(ExceptionEvent $originalEvent)
  48.     {
  49.         $event $this->decoratedService->onKernelException($originalEvent);
  50.         $exception $event->getThrowable();
  51.         if ($exception instanceof OAuthServerException) {
  52.             return $event;
  53.         }
  54.         if ($this->shouldAddTraceToResponse($event->getRequest(), $event->getResponse())) {
  55.             $event->setResponse($this->addTraceToResponse($event->getResponse(), $event->getThrowable()));
  56.         }
  57.         if ($this->shouldLogTrace($event->getRequest())) {
  58.             $this->errorLogger->error($exception->getMessage(), [
  59.                 'exception' => $this->getTrace($exception),
  60.             ]);
  61.         }
  62.         return $event;
  63.     }
  64.     private function shouldAddTraceToResponse(Request $request, ?Response $response): bool
  65.     {
  66.         if (!$this->containsValidDebugHeader($request)) {
  67.             return false;
  68.         }
  69.         if (!$response) {
  70.             return false;
  71.         }
  72.         if (!($response instanceof JsonResponse)) {
  73.             return false;
  74.         }
  75.         if ($response->getStatusCode() === 401) {
  76.             return false;
  77.         }
  78.         return true;
  79.     }
  80.     private function containsValidDebugHeader(Request $request): bool
  81.     {
  82.         $debugHeader $request->headers->get('X-Pickware-Show-Trace');
  83.         return $debugHeader && $this->jwtValidator->isJwtTokenValid($debugHeader);
  84.     }
  85.     private function addTraceToResponse(JsonResponse $responseThrowable $throwable): Response
  86.     {
  87.         $content json_decode($response->getContent(), true);
  88.         $content['trace'] = $this->getTrace($throwable);
  89.         $response->setData($content);
  90.         return $response;
  91.     }
  92.     private function shouldLogTrace(Request $request): bool
  93.     {
  94.         if ($this->containsValidDebugHeader($request)) {
  95.             return true;
  96.         }
  97.         if (mb_strpos($request->headers->get('User-Agent') ?? '''com.viison.pickware.POS') !== false) {
  98.             return true;
  99.         }
  100.         return false;
  101.     }
  102.     private function getTrace(Throwable $throwable): array
  103.     {
  104.         // Remove args so that no credentials are logged.
  105.         return array_map(function ($element) {
  106.             unset($element['args']);
  107.             return $element;
  108.         }, $throwable->getTrace());
  109.     }
  110. }