<?php
namespace App\Controller\Main;
use App\Entity\Main\User;
use App\Events\Main\Registration\SecurityEvent;
use App\Events\Main\Resetting\ResetEvent;
use App\EventSubscribers\Main\ResettingSubscriber;
use App\EventSubscribers\Main\SecuritySubscriber;
use App\Model\TokenGenerator\TokenGenerator;
use App\Services\EmailManager;
use App\Services\UserManager;
use App\Services\SecurityManager;
use Predis\Client;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* Controller managing the resetting of the password.
*
* @Route(
* condition="not (context.getHost() matches '%coaching_domain.host.regexp%')"
* )
*
*/
class ResettingController extends AbstractController
{
use BrulafineControllerTrait;
const AUTOLOGIN_ATTEMPTS_REDIS_KEY = "autologin_link_request_";
/**
* Request reset user password: show form.
*
* @Route("/resseting/request", name="user_resetting_request")
*/
public function requestAction()
{
$setup = $this->getSetup();
return $this->render($this->getTemplatesDir() . '/Security/views/Resetting/request.html.twig', [
'csrf_token' => $this->getLoginCsrfToken(),
'tracking' => $setup->getTracking(),
'site' => $setup->getSite(),
]);
}
/**
* Request reset user password: submit form and send email.
*
* @Route ("/resetting/send-email", name="user_resetting_send_email")
* @param Request $request
*
* @param UserManager $securityManager
* @param EmailManager $emailFactory
* @return Response
* @throws \Exception
*/
public function sendEmailAction(Request $request, UserManager $securityManager, EmailManager $emailFactory, EventDispatcherInterface $dispatcher)
{
$username = $request->request->get('username');
/** @var User $user */
$user = $securityManager->findUserByUsernameOrEmail($username);
//$ttl = $this->container->getParameter('fos_user.resetting.retry_ttl');
$ttl = 1;
if (null !== $user && !$user->isPasswordRequestNonExpired($ttl)) {
$event = new ResetEvent($user, $request);
$dispatcher->dispatch($event, ResettingSubscriber::RESETTING_RESET_REQUEST);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
if (null === $user->getConfirmationToken()) {
$tokenGenerator = new TokenGenerator();
$user->setConfirmationToken($tokenGenerator->generateToken());
}
// Define here landing page for the autologin.
$destination = $this->getParameter('reset_pw_autologin_destination') ?? null;
$emailFactory->sendAutoLoginEmailMessage($user, $destination);
$user->setPasswordRequestedAt(new \DateTime());
$securityManager->updateUser($user);
}
return new RedirectResponse($this->generateUrl('user_resetting_check_email', ['username' => $username]));
}
/**
* Tell the user to check his email provider.
*
* @param Request $request
*
* @Route ("/resseting/check-email", name="user_resetting_check_email")
* @return Response
*/
public function checkEmailAction(Request $request)
{
$username = $request->query->get('username');
if (empty($username)) {
// the user does not come from the sendEmail action
return new RedirectResponse($this->generateUrl('user_resetting_request'));
}
$setup = $this->getSetup();
return $this->render($this->getTemplatesDir() . '/Security/views/Resetting/check.html.twig', [
'csrf_token' => $this->getLoginCsrfToken(),
'tracking' => $setup->getTracking(),
'site' => $setup->getSite(),
]);
}
/**
* @param Request $request
* @param $token
* @param $dest
* @param LoggerInterface $logger
* @param SecurityManager $securityManager
* @return RedirectResponse
*/
public function autoLoginAction(Request $request, $token, $dest, LoggerInterface $logger, UserManager $securityManager, EventDispatcherInterface $eventDispatcher, $redisClient)
{
$environment = $this->getParameter("kernel.environment");
$redisKey = self::AUTOLOGIN_ATTEMPTS_REDIS_KEY . $request->getClientIp();
// prevent brut force attacks by limiting to 50 calls on this address by the same IP.
$redisClient->setex($redisKey, 3600, ((int) $redisClient->get($redisKey) + 1));
if ((int) $redisClient->get($redisKey) > 50 && 'test' != $environment) {
$this->addFlash("error", "flashMessages.site.linkNoValid");
$logger->alert("Someone is trying to bruteforce the autologin url, IP {$request->getClientIp()}, number of tries so far : {$redisClient->get($redisKey)}");
return new RedirectResponse($this->generateUrl("brulafine_shipping"));
}
// first check if user is already logged in.
$currentUser = $this->getUser();
if ($currentUser instanceof User) {
return $this->redirectToRoute($this->getRouteToRedirect($dest));
}
$user = $securityManager->findUserByConfirmationToken($token);
if (!$user instanceof User) {
$this->addFlash("error", "flashMessages.site.linkNoValid");
return new RedirectResponse($this->generateUrl("brulafine_shipping"));
}
// check if reset request exists.
$event = new ResetEvent($user, $request);
$eventDispatcher->dispatch($event, ResettingSubscriber::RESETTING_RESET_INITIALIZE);
if (null !== $event->getResponse()) {
$this->addFlash("error", "flashMessages.site.linkNoValid");
return new RedirectResponse($this->generateUrl("brulafine_shipping"));
}
// update the user data.
$user->setConfirmationToken(null);
$user->setPasswordRequestedAt(null);
$user->setEnabled(true);
$securityManager->updateUser($user);
// Force Login the user
$eventDispatcher->dispatch(
new SecurityEvent($user, $request),
SecuritySubscriber::USER_LOGGED_IN
);
return $this->redirectToRoute($this->getRouteToRedirect($dest));
}
/**
* @param $dest
* @return string
*/
private function getRouteToRedirect($dest)
{
// define where to redirect the user
if ('pass' == $dest) {
$route = 'user_change_password';
} else {
$route = 'brulafine_shipping';
}
return $route;
}
}