src/Twig/Functions/DownloadExtension.php line 70

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Twig\Functions;
  4. use App\Subscriber\DownloadTokenSubscriber;
  5. use Lcobucci\Clock\SystemClock;
  6. use Lcobucci\JWT\Encoding\CannotDecodeContent;
  7. use Lcobucci\JWT\Encoding\JoseEncoder;
  8. use Lcobucci\JWT\Signer\Hmac\Sha256;
  9. use Lcobucci\JWT\Signer\Key\InMemory;
  10. use Lcobucci\JWT\Token\InvalidTokenStructure;
  11. use Lcobucci\JWT\Token\Parser;
  12. use Lcobucci\JWT\Validation\Constraint\LooseValidAt;
  13. use Lcobucci\JWT\Validation\Constraint\SignedWith;
  14. use Lcobucci\JWT\Validation\Validator;
  15. use Psr\Log\LoggerInterface;
  16. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  17. use Twig\Extension\AbstractExtension;
  18. use Twig\TwigFunction;
  19. use TypeError;
  20. /**
  21. * Class DownloadExtension
  22. *
  23. * @package App\Twig\Functions
  24. */
  25. class DownloadExtension extends AbstractExtension
  26. {
  27. private string $downloadBaseUrl;
  28. private string $jwtPrivateKey;
  29. private LoggerInterface $logger;
  30. private SessionInterface $session;
  31. /**
  32. * DownloadExtension constructor.
  33. *
  34. * @param SessionInterface $session
  35. * @param string $downloadBaseUrl
  36. * @param string $jwtPrivateKey
  37. */
  38. public function __construct(SessionInterface $session, string $downloadBaseUrl, string $jwtPrivateKey, LoggerInterface $logger)
  39. {
  40. $this->session = $session;
  41. $this->downloadBaseUrl = $downloadBaseUrl;
  42. $this->jwtPrivateKey = $jwtPrivateKey;
  43. $this->logger = $logger;
  44. }
  45. /**
  46. * @return TwigFunction[]
  47. */
  48. public function getFunctions(): array
  49. {
  50. return [
  51. new TwigFunction('isAssetDownloadAllowed', [$this, 'isAssetDownloadAllowed']),
  52. new TwigFunction('getAssetDownloadUrl', [$this, 'getAssetDownloadUrl']),
  53. ];
  54. }
  55. /**
  56. * @return bool
  57. */
  58. public function isAssetDownloadAllowed(): bool
  59. {
  60. if (!$this->session->has(DownloadTokenSubscriber::SESSION_KEY_DOWNLOAD_TOKEN)) {
  61. return false;
  62. }
  63. $downloadToken = $this->session->get(DownloadTokenSubscriber::SESSION_KEY_DOWNLOAD_TOKEN);
  64. try {
  65. $parsedToken = (new Parser(new JoseEncoder()))->parse($downloadToken);
  66. } catch (TypeError $e) {
  67. $this->logger->warning('The token is invalid. Error: TypeError', ['downloadToken' => $downloadToken]);
  68. return false;
  69. } catch (CannotDecodeContent $e) {
  70. $this->logger->warning('The token is invalid. Error: CannotDecodeContent', ['downloadToken' => $downloadToken]);
  71. return false;
  72. } catch (InvalidTokenStructure $e) {
  73. $this->logger->warning('The token is invalid. Error: InvalidTokenStructure', ['downloadToken' => $downloadToken]);
  74. return false;
  75. }
  76. $constraints = [
  77. new SignedWith(new Sha256(), InMemory::plainText($this->jwtPrivateKey)),
  78. new LooseValidAt(SystemClock::fromSystemTimezone()),
  79. ];
  80. $valid = (new Validator())->validate($parsedToken, ...$constraints);
  81. if (!$valid) {
  82. $this->logger->warning('The token is invalid. Maybe it\'s expired or the jwtPrivateKey ist wrong configured.');
  83. }
  84. return $valid;
  85. }
  86. /**
  87. * @param array $asset
  88. * @return string
  89. */
  90. public function getAssetDownloadUrl(array $asset): string
  91. {
  92. $downloadToken = $this->session->get(DownloadTokenSubscriber::SESSION_KEY_DOWNLOAD_TOKEN);
  93. return $this->downloadBaseUrl . $asset['id'] . '?downloadToken=' . $downloadToken;
  94. }
  95. }