vendor/symfonycasts/verify-email-bundle/src/VerifyEmailHelper.php line 42

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the SymfonyCasts VerifyEmailBundle package.
  4. * Copyright (c) SymfonyCasts <https://symfonycasts.com/>
  5. * For the full copyright and license information, please view the LICENSE
  6. * file that was distributed with this source code.
  7. */
  8. namespace SymfonyCasts\Bundle\VerifyEmail;
  9. use Symfony\Component\HttpFoundation\Request;
  10. use Symfony\Component\HttpFoundation\UriSigner;
  11. use Symfony\Component\HttpKernel\UriSigner as LegacyUriSigner;
  12. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  13. use SymfonyCasts\Bundle\VerifyEmail\Exception\ExpiredSignatureException;
  14. use SymfonyCasts\Bundle\VerifyEmail\Exception\InvalidSignatureException;
  15. use SymfonyCasts\Bundle\VerifyEmail\Exception\WrongEmailVerifyException;
  16. use SymfonyCasts\Bundle\VerifyEmail\Generator\VerifyEmailTokenGenerator;
  17. use SymfonyCasts\Bundle\VerifyEmail\Model\VerifyEmailSignatureComponents;
  18. use SymfonyCasts\Bundle\VerifyEmail\Util\VerifyEmailQueryUtility;
  19. /**
  20. * @author Jesse Rushlow <[email protected]>
  21. * @author Ryan Weaver <[email protected]>
  22. */
  23. final class VerifyEmailHelper implements VerifyEmailHelperInterface
  24. {
  25. private $router;
  26. /**
  27. * @var UriSigner|LegacyUriSigner
  28. */
  29. private $uriSigner;
  30. private $queryUtility;
  31. private $tokenGenerator;
  32. /**
  33. * @var int The length of time in seconds that a signed URI is valid for after it is created
  34. */
  35. private $lifetime;
  36. public function __construct(UrlGeneratorInterface $router, /* no typehint for BC with legacy PHP */ $uriSigner, VerifyEmailQueryUtility $queryUtility, VerifyEmailTokenGenerator $generator, int $lifetime)
  37. {
  38. $this->router = $router;
  39. $this->uriSigner = $uriSigner;
  40. $this->queryUtility = $queryUtility;
  41. $this->tokenGenerator = $generator;
  42. $this->lifetime = $lifetime;
  43. if (!$uriSigner instanceof UriSigner) {
  44. /** @psalm-suppress UndefinedFunction */
  45. @trigger_deprecation('symfonycasts/verify-email-bundle', '1.17.0', 'Not providing an instance of %s is deprecated. It will be required in v2.0', UriSigner::class);
  46. }
  47. }
  48. public function generateSignature(string $routeName, string $userId, string $userEmail, array $extraParams = []): VerifyEmailSignatureComponents
  49. {
  50. $generatedAt = time();
  51. $expiryTimestamp = $generatedAt + $this->lifetime;
  52. $extraParams['token'] = $this->tokenGenerator->createToken($userId, $userEmail);
  53. $extraParams['expires'] = $expiryTimestamp;
  54. $uri = $this->router->generate($routeName, $extraParams, UrlGeneratorInterface::ABSOLUTE_URL);
  55. $signature = $this->uriSigner->sign($uri);
  56. /** @psalm-suppress PossiblyFalseArgument */
  57. return new VerifyEmailSignatureComponents(\DateTimeImmutable::createFromFormat('U', (string) $expiryTimestamp), $signature, $generatedAt);
  58. }
  59. public function validateEmailConfirmation(string $signedUrl, string $userId, string $userEmail): void
  60. {
  61. /** @psalm-suppress UndefinedFunction */
  62. @trigger_deprecation('symfonycasts/verify-email-bundle', '1.17.0', '%s() is deprecated and will be removed in v2.0, use validateEmailConfirmationFromRequest() instead.', __METHOD__);
  63. if (!$this->uriSigner->check($signedUrl)) {
  64. throw new InvalidSignatureException();
  65. }
  66. if ($this->queryUtility->getExpiryTimestamp($signedUrl) <= time()) {
  67. throw new ExpiredSignatureException();
  68. }
  69. $knownToken = $this->tokenGenerator->createToken($userId, $userEmail);
  70. $userToken = $this->queryUtility->getTokenFromQuery($signedUrl);
  71. if (!hash_equals($knownToken, $userToken)) {
  72. throw new WrongEmailVerifyException();
  73. }
  74. }
  75. public function validateEmailConfirmationFromRequest(Request $request, string $userId, string $userEmail): void
  76. {
  77. /** @legacy - Remove in 2.0 */
  78. if (!$this->uriSigner instanceof UriSigner) {
  79. throw new \RuntimeException(\sprintf('An instance of %s is required, provided by symfony/http-kernel >=6.4, to validate an email confirmation.', UriSigner::class));
  80. }
  81. if (!$this->uriSigner->checkRequest($request)) {
  82. throw new InvalidSignatureException();
  83. }
  84. if ($request->query->getInt('expires') <= time()) {
  85. throw new ExpiredSignatureException();
  86. }
  87. $knownToken = $this->tokenGenerator->createToken($userId, $userEmail);
  88. if (!hash_equals($knownToken, $request->query->getString('token'))) {
  89. throw new WrongEmailVerifyException();
  90. }
  91. }
  92. }