<?php
namespace AppBundle\EventSubscriber;
use Exception;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\KernelEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use AppBundle\Security\Authentication\Token\JwtUserToken;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\JWTEncoderInterface;
use AppBundle\Entity\User\{UserSession, SessionLog, UserSessionLog};
use AppBundle\Utils\JWTTokenGenerator;
use Psr\Log\LoggerInterface;
/**
* Description of ResponseSubscriber
*
* look at https://symfony.com/doc/current/event_dispatcher.html#creating-an-event-subscriber
*
* @author SAWIT Mateusz Miklewski <biuro@sawit.pl>
*/
class ResponseSubscriber implements EventSubscriberInterface {
private $entityManager;
private $tokenStorage;
private $jwt_encoder;
private $generator;
private $logger;
static $HeadersSet = false;
public function __construct(EntityManagerInterface $entityManager, TokenStorageInterface $tokenStorage, JWTEncoderInterface $jwt_encoder, JWTTokenGenerator $generator, LoggerInterface $logger)
{
$this->entityManager = $entityManager;
$this->tokenStorage = $tokenStorage;
$this->jwt_encoder = $jwt_encoder;
$this->generator = $generator;
$this->logger = $logger;
}
public static function getSubscribedEvents(): array {
// return the subscribed events, their methods and priorities
return array(
KernelEvents::RESPONSE => array(
array('addOptionsHeader', 10),
array('addTokenHeader', 0),
array('doShrinkSource', 0),
array('cacheAssets', 0)
)
);
}
public function addOptionsHeader(KernelEvent $event) {
$request = $event->getRequest();
$method = $request->getMethod();
$response = $event->getResponse();
if(!self::$HeadersSet) {
$response->headers->set('Access-Control-Allow-Origin', '*');
$response->headers->set('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
$response->headers->set('Access-Control-Allow-Headers', 'Accept, Authorization, Content-Type, Token');
$response->headers->set('Access-Control-Expose-Headers', 'Token');
self::$HeadersSet = true;
}
$event->setResponse($response);
if ('OPTIONS' === $method) {
$event->stopPropagation();
return $response;
}
return null;
}
public function addTokenHeader(KernelEvent $event) {
$request = $event->getRequest();
$method = $request->getRealMethod();
if(!$this->entityManager->isOpen()) {
return;
}
$this->entityManager->clear();
if ('OPTIONS' !== $method) {
$token = $this->tokenStorage->getToken();
if($token instanceof JwtUserToken) {
try {
/* @var $session UserSession */
$session = $this->entityManager->getRepository(UserSession::class)->findOneBy(['token' => $token->nonce]);
if($session && !$session->getDeleted()) {
$generator = $this->generator;
$newToken = $generator->refreshToken($token);
$response = $event->getResponse();
$response->headers->set('Token', $newToken);
$event->setResponse($response);
$sessionLog = new UserSessionLog();
$sessionLog->setRequest($event->getRequest()->getRequestUri());
$sessionLog->setRequestType($event->getRequest()->getMethod());
$sessionLog->setUserSession($session);
$this->entityManager->persist($sessionLog);
$this->entityManager->flush();
}
} catch (Exception $e) {
$this->logger->error($e->getMessage(), $e->getTrace());
}
}
}
}
public function doShrinkSource(FilterResponseEvent $e){
$response = $e->getResponse();
$request = $e->getRequest();
if(strpos($request->getRequestUri(), '/api') === false && strpos($request->getRequestUri(), '/_profiler') === false && !$response instanceof BinaryFileResponse) {
$content = $response->getContent();
$html = preg_replace('/(\>)\s*(\<)/m', '$1$2', $content);
$html = preg_replace('/\r/', '', $html);
$html = preg_replace('/\n/', ' ', $html);
$html = preg_replace('/\t/', ' ', $html);
$html = preg_replace('/\s{2,}/', ' ', $html);
$response->setContent($html);
}
}
public function cacheAssets(FilterResponseEvent $event) {
$request = $event->getRequest();
if($request->getContentType() == 'text/css') {
$response = $event->getResponse();
$response->setSharedMaxAge(6*30*24*60*60); // 6 mies
}
}
}