From d7468fc363b5d028db84373d4abfa6d7d19bacb9 Mon Sep 17 00:00:00 2001 From: polo Date: Mon, 11 Aug 2025 06:25:39 +0200 Subject: =?UTF-8?q?nouveau=20routeur!=20et=20contr=C3=B4leurs=20et=20vues?= =?UTF-8?q?=20pour=20la=20connexion=20et=20la=20gestion=20du=20compte,=20d?= =?UTF-8?q?=C3=A9but=20d'utilisation=20de=20Request=20et=20Response?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controller/ArticleController.php | 4 +- src/controller/UserController.php | 360 +++++++++++++++++++++++++++++++++++ src/controller/ViewController.php | 39 ++++ src/controller/password.php | 328 ------------------------------- 4 files changed, 401 insertions(+), 330 deletions(-) create mode 100644 src/controller/UserController.php create mode 100644 src/controller/ViewController.php delete mode 100644 src/controller/password.php (limited to 'src/controller') diff --git a/src/controller/ArticleController.php b/src/controller/ArticleController.php index e3e4edb..3b39335 100644 --- a/src/controller/ArticleController.php +++ b/src/controller/ArticleController.php @@ -19,12 +19,12 @@ class ArticleController // cas d'une nouvelle "news" if(is_array($json['content'])){ foreach($json['content'] as $one_input){ - $one_input = Security::secureString($one_input); + $one_input = Security::secureHTML($one_input); } $content = $json['content']; } else{ - $content = Security::secureString($json['content']); + $content = Security::secureHTML($json['content']); } // nouvel article diff --git a/src/controller/UserController.php b/src/controller/UserController.php new file mode 100644 index 0000000..50e8bf7 --- /dev/null +++ b/src/controller/UserController.php @@ -0,0 +1,360 @@ +getRepository(User::class)->findAll(); + + if(count($users) === 0) // table vide + { + $_SESSION['user'] = ''; + $_SESSION['admin'] = false; + + return false; + } + else{ + return true; + } + } + + static public function createUser(EntityManager $entityManager) + { + // test mauvais paramètres + if(!isset($_POST['login']) || empty($_POST['login']) + || !isset($_POST['password']) || empty($_POST['password']) + || !isset($_POST['password_confirmation']) || empty($_POST['password_confirmation']) + || !isset($_POST['create_user_hidden']) || !empty($_POST['create_user_hidden'])) + { + header('Location: ' . new URL); + die; + } + + unset($_SESSION['user']); + + $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; + $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; + unset($_SESSION['captcha']); + + $error = ''; + if($captcha_try == 0) + { + $error = 'error_non_valid_captcha'; + } + elseif($captcha_solution == 0) // ne peut pas arriver, si? + { + $error = 'captcha_server_error'; + } + elseif($captcha_try != $captcha_solution) // le test! + { + $error = 'bad_solution_captcha'; + } + elseif($_POST['password'] !== $_POST['password_confirmation']) + { + $error = 'different_passwords'; + } + else + { + $login = self::removeSpacesTabsCRLF(htmlspecialchars($_POST['login'])); + $password = self::removeSpacesTabsCRLF(htmlspecialchars($_POST['password'])); + + // self::removeSpacesTabsCRLF prévient la validation par erreur d'une chaine "vide" + + // conformité + if(!empty($password) && !empty($login) + && $password === $_POST['password'] && $login === $_POST['login']) + { + // enregistrement et redirection + $password = password_hash($password, PASSWORD_DEFAULT); + $user = new App\Entity\User($login, $password); + $entityManager->persist($user); + $entityManager->flush(); + + header('Location: ' . new URL); + die; + } + else{ + $error = 'forbidden_characters'; + } + } + + $url = empty($error) ? new URL : new URL(['error' => $error]); + header('Location: ' . $url); + die; + } + + static public function connect(EntityManager $entityManager): void + { + if($_SESSION['admin']) // déjà connecté? + { + header('Location: ' . new URL); + die; + } + + $_SESSION['user'] = ''; + $_SESSION['admin'] = false; + + $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; + $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; + unset($_SESSION['captcha']); + + $error = ''; + if($captcha_try == 0) + { + $error = 'error_non_valid_captcha'; + } + elseif($captcha_solution == 0) // pas censé se produire + { + $error = 'captcha_server_error'; + } + elseif($captcha_try != $captcha_solution) // le test! + { + $error = 'bad_solution_captcha'; + } + elseif(!isset($_POST['login']) || empty($_POST['login']) + || !isset($_POST['password']) || empty($_POST['password'])) + { + $error = 'bad_login_or_password'; + } + else // c'est OK + { + $login = trim($_POST['login']); + $password = trim($_POST['password']); + $user = self::getUser($login, $entityManager); + + // enregistrement et redirection + if(!empty($user) && $login === $user->getLogin() && password_verify($password, $user->getPassword())) + { + $log = new Log(true); + $entityManager->persist($log); + $entityManager->flush(); + + // protection fixation de session, si l'attaquant crée un cookie de session, il est remplacé + session_regenerate_id(true); + + $_SESSION['user'] = $login; + $_SESSION['admin'] = true; + + $url = new URL(isset($_GET['from']) ? ['page' => $_GET['from']] : []); + isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : ''; + header('Location: ' . $url); + die; + } + else + { + $log = new Log(false); + $entityManager->persist($log); + $entityManager->flush(); + $error = 'bad_login_or_password'; + } + } + + // tous les cas sauf connexion réussie + sleep(1); // défense basique à la force brute + $url = new URL(isset($_GET['from']) ? ['page' => 'connexion', 'from' => $_GET['from']] : []); + isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : ''; + !empty($error) ? $url->addParams(['error' => $error]) : ''; + header('Location: ' . $url); + die; + } + + static public function disconnect(): void + { + // nettoyage complet + $_SESSION = []; // mémoire vive + session_destroy(); // fichier côté serveur + setcookie('PHPSESSID', '', time() - 86400, '/'); // cookie de session + + // retour même page + $url = new URL; + isset($_GET['from']) ? $url->addParams(['page' => $_GET['from']]) : ''; + isset($_GET['id']) ? $url->addParams(['id' => $_GET['id']]) : ''; + header('Location: ' . $url); + die; + } + + static public function updateUsername(EntityManager $entityManager): void + { + if(!$_SESSION['admin']) // superflux, fait dans le routeur + { + self::disconnect(); + } + + $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; + $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; + unset($_SESSION['captcha']); + + $url = new URL(['page' => 'user_edit']); + isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null; + + $error = ''; + if(!isset($_POST['old_login']) || empty($_POST['old_login']) + || !isset($_POST['password']) || empty($_POST['password']) + || !isset($_POST['new_login']) || empty($_POST['new_login']) + || !isset($_POST['modify_username_hidden']) || !empty($_POST['modify_username_hidden'])) + { + $error = 'bad_login_or_password'; + } + elseif($captcha_try != $captcha_solution) // le test! + { + $error = 'bad_solution_captcha'; + } + else + { + // sécurisation de la saisie + $old_login = $_POST['old_login']; + $password = $_POST['password']; + $new_login = self::removeSpacesTabsCRLF(htmlspecialchars($_POST['new_login'])); + // removeSpacesTabsCRLF pour éviter d'enregistrer une chaîne vide + + // tests de conformité + if($old_login !== $_POST['old_login'] || $password !== $_POST['password'] || $new_login !== $_POST['new_login']) + { + $error = 'forbidden_characters'; + } + elseif($old_login !== $_SESSION['user']){ + $error = 'bad_login_or_password'; + } + elseif($old_login === $new_login){ + $error = 'same_username_as_before'; + } + else + { + $user = self::getUser($old_login, $entityManager); + + if(password_verify($password, $user->getPassword())) + { + $user->setLogin($new_login); + $entityManager->flush(); + $_SESSION['user'] = $new_login; + + $url->addParams(['success_login' => 'new_login']); + $error = ''; + } + else + { + $error = 'bad_login_or_password'; + } + } + } + + if(!empty($error)){ + sleep(1); + $url->addParams(['error_login' => $error]); + } + + header('Location: ' . $url); + die; + } + + static public function updatePassword(EntityManager $entityManager): void + { + if(!$_SESSION['admin']) // superflux, fait dans le routeur + { + self::disconnect(); + } + + $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; + $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; + unset($_SESSION['captcha']); + + $url = new URL(['page' => 'user_edit']); + isset($_GET['from']) ? $url->addParams(['from' => $_GET['from']]) : null; + + $error = ''; + if(!isset($_POST['login']) || empty($_POST['login']) + || !isset($_POST['old_password']) || empty($_POST['old_password']) + || !isset($_POST['new_password']) || empty($_POST['new_password']) + || !isset($_POST['modify_password_hidden']) || !empty($_POST['modify_password_hidden'])) + { + $error = 'bad_login_or_password'; + } + elseif($captcha_try != $captcha_solution) // le test! + { + $error = 'bad_solution_captcha'; + } + else + { + // sécurisation de la saisie + $login = $_POST['login']; + $old_password = $_POST['old_password']; + $new_password = self::removeSpacesTabsCRLF(htmlspecialchars($_POST['new_password'])); + // removeSpacesTabsCRLF pour éviter d'enregistrer une chaîne vide + + // tests de conformité + if($login !== $_POST['login'] || $old_password !== $_POST['old_password'] || $new_password !== $_POST['new_password']) + { + $error = 'forbidden_characters'; + } + elseif($login !== $_SESSION['user']){ + $error = 'bad_login_or_password'; + } + elseif($old_password === $new_password){ + $error = 'same_password_as_before'; + } + else + { + $user = self::getUser($login, $entityManager); + + if(password_verify($old_password, $user->getPassword())) + { + $new_password = password_hash($new_password, PASSWORD_DEFAULT); + $user->setPassword($new_password); + $entityManager->flush(); + + $url->addParams(['success_password' => 'new_password']); + $error = ''; + } + else + { + $error = 'bad_login_or_password'; + } + } + } + + if(!empty($error)){ + sleep(1); + $url->addParams(['error_password' => $error]); + } + + header('Location: ' . $url); + die; + } + + static private function getUser(string $login, EntityManager $entityManager): ?User + { + $users = $entityManager->getRepository('App\Entity\User')->findBy(['login' => $login]); + + if(count($users) === 0) + { + $_SESSION['user'] = ''; + $_SESSION['admin'] = false; + } + + foreach($users as $user) + { + if($user->getLogin() === $login) + { + return $user; + } + } + return null; + } + + // erreurs à la création des mots de passe + static private function removeSpacesTabsCRLF(string $chaine): string + { + $cibles = [' ', "\t", "\n", "\r"]; // doubles quotes !! + return(str_replace($cibles, '', $chaine)); + } +} \ No newline at end of file diff --git a/src/controller/ViewController.php b/src/controller/ViewController.php new file mode 100644 index 0000000..69955c6 --- /dev/null +++ b/src/controller/ViewController.php @@ -0,0 +1,39 @@ +makeRootNode(htmlspecialchars($request->query->get('id') ?? '')); + self::$root_node = $director->getNode(); + + // mode modification d'une page activé + if($_SESSION['admin'] && $request->query->has('page') + && $request->query->has('action') && $request->query->get('action') === 'modif_page' + && $request->query->get('page') !== 'connexion' && $request->query->get('page') !== 'article' && $request->query->get('page') !== 'nouvelle_page' && $request->query->get('page') !== 'menu_chemins'){ + // les contrôles de la 2è ligne devraient utiliser un tableau + MainBuilder::$modif_mode = true; + } + + // construction de la page + $this->useChildrenBuilder(self::$root_node); + + return new Response($this->html, 200); + } +} \ No newline at end of file diff --git a/src/controller/password.php b/src/controller/password.php deleted file mode 100644 index 3d003da..0000000 --- a/src/controller/password.php +++ /dev/null @@ -1,328 +0,0 @@ -getRepository(User::class)->findAll(); - - // cas particulier table vide - if(count($users) === 0) - { - $_GET = []; - $_SESSION['user'] = ''; - $_SESSION['admin'] = false; - - // création d'un utilisateur, puis rechargement de la page - createPassword($entityManager); - } -} - - -function createPassword(EntityManager $entityManager) -{ - // fonction exécutée à priori deux fois d'affilée: affichage puis traitement de la saisie - - unset($_SESSION['user']); - - $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; - $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; - - // II - traitement - $error = ''; - if(!isset($_POST['captcha'])) // page création d'un compte rechargée - { - //$error = ''; - } - elseif($captcha_try == 0) - { - $error = 'error_non_valid_captcha'; - } - elseif($captcha_solution == 0) - { - //$error = ''; - } - elseif($captcha_try != $captcha_solution) // le test! - { - $error = 'bad_solution_captcha'; - } - elseif(!isset($_POST['password']) || empty($_POST['password']) - || (!isset($_POST['login']) || empty($_POST['login']))) - { - $error = 'bad_login_or_password'; - } - else - { - $login = Security::secureString($_POST['login']); - $password = Security::secureString($_POST['password']); - - // -> prévenir la validation par erreur d'une chaine "vide" - $login = removeSpacesTabsCRLF($login); - $password = removeSpacesTabsCRLF($password); - - // conformité - if(isset($password) && isset($login) - && $password == $_POST['password'] && $login == $_POST['login']) - { - unset($_SESSION['captcha']); - - // enregistrement et redirection - $password = password_hash($password, PASSWORD_DEFAULT); - $user = new App\Entity\User($login, $password); - $entityManager->persist($user); - $entityManager->flush(); - - header('Location: ' . new URL); - exit(); - } - else - { - $error = 'bad_login_or_password'; - - // compteur dans la session et blocage de compte - } - } - - // inséré dans $captchaHtml puis dans $formulaireNouveauMDP - $captcha = new Captcha; - // enregistrement de la réponse du captcha pour vérification - $_SESSION['captcha'] = $captcha->getSolution(); - - - // I - affichage - $title = 'Bienvenue nageur bigouden'; - $subHeading = 'Veuillez choisir les codes que vous utiliserez pour gérer le site.'; - - // même vue que la fonction changerMotDePasse() - require('../src/view/password.php'); - - echo($header); - if($error != '') - { - sleep(1); - echo($error_messages[$error]); - } - echo($formulaireNouveauMDP); - echo($error_messages['forbidden_characters']); - echo($footer); - die; -} - - -function connect(LoginBuilder $builder, EntityManager $entityManager) -{ - // déjà connecté - if($_SESSION['admin']) - { - header('Location: ' . new URL); - die; - } - - // II - traitement - $_SESSION['user'] = ''; - $_SESSION['admin'] = false; - - $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; - $captcha_try = isset($_POST['captcha']) ? Captcha::controlInput($_POST['captcha']) : 0; - - $error = ''; - if(!isset($_POST['captcha'])) // page rechargée - { - //$error = ''; - } - elseif($captcha_try == 0) - { - $error = 'error_non_valid_captcha'; - } - elseif($captcha_solution == 0) - { - //$error = ''; - } - elseif($captcha_try != $captcha_solution) // le test! - { - $error = 'bad_solution_captcha'; - } - elseif(!isset($_POST['login']) || empty($_POST['login']) - || !isset($_POST['password']) || empty($_POST['password'])) - { - $error = 'bad_login_or_password'; - } - else // c'est OK - { - $login = Security::secureString($_POST['login']); - $password = Security::secureString($_POST['password']); - $user = getUser($login, $entityManager); - - // enregistrement et redirection - if(!empty($user) && $login === $user->getLogin() && password_verify($password, $user->getPassword())) - { - $log = new Log(true); - $entityManager->persist($log); - $entityManager->flush(); - - session_regenerate_id(true); // protection fixation de session, si l'attaquant a créé un cookie de session (attaque XSS), il est remplacé - //unset($_SESSION['captcha']); - $_SESSION['user'] = $login; - $_SESSION['admin'] = true; - $link = new URL(isset($_GET['from']) ? ['page' => $_GET['from']] : []); - isset($_GET['id']) ? $link->addParams(['id' => $_GET['id']]) : ''; - header('Location: ' . $link); - die; - } - else - { - $log = new Log(false); - $entityManager->persist($log); - $entityManager->flush(); - $error = 'bad_login_or_password'; - } - } - - // inséré dans $captchaHtml puis dans $formulaireNouveauMDP - $captcha = new Captcha; - // enregistrement de la réponse du captcha pour vérification - $_SESSION['captcha'] = $captcha->getSolution(); // int - - // I - affichage - $title = "Connexion"; - $subHeading = "Veuillez saisir votre identifiant (e-mail) et votre mot de passe."; - - require('../src/view/password.php'); - - //$builder->addHTML($header); - if($error != '') - { - sleep(1); - $builder->addHTML($error_messages[$error]); - } - $builder->addHTML($formulaireConnexion); - //$builder->addHTML($warning_messages['message_cookie']); - $builder->addHTML($warning_messages['private_browsing']); - $builder->addHTML($footer); - - //die; -} - - -function changePassword(EntityManager $entityManager): void -{ - // fonction exécutée à priori deux fois d'affilée: affichage puis traitement de la saisie - - // II - traitement - $error = ''; - $success = false; - if(empty($_POST)) // première fois ou page rechargée - { - // - } - elseif(!isset($_POST['login']) || empty($_POST['login']) - || !isset($_POST['old_password']) || empty($_POST['old_password']) - || !isset($_POST['new_password']) || empty($_POST['new_password']) - || !isset($_POST['modify_password_hidden']) || !empty($_POST['modify_password_hidden'])) - { - $error = 'bad_login_or_password'; - } - else - { - // sécurisation de la saisie - $new_password = Security::secureString($_POST['new_password']); - $login = Security::secureString($_POST['login']); - $old_password = Security::secureString($_POST['old_password']); - - // éviter d'enregistrer une chaîne vide - $new_password = removeSpacesTabsCRLF($new_password); - - // tests de conformité - if($login != $_POST['login'] || $old_password != $_POST['old_password'] || $new_password != $_POST['new_password']) - { - $error = 'forbidden_characters'; - } - elseif($login !== $_SESSION['user']){ - $error = 'bad_login_or_password'; - } - else - { - $user = getUser($login, $entityManager); - - if(password_verify($old_password, $user->getPassword())) - { - // enregistrement et redirection - $new_password = password_hash($new_password, PASSWORD_DEFAULT); - $user->setPassword($new_password); - $entityManager->flush(); - $success = true; - } - else - { - $error = 'bad_login_or_password'; - } - } - } - - - // I - affichage - $title = "Nouveau mot de passe"; - $subHeading = "Veuillez vous identifier à nouveau puis saisir votre nouveau mot de passe."; - - require('../src/view/password.php'); - - echo($header); - if($error != '') - { - sleep(1); // sécurité TRÈS insuffisante à la force brute - echo($error_messages[$error]); - } - elseif($success) - { - $success = false; - echo($alertJSNewPassword); - //header("Location: " . new URL(['page' => $_GET['from']])); // choisir "location" entre PHP et JS - die; - } - echo($formulaireModifMDP); - echo($footer); - die; -} - - -function getUser(string $login, EntityManager $entityManager): ?User -{ - $users = $entityManager->getRepository('App\Entity\User')->findBy(['login' => $login]); - - if(count($users) === 0) - { - $_SESSION['user'] = ''; - $_SESSION['admin'] = false; - } - - foreach($users as $user) - { - if($user->getLogin() === $login) - { - return $user; - } - } - return null; -} - - -function disconnect() -{ - // nettoyage complet - $_SESSION = []; // mémoire vive - session_destroy(); // fichier côté serveur - setcookie('PHPSESSID', '', time() - 4200, '/'); // cookie de session - $link = new URL(['page' => $_GET['page']]); - isset($_GET['id']) ? $link->addParams(['id' => $_GET['id']]) : ''; - header('Location: ' . $link); - die; -} \ No newline at end of file -- cgit v1.2.3