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->log->writeLog(
  122.                 [
  123.                     IOptionService::KEY_CLASS => get_class($this),
  124.                     IOptionService::KEY_FUNCTION => __FUNCTION__,
  125.                     IOptionService::KEY_URL => $request->getRequestUri(),
  126.                     IOptionService::KEY_ACCOUNT => 'UNKNOWN',
  127.                     IOptionService::KEY_MESSAGE => 'activation url error not in array',
  128.                     IOptionService::KEY_CATEGORY => 'HACK',
  129.                 ],
  130.                 Log::MESSAGE_ERROR
  131.             );
  132.             $this->session->invalidate();
  133.             return $this->redirectToRoute('auth_signout');
  134.         }
  135.         $referer $request->headers->get("referer"); // get the referer, it can be empty!
  136.         if (!\is_string($referer) || !$referer) {
  137.             $this->log->writeLog(
  138.                 [
  139.                     IOptionService::KEY_CLASS => get_class($this),
  140.                     IOptionService::KEY_FUNCTION => __FUNCTION__,
  141.                     IOptionService::KEY_URL => $request->getRequestUri(),
  142.                     IOptionService::KEY_ACCOUNT => $account["email"],
  143.                     IOptionService::KEY_MESSAGE => "activation with no referrer",
  144.                     IOptionService::KEY_CATEGORY => "HACK"
  145.                 ],
  146.                 Log::MESSAGE_ERROR
  147.             );
  148.             $this->session->invalidate();
  149.             return $this->redirectToRoute("auth_signout");
  150.         }
  151.         $title $message $step null;
  152.         if ('signin_activation' == $account['step']) {
  153.             $title $this->translator->trans('activation_code');
  154.             $message $this->translator->trans('signup_activation_code_info1');
  155.             $step 'signin_activation';
  156.         } elseif ('forgot_activation' == $account['step']) {
  157.             $title $this->translator->trans('activation_code');
  158.             $message $this->translator->trans('forgot_activation_code_info2', ['%0%' => CommonForm::maskEmail($account['email'])]);
  159.             $step 'forgot_activation';
  160.         }
  161.         if ($request->isMethod("POST") && $request->isXmlHttpRequest()) {
  162.             $token = new CsrfToken("activation_form"$request->request->get("token"));
  163.             if ($csrfTokenManager->isTokenValid($token)) {
  164.                 $jsonData $this->authForm->checkActivation($request$this->session$this->log$this->getUser());
  165.                 if ($jsonData != null) {
  166.                     if ($account["step"] == "signin_activation") {
  167.                         if ($jsonData == IOptionService::RESPONSE_AUTH) {
  168.                             //clean session
  169.                             $this->session->remove(IOptionService::SESSION_ACCOUNT);
  170.                             //create new session file
  171.                             $this->fileService->createSessionFile(
  172.                                 "app.connection_dir",
  173.                                 $account["email"],
  174.                                 $request->getSession()->getId(),
  175.                                 (new \DateTime())->format("Y-m-d")
  176.                             );
  177.                         }
  178.                         return new JsonResponse($jsonData200);
  179.                     }
  180.                     if ($account["step"] == "forgot_activation") {
  181.                         return new JsonResponse($jsonData200);
  182.                     }
  183.                 }
  184.             }
  185.             return new JsonResponse($this->translator->trans('wrong_activation_code'), 200);
  186.         }
  187.         return $this->render(
  188.             "auth/activation.html.twig",
  189.             [
  190.                 "title" => $title,
  191.                 "message" => $message,
  192.                 "step" => $step
  193.             ]
  194.         );
  195.     }
  196.     /**
  197.      * @Route("/resend-activation-code", name="auth_resent_activation_code")
  198.      */
  199.     public function resendActivationCode(Request $requestEntityManagerInterface $manager): Response
  200.     {
  201.         $account $this->session->get(IOptionService::SESSION_ACCOUNT);
  202.         if (null == $account || !in_array($account['step'], ['signin_staff_activation''signup_activation''forgot_activation''signin_activation'])) {
  203.             $this->log->writeLog(
  204.                 [
  205.                     IOptionService::KEY_CLASS => get_class($this),
  206.                     IOptionService::KEY_FUNCTION => __FUNCTION__,
  207.                     IOptionService::KEY_URL => $request->getRequestUri(),
  208.                     IOptionService::KEY_ACCOUNT => 'UNKNOWN',
  209.                     IOptionService::KEY_MESSAGE => 'activation url error not in array',
  210.                     IOptionService::KEY_CATEGORY => 'HACK',
  211.                 ],
  212.                 Log::MESSAGE_ERROR
  213.             );
  214.             $this->session->invalidate();
  215.             return new JsonResponse(['redirect' => $this->generateUrl('auth_signout')], 400);
  216.         }
  217.         $referer $request->headers->get("referer"); // get the referer, it can be empty!
  218.         if (!\is_string($referer) || !$referer) {
  219.             $this->log->writeLog(
  220.                 [
  221.                     IOptionService::KEY_CLASS => get_class($this),
  222.                     IOptionService::KEY_FUNCTION => __FUNCTION__,
  223.                     IOptionService::KEY_URL => $request->getRequestUri(),
  224.                     IOptionService::KEY_ACCOUNT => $account["email"],
  225.                     IOptionService::KEY_MESSAGE => "activation with no referrer",
  226.                     IOptionService::KEY_CATEGORY => "HACK"
  227.                 ],
  228.                 Log::MESSAGE_ERROR
  229.             );
  230.             $this->session->invalidate();
  231.             return new JsonResponse(['redirect' => $this->generateUrl('auth_signout')], 400);
  232.         }
  233.         try {
  234.             // Generate activation code
  235.             $activationCode null;
  236.             $page 'signin_activation' == $account['step'] ? IAuthService::ACTIVATION IAuthService::RESET;
  237.             $findUser $this->authService->signInUser($account['email'], null);
  238.             if (!empty($findUser)) {
  239.                 $activationCode CommonForm::generateCode(6true);
  240.                 $findUser->setValidationCode($activationCode);
  241.                 $findUser->setValidationPage($page);
  242.                 $findUser->setValidationDate(new \DateTime('now'));
  243.               
  244.                 $manager->persist($findUser);
  245.                 $manager->flush();
  246.                 $account['activation'] = $activationCode;
  247.                 $account['created'] = new \DateTime('now');
  248.                 $this->session->set(IOptionService::SESSION_ACCOUNT$account);
  249.                 $this->notifyService->sendMail(
  250.                     $this->translator->trans('request_activation_code'),
  251.                     'request_activation_code',
  252.                     [
  253.                         'email' => $findUser->getEmail(),
  254.                         'data' => [
  255.                             'fullname' => $findUser->getFullName(),
  256.                             'code' => $account['activation'],
  257.                             'time_elapsed' => IOptionService::MAX_ACCOUNT_ACTIVATION_TIME,
  258.                             'app_url' => IOptionService::BASE_URL,
  259.                             'support_mail' => IEmailService::SUPPORT,
  260.                             'logo' => IOptionService::CDN_LOGO,
  261.                             'favicon' => IOptionService::CDN_FAVICON,
  262.                         ],
  263.                     ]
  264.                 );
  265.                 $this->log->writeLog(
  266.                     [
  267.                         IOptionService::KEY_CLASS => get_class($this),
  268.                         IOptionService::KEY_FUNCTION => __FUNCTION__,
  269.                         IOptionService::KEY_URL => $request->getRequestUri(),
  270.                         IOptionService::KEY_MESSAGE => 'User ask again activation code success'.$findUser->getGuid(),
  271.                     ],
  272.                     Log::MESSAGE_ERROR
  273.                 );
  274.                 return new JsonResponse(['message' => $this->translator->trans('activation_code_resend')], 200);
  275.             }
  276.             $this->log->writeLog(
  277.                 [
  278.                     IOptionService::KEY_CLASS => get_class($this),
  279.                     IOptionService::KEY_FUNCTION => __FUNCTION__,
  280.                     IOptionService::KEY_URL => $request->getRequestUri(),
  281.                     IOptionService::KEY_ACCOUNT => 'UNKNOWN',
  282.                     IOptionService::KEY_MESSAGE => 'account not found',
  283.                     IOptionService::KEY_CATEGORY => 'HACK',
  284.                 ],
  285.                 Log::MESSAGE_ERROR
  286.             );
  287.             return new JsonResponse(['message' => $this->translator->trans('activation_code_resend')], 200);
  288.         } catch (\Exception $e) {
  289.             $this->log->writeLog(
  290.                 [
  291.                     IOptionService::KEY_CLASS => get_class($this),
  292.                     IOptionService::KEY_FUNCTION => __FUNCTION__,
  293.                     IOptionService::KEY_URL => $request->getRequestUri(),
  294.                     IOptionService::KEY_MESSAGE => 'User ask again activation code failed'.$account['email'],
  295.                 ],
  296.                 Log::MESSAGE_ERROR
  297.             );
  298.             return new JsonResponse(['message' => $this->translator->trans('activation_code_resend')], 200);
  299.         }
  300.     }
  301.     /**
  302.      * @Route("/reset-password", name="auth_reset_password")
  303.      */
  304.     public function resetPassword(Request $requestCsrfTokenManagerInterface $csrfTokenManager): Response
  305.     {
  306.         $account $this->session->get(IOptionService::SESSION_ACCOUNT);
  307.         if (empty($account)) {
  308.             return $this->redirectToRoute('auth_signin');
  309.         }
  310.         if ($request->isMethod('POST') && $request->isXmlHttpRequest()) {
  311.             $token = new CsrfToken('reset_form'$request->request->get('token'));
  312.             if ($csrfTokenManager->isTokenValid($token)) {
  313.                 $result $this->authForm->checkReset($request$this->session);
  314.                 if ($result instanceof BaseAuth) {
  315.                     // clean session
  316.                     $this->session->remove(IOptionService::SESSION_ACCOUNT);
  317.                     // delete blacklist file
  318.                     $this->fileService->deleteFile($this->getParameter('app.blacklist_dir').DIRECTORY_SEPARATOR.$result->getEmail().'.log');
  319.                     return new JsonResponse(null200);
  320.                 }
  321.                 if ('fake_email' == $result) {
  322.                     return new JsonResponse(null200);
  323.                 }
  324.                 return new JsonResponse(null200);
  325.             }
  326.             return new JsonResponse(null200);
  327.         }
  328.         return $this->render('auth/reset.html.twig');
  329.     }
  330.     /**
  331.      * @Route("/validate-account/{tid}", name="auth_validate_account")
  332.      */
  333.     public function validate(Request $requestCsrfTokenManagerInterface $csrfTokenManager, ?bool $profileId false): Response
  334.     {
  335.         if ($this->fileService->countLinesInFile($this->getParameter('app.blacklist_dir').DIRECTORY_SEPARATOR.CommonForm::getAddressIp($request->getClientIp())) >= 3) {
  336.             return $this->render('error/error.html.twig', ['url' => IOptionService::BASE_URL]);
  337.         }
  338.         if ($request->isMethod('POST') && $request->isXmlHttpRequest()) {
  339.             $token = new CsrfToken('validate_account'$request->request->get('token'));
  340.             if ($csrfTokenManager->isTokenValid($token)) {
  341.                 $response $this->authForm->checkValidateAccount($request);
  342.                 if (empty($response)) {
  343.                     $this->session->invalidate();
  344.                     return new JsonResponse([[
  345.                         'message' => $this->translator->trans('account_validation_success'),
  346.                         'redirect' => $this->generateUrl('auth_signin'),],
  347.                     ], 200);
  348.                 }
  349.                 return new JsonResponse([['message' => $response,],], 400);
  350.             }
  351.             return new JsonResponse([[
  352.                 'message' => $this->translator->trans('account_validation_success'),
  353.                 'redirect' => $this->generateUrl('auth_signin'),],
  354.             ], 200);
  355.         }
  356.         $findUser $this->authService->loadUserByValidationCode($request->attributes->get('tid'));
  357.         if(empty($findUser) ||  ($findUser instanceof  BaseAuth  && ($findUser->getStatus() != IOptionService::STATUS_PENDING))) {
  358.             // write in blacklist file
  359.             $this->fileService->appendFile(
  360.                 "app.blacklist_dir",
  361.                 CommonForm::getAddressIp($request->getClientIp()),
  362.                 "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
  363.             );
  364.             $this->log->writeLog(
  365.                 [
  366.                     IOptionService::KEY_CLASS => get_class($this),
  367.                     IOptionService::KEY_FUNCTION => __FUNCTION__,
  368.                     IOptionService::KEY_URL => $request->getRequestUri(),
  369.                     IOptionService::KEY_MESSAGE => "invalid request: attempt to get new account",
  370.                     IOptionService::KEY_CATEGORY => "HACK"
  371.                 ],
  372.                 Log::MESSAGE_ERROR
  373.             );
  374.             return $this->render("error/error.html.twig", ["url" => IOptionService::BASE_URL]);
  375.         }
  376.         return $this->render('auth/validate_account.html.twig', [
  377.             'entity' => $findUser,
  378.             'tid' => $request->attributes->get('tid'),
  379.         ]);
  380.     }
  381.     /**
  382.      * @Route("/signout", name="auth_signout")
  383.      */
  384.     public function signout(Request $request): Response
  385.     {
  386.         $request->getSession()->invalidate(1);
  387.         $request->getSession()->clear();
  388.         return $this->redirectToRoute('auth_signin');
  389.     }
  390. }