10namespace ComusParty\Controllers;
12use ComusParty\App\Cookie;
13use ComusParty\App\Exceptions\AuthenticationException;
14use ComusParty\App\Exceptions\MalformedRequestException;
15use ComusParty\App\Mailer;
16use ComusParty\App\MessageHandler;
17use ComusParty\App\Validator;
18use ComusParty\Models\ArticleDAO;
19use ComusParty\Models\ModeratorDao;
20use ComusParty\Models\PasswordResetToken;
21use ComusParty\Models\PasswordResetTokenDAO;
22use ComusParty\Models\PlayerDAO;
23use ComusParty\Models\RememberToken;
24use ComusParty\Models\RememberTokenDAO;
25use ComusParty\Models\User;
26use ComusParty\Models\UserDAO;
27use DateMalformedStringException;
30use Random\RandomException;
32use Twig\Error\LoaderError;
33use Twig\Error\RuntimeError;
34use Twig\Error\SyntaxError;
35use Twig\Loader\FilesystemLoader;
65 echo
$twig->render(
'login.twig', [
80 echo
$twig->render(
'forgot-password.twig');
96 'format' => FILTER_VALIDATE_EMAIL
100 if (!$validator->validate([
'email' => $email])) {
102 header(
'Location: /forgot-password');
107 $user = $userManager->findByEmail($email);
109 if (is_null($user)) {
110 MessageHandler::addMessageParametersToSession(
"Un lien de réinitialisation de mot de passe vous a été envoyé par e-mail");
111 header(
'Location: /login');
117 if ($tokenManager->findByUserId($user->getId())) {
118 MessageHandler::addMessageParametersToSession(
"Un lien de réinitialisation de mot de passe vous a été envoyé par e-mail");
119 header(
'Location: /login');
123 $token =
new PasswordResetToken($user->getId(), bin2hex(random_bytes(30)),
new DateTime());
124 $tokenManager->insert($token);
126 $url =
BASE_URL .
"/reset-password/" . $token->getToken();
127 $to = $user->getEmail();
129 $subject =
'🔑 Réinitialiser votre mot de passe';
132 <p>Il semblerait que vous ayez fait une demande de réinitialisation de mot de passe.</p>
133 <p>Pour ce faire, cliquez sur le lien ci-dessous et renseignez votre nouveau mot de passe :</p>
134 <a href="' . $url .
'">✅ Changer le mot de passe</a>
135 <p>À très bientôt dans l’arène ! 🎲,<br>
136 L\'équipe Comus Party 🚀</p>
138 <p style="font-size: 9px;">Si vous n\'êtes pas à l\'origine de cette demande, vous pouvez ignorer le présent mail.</p>';
141 $mailer =
new Mailer([$to], $subject, $message);
142 $mailer->generateHTMLMessage();
145 }
catch (Exception $e) {
146 MessageHandler::addExceptionParametersToSession($e);
147 header(
'Location: /forgot-password');
151 MessageHandler::addMessageParametersToSession(
"Un lien de réinitialisation de mot de passe vous a été envoyé par e-mail");
152 header(
'Location: /login');
170 $token = $tokenManager->findByToken($token);
172 if (is_null($token)) {
176 echo
$twig->render(
'reset-password.twig');
189 public function resetPassword(
string $token,
string $password,
string $passwordConfirm)
196 'format' =>
'/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?_&^#])[A-Za-z\d@$!%*?_&^#]{8,}$/'
198 'passwordConfirm' => [
202 'format' =>
'/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?_&^#])[A-Za-z\d@$!%*?_&^#]{8,}$/'
208 $validated = $validator->validate([
209 'password' => $password,
210 'passwordConfirm' => $passwordConfirm
217 if ($password !== $passwordConfirm) {
222 $token = $tokenManager->findByToken($token);
224 if (is_null($token)) {
230 $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
231 $user = $userManager->findById($token->getUserId());
232 $user->setPassword($hashedPassword);
234 if (!$userManager->update($user)) {
235 throw new Exception(
"Erreur lors de la mise à jour du mot de passe", 500);
238 if (!$tokenManager->delete($token->getUserId())) {
239 throw new Exception(
"Erreur lors de la suppression du token", 500);
242 echo MessageHandler::sendJsonMessage(
"Votre mot de passe a bien été réinitialisé");
244 }
catch (Exception $e) {
245 MessageHandler::sendJsonException($e);
260 echo
$twig->render(
'sign-up.twig', [
278 public function login(?
string $email, ?
string $password, ?
bool $rememberMe, ?
string $cloudflareCaptchaToken): bool
284 'format' => FILTER_VALIDATE_EMAIL
300 if (!$validator->validate([
'email' => $email,
'password' => $password])) {
305 $user = $userManager->findByEmail($email);
307 if (is_null($user)) {
311 if (is_null($user->getEmailVerifiedAt())) {
315 if ($user->getDisabled()) {
319 if (!password_verify($password, $user->getPassword())) {
326 $token->generateToken();
327 $key = $token->generateKey();
329 Cookie::set(
'rmb_token', base64_encode($token->getToken()), $token->getExpiresAt()->getTimestamp());
330 Cookie::set(
'rmb_usr', base64_encode($user->getId()), $token->getExpiresAt()->getTimestamp());
331 Cookie::set(
'rmb_key', base64_encode($key), $token->getExpiresAt()->getTimestamp());
336 echo MessageHandler::sendJsonMessage(
"Vous êtes connecté en tant que " . ($_SESSION[
'role'] ===
'player' ?
"joueur" :
"modérateur"));
341 }
catch (Exception $e) {
342 MessageHandler::sendJsonException($e);
355 $url =
'https://challenges.cloudflare.com/turnstile/v0/siteverify';
358 'response' => $cloudflareCaptchaToken,
359 'remoteip' => $_SERVER[
'REMOTE_ADDR']
364 curl_setopt($curl, CURLOPT_URL, $url);
365 curl_setopt($curl, CURLOPT_POST,
true);
366 curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
367 curl_setopt($curl, CURLOPT_RETURNTRANSFER,
true);
368 curl_setopt($curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
370 $result = curl_exec($curl);
372 if (curl_errno($curl)) {
374 throw new Exception(
"Erreur lors de la vérification du captcha : " . curl_error($curl));
376 $response = json_decode($result);
378 return $response->success;
400 $moderatorManager =
new ModeratorDAO($this->
getPdo());
401 $moderator = $moderatorManager->findByUserId($user->
getId());
404 $player = $playerManager->findByUserId($user->
getId());
406 if (is_null($player) && is_null($moderator)) {
407 throw new AuthenticationException(
"Aucun joueur ou modérateur n'est associé à votre compte. Veuillez contacter un administrateur.");
410 if (!is_null($player)) {
412 $activePfp = $articleManager->findActivePfpByPlayerUuid($player->getUuid());
413 $player->setActivePfp($activePfp ==
null ?
"default-pfp.jpg" : $activePfp->getFilePath());
414 $_SESSION[
'role'] =
'player';
415 $_SESSION[
'uuid'] = $player->getUuid();
416 $_SESSION[
'username'] = $player->getUsername();
417 $_SESSION[
'comusCoin'] = $player->getComusCoin();
418 $_SESSION[
'elo'] = $player->getElo();
419 $_SESSION[
'xp'] = $player->getXp();
420 $_SESSION[
'basket'] = [];
421 $_SESSION[
'pfpPath'] = $player->getActivePfp();
423 $_SESSION[
'role'] =
'moderator';
424 $_SESSION[
'uuid'] = $moderator->getUuid();
425 $_SESSION[
'firstName'] = $moderator->getFirstName();
426 $_SESSION[
'lastName'] = $moderator->getLastName();
444 if (!$token && !$userId && !$key) {
449 $rmbToken = $tokenManager->find(intval(base64_decode($userId)), base64_decode($token));
456 if (!$rmbToken->isValid(base64_decode($key))) {
461 if ($rmbToken->isExpired()) {
462 $tokenManager->delete($rmbToken);
467 $user = (
new UserDAO($this->
getPdo()))->findById(intval(base64_decode($userId)));
477 $this->
getTwig()->addGlobal(
'auth', [
478 'pfpPath' => $_SESSION[
'pfpPath'] ??
null,
479 'loggedIn' => isset($_SESSION[
'uuid']),
480 'loggedUuid' => $_SESSION[
'uuid'] ??
null,
481 'loggedUsername' => $_SESSION[
'username'] ??
null,
482 'loggedComusCoin' => $_SESSION[
'comusCoin'] ??
null,
483 'loggedElo' => $_SESSION[
'elo'] ??
null,
484 'loggedXp' => $_SESSION[
'xp'] ??
null,
485 'role' => $_SESSION[
'role'] ??
null,
486 'firstName' => $_SESSION[
'firstName'] ??
null,
487 'lastName' => $_SESSION[
'lastName'] ??
null,
519 if ($token && $userId) {
521 $rmbToken = $tokenManager->find(intval(base64_decode($userId)), base64_decode($token));
523 $tokenManager->delete($rmbToken);
529 header(
'Location: /login');
551 public function register(?
string $username, ?
string $email, ?
string $password, ?
string $passwordConfirm, ?
bool $termsOfServiceIsChecked, ?
bool $privacyPolicyIsChecked, ?
string $cloudflareCaptchaToken): void
559 'format' =>
'/^[a-zA-Z0-9_-]+$/'
564 'format' => FILTER_VALIDATE_EMAIL
571 'format' =>
'/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?_&^#])[A-Za-z\d@$!%*?_&^#]{8,}$/'
573 'passwordConfirm' => [
578 'format' =>
'/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?_&^#])[A-Za-z\d@$!%*?_&^#]{8,}$/'
589 if (!$validator->validate([
'username' => $username,
'email' => $email,
'password' => $password,
'passwordConfirm' => $passwordConfirm])) {
593 if ($password !== $passwordConfirm) {
597 if (!$termsOfServiceIsChecked || !$privacyPolicyIsChecked) {
598 throw new AuthenticationException(
"Vous devez accepter les conditions d'utilisation et la politique de confidentialité pour vous inscrire");
602 $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
608 $existingUser = $userDAO->findByEmail($email) !==
null;
609 $existingPlayer = $playerDAO->findByUsername($username) !==
null;
615 if ($existingPlayer) {
620 $emailVerifToken = bin2hex(random_bytes(30));
621 $resultUser = $userDAO->createUser($email, $hashedPassword, $emailVerifToken);
627 $subject =
'🎉 Bienvenue sur Comus Party !';
629 '<p>Merci d\'avoir créé un compte sur notre plateforme de mini-jeux en ligne. 🎮</p>
630 <p>Pour commencer à jouer et rejoindre nos parties endiablées, il ne vous reste plus qu\'une étape :</p>
631 <a href="' .
BASE_URL .
'/confirm-email/' . urlencode($emailVerifToken) .
'">✅ Confirmer votre compte ici</a>
632 <p>À très bientôt dans l’arène ! 🎲,<br>
633 L\'équipe Comus Party 🚀</p>';
635 $confirmMail =
new Mailer(array($email), $subject, $message);
636 $confirmMail->generateHTMLMessage();
637 $confirmMail->send();
640 $playerDAO->createPlayer($username, $email);
643 $user = $userManager->findByEmail($email);
645 if (is_null($user)) {
650 $player = $playerManager->findWithDetailByUserId($user->getId());
652 if (is_null($player)) {
656 echo MessageHandler::sendJsonMessage(
"Votre compte a été créé et un mail de confirmation vous a été envoyé. Veuillez confirmer votre compte pour pouvoir vous connecter.");
659 }
catch (Exception $e) {
660 MessageHandler::sendJsonException($e);
675 public function confirmEmail(
string $emailVerifToken,
bool $isLoggedIn): void
678 $user = $userDAO->findByEmailVerifyToken($emailVerifToken);
680 $userDAO->confirmUser($emailVerifToken);
681 MessageHandler::addMessageParametersToSession(
"Votre compte a bien été confirmé. Vous pouvez maintenant vous connecter.");
684 header(
'Location: /');
686 header(
'Location: /login');
690 header(
'Location: /register');
static delete(string $name)
Supprime un cookie.
static set(string $name, string $value, ?int $expire=null)
Crée un cookie ou met à jour un cookie existant.
static get(string $name)
Récupère la valeur d'un cookie.
Classe AuthenticationException.
showLoginPage()
La méthode showLoginPage permet d'afficher la page de connexion.
verifyCaptcha(string $cloudflareCaptchaToken)
Permet de vérifier le token de captcha auprès de Cloudflare.
clearRememberCookies()
Supprime les cookies de connexion.
login(?string $email, ?string $password, ?bool $rememberMe, ?string $cloudflareCaptchaToken)
Traite la demande de connexion de l'utilisateur.
__construct(FilesystemLoader $loader, Environment $twig)
Constructeur de la classe ControllerAuth.
resetPassword(string $token, string $password, string $passwordConfirm)
Réinitialise le mot de passe de l'utilisateur.
logOut()
Déconnecte l'utilisateur.
sendResetPasswordLink(string $email)
Envoie un lien de réinitialisation de mot de passe à l'adresse e-mail fournie.
showRegistrationPage()
La méthode showRegistrationPage permet d'afficher la page d'inscription.
confirmEmail(string $emailVerifToken, bool $isLoggedIn)
Confirme l'adresse e-mail d'un utilisateur à l'aide du token de vérification.
showResetPasswordPage(string $token)
Affiche la page de réinitialisation de mot de passe.
authenticate(User $user)
Permet d'authentifier l'utilisateur.
restoreSession()
Permet de reprendre la session via un cookie.
showForgotPasswordPage()
Affiche la page de réinitialisation de mot de passe.
getTwig()
Retourne l'attribut twig, correspondant à l'environnement de Twig.
getPdo()
Retourne l'attribut PDO, correspondant à la connexion à la base de données.
Classe PasswordResetTokenDAO.
Classe PasswordResetToken.
getId()
Retourne l'identifiant de l'utilisateur.
getEmailVerifiedAt()
Retourne la date de vérification de l'adresse e-mail.
getDisabled()
Retourne l'état de l'utilisateur (activé ou désactivé)
const CF_TURNSTILE_SITEKEY
Clef du site pour CloudFlare Turnstile.
const CF_TURNSTILE_SECRETKEY
Clef secrète d'authentification pour CloudFlare Turnstile.
const BASE_URL
URL complète de l'application.