src/Controller/AuthController.php line 67

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Controller;
  4. use App\Logger\Log;
  5. use App\Form\AuthForm;
  6. use App\Entity\BaseAuth;
  7. use App\Form\CommonForm;
  8. use App\Service\AuthService;
  9. use App\Service\FileService;
  10. use App\Service\EmailService;
  11. use App\Service\IAuthService;
  12. use App\Service\IEmailService;
  13. use App\Service\OptionService;
  14. use App\Service\SchoolService;
  15. use App\Service\IOptionService;
  16. use Symfony\Component\Asset\Packages;
  17. use Doctrine\ORM\EntityManagerInterface;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\Security\Core\Security;
  20. use Symfony\Component\HttpFoundation\Response;
  21. use Symfony\Component\Security\Csrf\CsrfToken;
  22. use Symfony\Component\Routing\Annotation\Route;
  23. use Symfony\Component\HttpFoundation\JsonResponse;
  24. use Symfony\Contracts\Translation\TranslatorInterface;
  25. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  26. use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
  27. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  28. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
  29. class AuthController extends BaseController
  30. {
  31.     private AuthForm $authForm;
  32.     
  33.     public function __construct(
  34.         AuthForm $authForm,
  35.         AuthService $authService,
  36.         EmailService $notifyService,
  37.         OptionService $optionService,
  38.         SchoolService $schoolService,
  39.         Security $security,
  40.         FileService $fileService,
  41.         SessionInterface $session,
  42.         Packages $assetsManager,
  43.         TranslatorInterface $translator,
  44.         Log $log
  45.     ) {
  46.         parent::__construct(
  47.             $authService,
  48.             $notifyService,
  49.             $optionService,
  50.             $fileService,
  51.             $session,
  52.             $assetsManager,
  53.             $translator,
  54.             $log,
  55.             $security,
  56.             $schoolService
  57.         );
  58.         $this->authForm $authForm;
  59.     }
  60.     /**
  61.      * @Route("/login", name="auth_signin")
  62.      */
  63.     public function signIn(Request $requestAuthenticationUtils $authenticationUtilsParameterBagInterface $parameter): Response
  64.     {
  65.         $lastUserName $authenticationUtils->getLastUsername();
  66.         $lastError $authenticationUtils->getLastAuthenticationError();
  67.         
  68.         $view ='auth/sign_in.html.twig';
  69.         if($parameter->get('app.user') == IAuthService::ROLE_FAMILY){
  70.             $view ='auth/sign_family.html.twig';
  71.         }
  72.         return $this->render($view, [
  73.             'lastUser' => $lastUserName,
  74.             'lastError' => $lastError,
  75.             'env' => $parameter->get('app.env')
  76.         ]);
  77.     }
  78.     /**
  79.      * @Route("/forgot", name="auth_forgot_password")
  80.      */
  81.     public function forgotPassword(Request $requestCsrfTokenManagerInterface $csrfTokenManager): Response
  82.     {
  83.         if ($request->isMethod('POST') && $request->isXmlHttpRequest()) {
  84.             $token = new CsrfToken('form_forgot_password'$request->request->get('token'));
  85.             if ($csrfTokenManager->isTokenValid($token)) {
  86.                 $result $this->authForm->checkForgot($request$this->session);
  87.                 if ($result instanceof BaseAuth) {
  88.                     $this->notifyService->sendMail(
  89.                         $this->translator->trans('activation_code'),
  90.                         'forgot_password',
  91.                         [
  92.                             'email' => $result->getEmail(),
  93.                             'data' => [
  94.                                 'fullname' => $result->getFullName(),
  95.                                 'code' => $result->getValidationCode(),
  96.                                 'time_elapsed' => IOptionService::MAX_ACCOUNT_ACTIVATION_TIME,
  97.                                 'app_url' => IOptionService::BASE_URL,
  98.                                 'support_mail' => IEmailService::SUPPORT,
  99.                                 'logo' => IOptionService::CDN_LOGO,
  100.                                 'favicon' => IOptionService::CDN_FAVICON,
  101.                             ],
  102.                         ]
  103.                     );
  104.                     return new JsonResponse(null200);
  105.                 } else if(is_array($result)){
  106.                     return new JsonResponse($result400);
  107.                 }
  108.                 return new JsonResponse(null200);
  109.             }
  110.             return new JsonResponse(null200);
  111.         }
  112.         return $this->render('auth/forgot_password.html.twig');
  113.     }
  114.     /**
  115.      * @Route("/activation", name="auth_activation")
  116.      */
  117.     public function activation(Request $requestCsrfTokenManagerInterface $csrfTokenManager): Response
  118.     {
  119.         $account $this->session->get(IOptionService::SESSION_ACCOUNT);
  120.         if (null == $account || !in_array($account['step'], ['signin_staff_activation''signup_activation''forgot_activation''signin_activation'])) {
  121.             $this->activityLog($request,get_class($this),__FUNCTION__,'activation url error not in array',Log::MESSAGE_INFO,'HACK');
  122.             $this->session->invalidate();
  123.             return $this->redirectToRoute('auth_signout');
  124.         }
  125.         $referer $request->headers->get("referer"); // get the referer, it can be empty!
  126.         if (!\is_string($referer) || !$referer) {
  127.             $this->activityLog($request,get_class($this),__FUNCTION__,'activation with no referrer',Log::MESSAGE_INFO,'HACK',$account["email"]);
  128.             $this->session->invalidate();
  129.             return $this->redirectToRoute("auth_signout");
  130.         }
  131.         $title $message $step null;
  132.         if ('signin_activation' == $account['step']) {
  133.             $title $this->translator->trans('activation_code');
  134.             $message $this->translator->trans('signup_activation_code_info1');
  135.             $step 'signin_activation';
  136.         } elseif ('forgot_activation' == $account['step']) {
  137.             $title $this->translator->trans('activation_code');
  138.             $message $this->translator->trans('forgot_activation_code_info2', ['%0%' => CommonForm::maskEmail($account['email'])]);
  139.             $step 'forgot_activation';
  140.         }
  141.         if ($request->isMethod("POST") && $request->isXmlHttpRequest()) {
  142.             $token = new CsrfToken("activation_form"$request->request->get("token"));
  143.             if ($csrfTokenManager->isTokenValid($token)) {
  144.                 $jsonData $this->authForm->checkActivation($request$this->session$this->log$this->getUser());
  145.                 if ($jsonData != null) {
  146.                     if ($account["step"] == "signin_activation") {
  147.                         if ($jsonData == IOptionService::RESPONSE_AUTH) {
  148.                             //clean session
  149.                             $this->session->remove(IOptionService::SESSION_ACCOUNT);
  150.                             //create new session file
  151.                             $this->fileService->createSessionFile(
  152.                                 "app.connection_dir",
  153.                                 $account["email"],
  154.                                 $request->getSession()->getId(),
  155.                                 (new \DateTime())->format("Y-m-d")
  156.                             );
  157.                         }
  158.                         return new JsonResponse($jsonData200);
  159.                     }
  160.                     if ($account["step"] == "forgot_activation") {
  161.                         return new JsonResponse($jsonData200);
  162.                     }
  163.                 }
  164.             }
  165.             return new JsonResponse($this->translator->trans('wrong_activation_code'), 200);
  166.         }
  167.         return $this->render(
  168.             "auth/activation.html.twig",
  169.             [
  170.                 "title" => $title,
  171.                 "message" => $message,
  172.                 "step" => $step
  173.             ]
  174.         );
  175.     }
  176.     /**
  177.      * @Route("/resend-activation-code", name="auth_resent_activation_code")
  178.      */
  179.     public function resendActivationCode(Request $requestEntityManagerInterface $manager): Response
  180.     {
  181.         $account $this->session->get(IOptionService::SESSION_ACCOUNT);
  182.         if (null == $account || !in_array($account['step'], ['signin_staff_activation''signup_activation''forgot_activation''signin_activation'])) {
  183.             $this->activityLog($request,get_class($this),__FUNCTION__,'activation url error not in array',Log::MESSAGE_INFO,'HACK','UNKNOWN');
  184.             $this->session->invalidate();
  185.             return new JsonResponse(['redirect' => $this->generateUrl('auth_signout')], 400);
  186.         }
  187.         $referer $request->headers->get("referer"); // get the referer, it can be empty!
  188.         if (!\is_string($referer) || !$referer) {
  189.             $this->activityLog($request,get_class($this),__FUNCTION__,'activation with no referrer',Log::MESSAGE_INFO,'HACK',$account["email"]);
  190.             $this->session->invalidate();
  191.             return new JsonResponse(['redirect' => $this->generateUrl('auth_signout')], 400);
  192.         }
  193.         try {
  194.             // Generate activation code
  195.             $activationCode null;
  196.             $page 'signin_activation' == $account['step'] ? IAuthService::ACTIVATION IAuthService::RESET;
  197.             $findUser $this->authService->signInUser($account['email'], null);
  198.             if (!empty($findUser)) {
  199.                 $activationCode CommonForm::generateCode(6true);
  200.                 $findUser->setValidationCode($activationCode);
  201.                 $findUser->setValidationPage($page);
  202.                 $findUser->setValidationDate(new \DateTime('now'));
  203.               
  204.                 $manager->persist($findUser);
  205.                 $manager->flush();
  206.                 $account['activation'] = $activationCode;
  207.                 $account['created'] = new \DateTime('now');
  208.                 $this->session->set(IOptionService::SESSION_ACCOUNT$account);
  209.                 $this->notifyService->sendMail(
  210.                     $this->translator->trans('request_activation_code'),
  211.                     'request_activation_code',
  212.                     [
  213.                         'email' => $findUser->getEmail(),
  214.                         'data' => [
  215.                             'fullname' => $findUser->getFullName(),
  216.                             'code' => $account['activation'],
  217.                             'time_elapsed' => IOptionService::MAX_ACCOUNT_ACTIVATION_TIME,
  218.                             'app_url' => IOptionService::BASE_URL,
  219.                             'support_mail' => IEmailService::SUPPORT,
  220.                             'logo' => IOptionService::CDN_LOGO,
  221.                             'favicon' => IOptionService::CDN_FAVICON,
  222.                         ],
  223.                     ]
  224.                 );
  225.                 $this->activityLog($request,get_class($this),__FUNCTION__,'User ask again activation code success',Log::MESSAGE_ERROR);
  226.                 return new JsonResponse(['message' => $this->translator->trans('activation_code_resend')], 200);
  227.             }
  228.             $this->activityLog($request,get_class($this),__FUNCTION__,'account not found',Log::MESSAGE_ERROR,'HACK','UNKNOWN');
  229.             return new JsonResponse(['message' => $this->translator->trans('activation_code_resend')], 200);
  230.         } catch (\Exception $e) {
  231.             $this->activityLog($request,get_class($this),__FUNCTION__,'User ask again activation code failed'.$account['email']
  232.             ,Log::MESSAGE_ERROR);
  233.             return new JsonResponse(['message' => $this->translator->trans('activation_code_resend')], 200);
  234.         }
  235.     }
  236.     /**
  237.      * @Route("/reset-password", name="auth_reset_password")
  238.      */
  239.     public function resetPassword(Request $requestCsrfTokenManagerInterface $csrfTokenManager): Response
  240.     {
  241.         $account $this->session->get(IOptionService::SESSION_ACCOUNT);
  242.         if (empty($account)) {
  243.             return $this->redirectToRoute('auth_signin');
  244.         }
  245.         if ($request->isMethod('POST') && $request->isXmlHttpRequest()) {
  246.             $token = new CsrfToken('reset_form'$request->request->get('token'));
  247.             if ($csrfTokenManager->isTokenValid($token)) {
  248.                 $result $this->authForm->checkReset($request$this->session);
  249.                 if ($result instanceof BaseAuth) {
  250.                     // clean session
  251.                     $this->session->remove(IOptionService::SESSION_ACCOUNT);
  252.                     // delete blacklist file
  253.                     $this->fileService->deleteFile($this->getParameter('app.blacklist_dir').DIRECTORY_SEPARATOR.$result->getEmail().'.log');
  254.                     return new JsonResponse(null200);
  255.                 }
  256.                 if ('fake_email' == $result) {
  257.                     return new JsonResponse(null200);
  258.                 }
  259.                 return new JsonResponse(null200);
  260.             }
  261.             return new JsonResponse(null200);
  262.         }
  263.         return $this->render('auth/reset.html.twig');
  264.     }
  265.     /**
  266.      * @Route("/validate-account/{tid}", name="auth_validate_account")
  267.      */
  268.     public function validate(Request $requestCsrfTokenManagerInterface $csrfTokenManager, ?bool $profileId false): Response
  269.     {
  270.         if ($this->fileService->countLinesInFile($this->getParameter('app.blacklist_dir').DIRECTORY_SEPARATOR.CommonForm::getAddressIp($request->getClientIp())) >= 3) {
  271.             return $this->render('error/error.html.twig', ['url' => IOptionService::BASE_URL]);
  272.         }
  273.         if ($request->isMethod('POST') && $request->isXmlHttpRequest()) {
  274.             $token = new CsrfToken('validate_account'$request->request->get('token'));
  275.             if ($csrfTokenManager->isTokenValid($token)) {
  276.                 $response $this->authForm->checkValidateAccount($request);
  277.                 if (empty($response)) {
  278.                     $this->session->invalidate();
  279.                     return new JsonResponse([[
  280.                         'message' => $this->translator->trans('account_validation_success'),
  281.                         'redirect' => $this->generateUrl('auth_signin'),],
  282.                     ], 200);
  283.                 }
  284.                 return new JsonResponse([['message' => $response,],], 400);
  285.             }
  286.             return new JsonResponse([[
  287.                 'message' => $this->translator->trans('account_validation_success'),
  288.                 'redirect' => $this->generateUrl('auth_signin'),],
  289.             ], 200);
  290.         }
  291.         $findUser $this->authService->loadUserByValidationCode($request->attributes->get('tid'));
  292.         if(empty($findUser) ||  ($findUser instanceof  BaseAuth  && ($findUser->getStatus() != IOptionService::STATUS_PENDING))) {
  293.             // write in blacklist file
  294.             $this->fileService->appendFile(
  295.                 "app.blacklist_dir",
  296.                 CommonForm::getAddressIp($request->getClientIp()),
  297.                 "date=" . (new \DateTime())->format("Y-m-d H:i:s") . "|ip=" CommonForm::getAddressIp($request->getClientIp()) . "|page=CREATE_ACCOUNT|user-agent=" $request->headers->get("user-agent") . PHP_EOL
  298.             );
  299.             $this->activityLog($request,get_class($this),__FUNCTION__,'invalid request: attempt to get new account',Log::MESSAGE_ERROR,'HACK');
  300.             return $this->render("error/error.html.twig", ["url" => IOptionService::BASE_URL]);
  301.         }
  302.         return $this->render('auth/validate_account.html.twig', [
  303.             'entity' => $findUser,
  304.             'tid' => $request->attributes->get('tid'),
  305.         ]);
  306.     }
  307.     /**
  308.      * @Route("/signout", name="auth_signout")
  309.      */
  310.     public function signout(Request $request): Response
  311.     {
  312.         $request->getSession()->invalidate(1);
  313.         $request->getSession()->clear();
  314.         return $this->redirectToRoute('auth_signin');
  315.     }
  316. }