vendor/ibexa/user/src/bundle/Controller/PasswordResetController.php line 81

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4.  * @license For full copyright and license information view LICENSE file distributed with this source code.
  5.  */
  6. declare(strict_types=1);
  7. namespace Ibexa\Bundle\User\Controller;
  8. use DateInterval;
  9. use DateTime;
  10. use Ibexa\Bundle\User\Type\UserForgotPasswordReason;
  11. use Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException;
  12. use Ibexa\Contracts\Core\Repository\PermissionResolver;
  13. use Ibexa\Contracts\Core\Repository\UserService;
  14. use Ibexa\Contracts\Core\Repository\Values\User\User;
  15. use Ibexa\Contracts\Core\Repository\Values\User\UserTokenUpdateStruct;
  16. use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
  17. use Ibexa\User\ExceptionHandler\ActionResultHandler;
  18. use Ibexa\User\Form\Data\UserPasswordResetData;
  19. use Ibexa\User\Form\Factory\FormFactory;
  20. use Ibexa\User\View\ForgotPassword\FormView;
  21. use Ibexa\User\View\ForgotPassword\LoginView;
  22. use Ibexa\User\View\ForgotPassword\SuccessView;
  23. use Ibexa\User\View\ResetPassword\FormView as UserResetPasswordFormView;
  24. use Ibexa\User\View\ResetPassword\InvalidLinkView;
  25. use Ibexa\User\View\ResetPassword\SuccessView as UserResetPasswordSuccessView;
  26. use Swift_Mailer;
  27. use Swift_Message;
  28. use Symfony\Component\HttpFoundation\Request;
  29. use Symfony\Component\HttpFoundation\Response;
  30. use Twig\Environment;
  31. class PasswordResetController extends Controller
  32. {
  33.     /** @var \Ibexa\User\Form\Factory\FormFactory */
  34.     private $formFactory;
  35.     /** @var \Ibexa\Contracts\Core\Repository\UserService */
  36.     private $userService;
  37.     /** @var \Swift_Mailer */
  38.     private $mailer;
  39.     /** @var \Twig\Environment */
  40.     private $twig;
  41.     /** @var \Ibexa\User\ExceptionHandler\ActionResultHandler */
  42.     private $actionResultHandler;
  43.     /** @var \Ibexa\Contracts\Core\Repository\PermissionResolver */
  44.     private $permissionResolver;
  45.     /** @var \Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface */
  46.     private $configResolver;
  47.     public function __construct(
  48.         FormFactory $formFactory,
  49.         UserService $userService,
  50.         Swift_Mailer $mailer,
  51.         Environment $twig,
  52.         ActionResultHandler $actionResultHandler,
  53.         PermissionResolver $permissionResolver,
  54.         ConfigResolverInterface $configResolver
  55.     ) {
  56.         $this->formFactory $formFactory;
  57.         $this->userService $userService;
  58.         $this->mailer $mailer;
  59.         $this->twig $twig;
  60.         $this->actionResultHandler $actionResultHandler;
  61.         $this->permissionResolver $permissionResolver;
  62.         $this->configResolver $configResolver;
  63.     }
  64.     /**
  65.      * @return \Ibexa\User\View\ForgotPassword\FormView|\Ibexa\User\View\ForgotPassword\SuccessView|\Symfony\Component\HttpFoundation\RedirectResponse
  66.      *
  67.      * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType
  68.      */
  69.     public function userForgotPasswordAction(Request $request, ?string $reason null)
  70.     {
  71.         $form $this->formFactory->forgotUserPassword();
  72.         $form->handleRequest($request);
  73.         if ($form->isSubmitted() && $form->isValid()) {
  74.             $data $form->getData();
  75.             $users $this->userService->loadUsersByEmail($data->getEmail());
  76.             /** Because is is possible to have multiple user accounts with same email address we must gain a user login. */
  77.             if (\count($users) > 1) {
  78.                 return $this->redirectToRoute('ibexa.user.forgot_password.login');
  79.             }
  80.             if (!empty($users)) {
  81.                 $user reset($users);
  82.                 $token $this->updateUserToken($user);
  83.                 $this->sendResetPasswordMessage($user->email$token);
  84.             }
  85.             return new SuccessView(null);
  86.         }
  87.         return new FormView(null, [
  88.             'form_forgot_user_password' => $form->createView(),
  89.             'reason' => $reason,
  90.             'userForgotPasswordReasonMigration' => UserForgotPasswordReason::MIGRATION,
  91.         ]);
  92.     }
  93.     /**
  94.      * @param \Symfony\Component\HttpFoundation\Request $request
  95.      *
  96.      * @return \Ibexa\User\View\ForgotPassword\LoginView|\Ibexa\User\View\ForgotPassword\SuccessView
  97.      *
  98.      * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType
  99.      */
  100.     public function userForgotPasswordLoginAction(Request $request)
  101.     {
  102.         $form $this->formFactory->forgotUserPasswordWithLogin();
  103.         $form->handleRequest($request);
  104.         if ($form->isSubmitted() && $form->isValid()) {
  105.             $data $form->getData();
  106.             try {
  107.                 $user $this->userService->loadUserByLogin($data->getLogin());
  108.             } catch (NotFoundException $e) {
  109.                 $user null;
  110.             }
  111.             if (!$user || \count($this->userService->loadUsersByEmail($user->email)) < 2) {
  112.                 return new SuccessView(null);
  113.             }
  114.             $token $this->updateUserToken($user);
  115.             $this->sendResetPasswordMessage($user->email$token);
  116.             return new SuccessView(null);
  117.         }
  118.         return new LoginView(null, [
  119.             'form_forgot_user_password_with_login' => $form->createView(),
  120.         ]);
  121.     }
  122.     /**
  123.      * @param \Symfony\Component\HttpFoundation\Request $request
  124.      * @param string $hashKey
  125.      *
  126.      * @return \Ibexa\User\View\ResetPassword\FormView|\Ibexa\User\View\ResetPassword\InvalidLinkView|\Ibexa\User\View\ResetPassword\SuccessView
  127.      *
  128.      * @throws \Ibexa\Core\Base\Exceptions\InvalidArgumentType
  129.      */
  130.     public function userResetPasswordAction(Request $requeststring $hashKey)
  131.     {
  132.         $response = new Response();
  133.         $response->headers->set('X-Robots-Tag''noindex');
  134.         try {
  135.             $user $this->userService->loadUserByToken($hashKey);
  136.         } catch (NotFoundException $e) {
  137.             $view = new InvalidLinkView(null);
  138.             $view->setResponse($response);
  139.             return $view;
  140.         }
  141.         $userPasswordResetData = new UserPasswordResetData();
  142.         $form $this->formFactory->resetUserPassword($userPasswordResetDatanull$user->getContentType());
  143.         $form->handleRequest($request);
  144.         if ($form->isSubmitted() && $form->isValid()) {
  145.             try {
  146.                 $currentUser $this->permissionResolver->getCurrentUserReference();
  147.                 $this->permissionResolver->setCurrentUserReference($user);
  148.             } catch (NotFoundException $e) {
  149.                 $view = new InvalidLinkView(null);
  150.                 $view->setResponse($response);
  151.                 return $view;
  152.             }
  153.             $data $form->getData();
  154.             try {
  155.                 $this->userService->updateUserPassword($user$data->getNewPassword());
  156.                 $this->userService->expireUserToken($hashKey);
  157.                 $this->permissionResolver->setCurrentUserReference($currentUser);
  158.                 $view = new UserResetPasswordSuccessView(null);
  159.                 $view->setResponse($response);
  160.                 return $view;
  161.             } catch (\Exception $e) {
  162.                 $this->actionResultHandler->error($e->getMessage());
  163.             }
  164.         }
  165.         $view = new UserResetPasswordFormView(null, [
  166.             'form_reset_user_password' => $form->createView(),
  167.         ]);
  168.         $view->setResponse($response);
  169.         return $view;
  170.     }
  171.     /**
  172.      * @param \Ibexa\Contracts\Core\Repository\Values\User\User $user
  173.      *
  174.      * @return string
  175.      *
  176.      * @throws \Exception
  177.      */
  178.     private function updateUserToken(User $user): string
  179.     {
  180.         $struct = new UserTokenUpdateStruct();
  181.         $struct->hashKey bin2hex(random_bytes(16));
  182.         $date = new DateTime();
  183.         $date->add(new DateInterval($this->configResolver->getParameter('security.token_interval_spec')));
  184.         $struct->time $date;
  185.         $this->userService->updateUserToken($user$struct);
  186.         return $struct->hashKey;
  187.     }
  188.     private function sendResetPasswordMessage(string $tostring $hashKey): void
  189.     {
  190.         $template $this->twig->load($this->configResolver->getParameter('user_forgot_password.templates.mail'));
  191.         $senderAddress $this->configResolver->hasParameter('sender_address''swiftmailer.mailer')
  192.             ? $this->configResolver->getParameter('sender_address''swiftmailer.mailer')
  193.             : '';
  194.         $subject $template->renderBlock('subject', []);
  195.         $from $template->renderBlock('from', []) ?: $senderAddress;
  196.         $body $template->renderBlock('body', ['hash_key' => $hashKey]);
  197.         $message = (new Swift_Message())
  198.             ->setSubject($subject)
  199.             ->setTo($to)
  200.             ->setBody($body'text/html');
  201.         if (empty($from) === false) {
  202.             $message->setFrom($from);
  203.         }
  204.         $this->mailer->send($message);
  205.     }
  206. }
  207. class_alias(PasswordResetController::class, 'EzSystems\EzPlatformUserBundle\Controller\PasswordResetController');