<?php
namespace App\Controller;
use App\Entity\App\UserPasswordChange;
use App\Entity\App\Users;
use App\Repository\Tools\AppSettingsRepository;
use App\Repository\UsersRepository;
use App\Services\LogService;
use App\Services\MailerService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\Translation\TranslatorInterface;
class SecurityController extends AbstractController
{
private $_AppSettings;
private $entityManager;
private $mailerService;
private $csrfTokenManager;
private $translator;
public function __construct(
AppSettingsRepository $apRepository,
UsersRepository $userRepository,
UrlGeneratorInterface $urlGenerator,
EntityManagerInterface $entityManager,
MailerService $mailerService,
CsrfTokenManagerInterface $csrfTokenManager,
TranslatorInterface $translator,
LogService $logService
){
$this->entityManager = $entityManager;
$this->mailerService = $mailerService;
$this->csrfTokenManager = $csrfTokenManager;
$this->translator = $translator;
$this->userRepository = $userRepository;
$this->urlGenerator = $urlGenerator;
$this->_getAppSettings($apRepository);
$this->logService = $logService;
}
public function generateRandomString($length = 10) {
return substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,$length);
}
public function _getAppSettings($apRepository){
$this->_AppSettings = $apRepository->getAppSettings();
}
#[Route('/login', name: 'app_login')]
public function login(AuthenticationUtils $authenticationUtils): Response
{
$error = $authenticationUtils->getLastAuthenticationError();
if ($error) {
$translatedError = $this->translator->trans($error->getMessageKey(), $error->getMessageData(), 'security');
$this->addFlash('error', $translatedError);
}
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', ['app_settings' => $this->_AppSettings,'last_username' => $lastUsername, 'error' => $error]);
}
#[Route('/wyloguj', name: 'app_logout')]
public function logout(): void
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
#[Route('/resetowanie-hasla/zgloszenie', name: 'app-reset-password-request', methods: ["GET", "POST"])]
public function appResetPasswordRequest(Request $request): Response
{
if ($request->isMethod('POST')) {
$csrfToken = $request->request->get('_csrf_token');
if (!$this->csrfTokenManager->isTokenValid(new CsrfToken('reset_request', $csrfToken))) {
throw new InvalidCsrfTokenException();
}
$username = (string)$request->request->get('ress_username');
$email = (string)$request->request->get('ress_email');
if (empty($username) || empty($email)) {
$this->addFlash('error', 'Login i adres e-mail są wymagane.');
return $this->redirectToRoute('app-reset-password-request');
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->addFlash('error', 'Podano niepoprawny adres e-mail.');
return $this->redirectToRoute('app-reset-password-request');
}
$user = $this->userRepository->findOneBy([
'username' => $username,
'email' => $email
]);
if (!$user) {
$this->addFlash('success', 'Jeśli dane zostały wprowadzone poprawnie, otrzymasz wiadomość e-mail z instrukcjami dotyczącymi resetowania hasła.');
return $this->redirectToRoute('app-reset-password-request');
}
if (!$user->isUserStatus()) {
$this->addFlash('success', 'Jeśli dane zostały wprowadzone poprawnie, otrzymasz wiadomość e-mail z instrukcjami dotyczącymi resetowania hasła.');
return $this->redirectToRoute('app-reset-password-request');
}
if ($user->getEmail() == null) {
$this->addFlash('success', 'Jeśli dane zostały wprowadzone poprawnie, otrzymasz wiadomość e-mail z instrukcjami dotyczącymi resetowania hasła.');
return $this->redirectToRoute('app-reset-password-request');
}
$data = [
'user_change_password_code' => $user->getId() . uniqid(). $this->generateRandomString(130)
];
try {
$this->entityManager->beginTransaction();
$this->userRepository->disableOldChangePassword($user->getId());
$newReset = new UserPasswordChange();
$newReset->setCreatedAt(new \DateTime());
$newReset->setUserId($user->getId());
$newReset->setUserPasswordChangeStatus(true);
$newReset->setUserPasswordChangeCode($data['user_change_password_code']);
$this->entityManager->persist($newReset);
$this->entityManager->flush();
$_queue = $this->mailerService->createQueue(
10,
$user->getEmail(),
[
'user_login' => $user->getUserlogin(),
'user_change_password_url' =>
$this->urlGenerator->generate(
'app-reset-password',
['token' => $data['user_change_password_code']],
UrlGeneratorInterface::ABSOLUTE_URL
)
],
0,
null,
$request->getClientIp()
);
$log = $this->logService->createLog(
48,
[
'userId' => $user->getId(),
'tokenId' => $newReset->getUserPasswordChangeId()
],
null,
$request->getClientIp()
);
$this->entityManager->commit();
$this->addFlash('success', 'Jeśli dane zostały wprowadzone poprawnie, otrzymasz wiadomość e-mail z instrukcjami dotyczącymi resetowania hasła.');
} catch (\Exception $e) {
$this->entityManager->rollback();
$this->addFlash('error', 'Wystąpił błąd podczas przetwarzania żądania. Prosimy spróbować ponownie.');
// $this->addFlash('error', $e->getMessage());
}
return $this->redirectToRoute('app-reset-password-request');
}
return $this->render('security/reset_password_registation.html.twig', ['app_settings' => $this->_AppSettings]);
}
#[Route('/resetowanie-hasla/zmiana/{token}', name: 'app-reset-password', methods: ["GET", "POST"])]
public function appResetPassword(Request $request, string $token, UserPasswordHasherInterface $passwordEncoder): Response
{
if ($request->isMethod('POST')) {
$csrfToken = $request->request->get('_csrf_token');
if (!$this->csrfTokenManager->isTokenValid(new CsrfToken('reset_password', $csrfToken))) {
throw new InvalidCsrfTokenException();
}
$userLogin = (string)$request->request->get('ress_username');
$password1 = (string)$request->request->get('reset_password1');
$password2 = (string)$request->request->get('reset_password2');
if (empty($password1) || empty($password2) || empty($userLogin)) {
$this->addFlash('error', 'Wprowadzone dane są niekompletne.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
if ($password1 !== $password2) {
$this->addFlash('error', 'Wprowadzone hasła różnią się.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
if (strlen($password1) < 10) {
$this->addFlash('error', 'Hasło musi zawierać przynajmniej 10 znaków.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
if (!preg_match('/[0-9]/', $password1)) {
$this->addFlash('error', 'Hasło musi zawierać cyfrę.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
if (!preg_match('/[@$%&!#*()_+-]/', $password1)) {
$this->addFlash('error', 'Hasło musi zawierać znaki specjalne.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
if (!preg_match('/[a-z]/', $password1)) {
$this->addFlash('error', 'Hasło musi zawierać co najmniej jedną małą literę!');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
if (!preg_match('/[A-Z]/', $password1)) {
$this->addFlash('error', 'Hasło musi zawierać co najmniej jedną wielką literę!');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
$resetRequest = $this->entityManager->getRepository(UserPasswordChange::class)
->findOneBy(['userPasswordChangeCode' => $token, 'userPasswordChangeStatus' => true]);
if (!$resetRequest) {
$this->addFlash('error', 'Błędny login lub kod resetowania hasła wygasł. Sprawdź dane i spróbuj ponownie.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
$expiryTime = (clone $resetRequest->getCreatedAt())->modify('+6 hours');
if (new \DateTime() > $expiryTime) {
// $this->addFlash('error', 'Błędny lub wykorzystany klucz zmiany hasła.');
$this->addFlash('error', 'Błędny login lub kod resetowania hasła wygasł. Sprawdź dane i spróbuj ponownie.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
$user = $this->entityManager->getRepository(Users::class)
->find($resetRequest->getUserId());
if (!$user) {
// $this->addFlash('error', 'Nie znaleziono użytkownika.');
$this->addFlash('error', 'Błędny login lub kod resetowania hasła wygasł. Sprawdź dane i spróbuj ponownie.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
if($user->getUserIdentifier() != $userLogin){
$this->addFlash('error', 'Błędny login lub kod resetowania hasła wygasł. Sprawdź dane i spróbuj ponownie.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
if (!$user->isUserStatus()) {
// $this->addFlash('error', 'Twoje konto jest zablokowane. Skontaktuj się z administratorem.');
$this->addFlash('error', 'Błędny login lub kod resetowania hasła wygasł. Sprawdź dane i spróbuj ponownie.');
return $this->redirectToRoute('app-reset-password', ['token' => $token]);
}
$hashedPassword = $passwordEncoder->hashPassword($user, $password1);
$user->setPassword($hashedPassword);
$user->setPasswordChangedAt(new \DateTime());
$user->setTryLogin(0);
$user->setUserStatus(true);
$user->setUpdatedAt(new \DateTime());
$resetRequest->setUserPasswordChangeStatus(false);
$resetRequest->setUserPasswordChangeDateUsed(new \DateTime());
$this->entityManager->flush();
$log = $this->logService->createLog(
47,
[
'userId' => $user->getId(),
'tokenId' => $resetRequest->getUserPasswordChangeId(),
],
null,
$request->getClientIp()
);
$this->addFlash('success', 'Hasło zostało pomyślnie zresetowane.');
return $this->redirectToRoute('app_login');
}
return $this->render('security/reset_password.html.twig', ['app_settings' => $this->_AppSettings]);
}
}