<?phpdeclare(strict_types=1);namespace App\Module\Cms\Subscriber;use Exception;use Symfony\Component\EventDispatcher\EventSubscriberInterface;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpKernel\Event\RequestEvent;use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;use Symfony\Component\HttpKernel\KernelEvents;/** * Class PreviewSubscriber * * @package App\Module\Cms\Subscriber */class PreviewSubscriber implements EventSubscriberInterface{ /** * VALIDATION_TOKEN_LIFETIME */ private const VALIDATION_TOKEN_LIFETIME = 9000; private string $previewToken; /** * PreviewSubscriber constructor. * * @param string $previewToken */ public function __construct(string $previewToken) { $this->previewToken = $previewToken; } /** * @return array[][] */ public static function getSubscribedEvents(): array { return [ KernelEvents::REQUEST => [ ['onKernelRequest', 32], ], ]; } /** * @param RequestEvent $event * @throws Exception * @return void */ public function onKernelRequest(RequestEvent $event): void { if (!$event->isMasterRequest()) { return; } $request = $event->getRequest(); if ($request->getPathInfo() !== '/preview') { return; } if (!$this->hasValidToken($request)) { throw new AccessDeniedHttpException('Token missing or invalid!'); } } /** * @param Request $request * @return string */ private function generateValidationToken(Request $request): string { $tokenData = $request->query->get('_storyblok_tk'); $rawToken = sprintf('%s:%s:%s', $tokenData['space_id'], $this->previewToken, $tokenData['timestamp']); return sha1($rawToken); } /** * @param Request $request * @return bool */ private function hasValidToken(Request $request): bool { $tokenData = $request->query->get('_storyblok_tk'); $tokenTimestamp = (int) ($tokenData['timestamp'] ?? 0); if ($tokenTimestamp === 0 || $tokenTimestamp < (strtotime('now') - self::VALIDATION_TOKEN_LIFETIME)) { throw new AccessDeniedHttpException('Expired - tokenTimestamp: ' . $tokenTimestamp . ' expirationDate: ' . (strtotime('now') - self::VALIDATION_TOKEN_LIFETIME)); } $token = $tokenData['token'] ?? null; if ($token === null || $token !== $this->generateValidationToken($request)) { throw new AccessDeniedHttpException('Invalid token - delivered: ' . $token . ' expected: ' . $this->generateValidationToken($request)); } return true; }}