123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- <?php
- declare(strict_types=1);
- $ALLOWED_SYMBOLS = array('#', '_', '-', '!', '[', ']', '=', '~', '*', '@','/','\\','$','%','?','&','(',')');
- // --------
- // Sécurité
- // --------
- if (isValidConstant() != 1) {
- fermeSessionUtilisateur();
- }
- use chillerlan\QRCode\QRCode;
- use chillerlan\QRCode\QROptions;
- require_once("lib/Password.php");
- require_once("lib/lib2fa.inc.php");
- // Style spécial pour le profil
- echo "<link type=\"text/css\" href=\"css/style_viewer.css\" rel=\"stylesheet\" />\n";
- // Gestionnaire de mot de passe JavaScript
- // https://www.cssscript.com/check-strength-passwords-pwstrength/
- // https://www.netwrix.com/password_best_practice.html
- // Retenir les 10 derniers mots de passe pour éviter une réutilisation.
- // Rotation au 6 mois
- // Notification par courriel de l'expiration du mot de passe.
- // En cas de doute, changer le mot de passe pour votre sécurité.
- // Possibilité d'utiliser une phrase comme mot de passe.
- // Proposer un générateur de mot de passe pour navigateur.
- // Historique des mots de passe
- // https://phpgurukul.com/maintain-password-history-using-php-mysql/
- // https://huboftutorials.com/how-to-maintain-password-history-using-php-and-mysql/
- // ------------------------------
- // Caractéristiques du module
- // ------------------------------
- unset($module);
- $module = array(
- "titre" => "Profil de l'utilisateur",
- "urldest" => $SCRIPT_NAME . "?page=profil",
- "recherche" => array("engin" => false),
- "jeton" => $jeton,
- "compte" => 0,
- "taille" => "800px",
- "msg" => array(
- "maj_ok" => "Mise à jour du mot de passe effectuée avec succès.",
- "maj_echec" => "L'opération de mise à jour du mot de passe a échouée.",
- "maj_info_ok" => "Mise à jour des informations personnelles effectuée avec succès.",
- "maj_info_echec" => "L'opération de mise à jour des informations personnelles a échouée.",
- "maj_jeton_ok" => "Mise à jour du jeton de sécurité effectuée avec succès.",
- "maj_jeton_echec" => "L'opération de mise à jour du jeton de sécurité a échouée."
- )
- );
- $sqlparam["connexion"] = "maitre";
- $sqlparam["table"][] = "administration";
- $sqlparam["where"][] = "refutilisateur =" . $_SESSION["noutilisateur"];
- $result = executerRequeteSql($sqlparam);
- if (isset($result) && !empty($result)) {
- $lcellulaire = $result[0]["cellulaire"];
- $lfournisseur = $result[0]["fournisseur"];
- }
- // ------------------
- // Requête sur le tri
- // ------------------
- if (isset($action)) {
- $msg = "";
- //Cueillette de données du formulaire
- if ($action == "Changer votre mot de passe") {
- $password = new PHPPassword\Password(array(
- 'minLength' => 12,
- 'minNumbers' => 3,
- 'minLetters' => 6,
- 'minLowerCase' => 3,
- 'minUpperCase' => 3,
- 'minSymbols' => 2,
- 'maxSymbols' => 3,
- 'allowedSymbols' => $ALLOWED_SYMBOLS
- ));
- $pattern = "/[^a-zA-Z]/";
- if (!empty(filter_input(INPUT_POST, 'motDePasseActuel'))) {
- $motDePasseActuel = antiInjection(filter_input(INPUT_POST, 'motDePasseActuel'));
- }
- if (!empty(filter_input(INPUT_POST, 'motDePasseNouveau'))) {
- $motDePasseNouveau = antiInjection(filter_input(INPUT_POST, 'motDePasseNouveau'));
- }
- if (!empty(filter_input(INPUT_POST, 'confirmation'))) {
- $confirmation = antiInjection(filter_input(INPUT_POST, 'confirmation'));
- }
- $badResult = false;
- //Mot de passe actuel vide
- if (empty($motDePasseActuel)) {
- $badResult = true;
- $msg = "Le mot de passe actuel est vide.";
- }
- //Nouveau mot de passe actuel vide
- if (!$badResult && empty($motDePasseNouveau)) {
- $badResult = true;
- $msg = "Le nouveau mot de passe est vide.";
- }
- //confirmation actuel vide
- if (!$badResult && empty($confirmation)) {
- $badResult = true;
- $msg = "La confirmation est vide.";
- }
- // Le même que celui actuellement utilisé ?
- if (!$badResult && $motDePasseNouveau === $motDePasseActuel) {
- $badResult = true;
- $msg = "Le nouveau mot de passe est identique à celui actuellement utilisé.";
- }
- // Mot de passe différent ?
- if (!$badResult && $motDePasseNouveau !== $confirmation) {
- $badResult = true;
- $msg = "Le nouveau mot de passe diffère de la confirmation.";
- }
- // Mot de passe presque identique ou similaire
- if (!$badResult && levenshtein($motDePasseActuel, $motDePasseNouveau) <= 4) {
- $badResult = true;
- $msg = "Le nouveau mot de passe est trop similaire au mot de passe actuel.";
- }
- // Respecte la politique de création des mots de passe ?
- //TODO en faire une négation pour validatePassword.
- if (!$badResult && $password->validatePassword($motDePasseNouveau)) {
- $badResult = true;
- $msg = "Le nouveau mot de passe ne respecte pas la politique de création des mots de passe.";
- }
- // Prévention contre les attaques de dictionnaire
- if (!$badResult) {
- unset($sqlparam);
- $sqlparam["connexion"] = "maitre";
- $sqlparam["table"][] = "dictionnaire_mdp";
- $sqlparam["where"][] = "entree like '%" . $motDePasseNouveau . "%'";
- $result = executerRequeteSql($sqlparam);
- if (isset($result) && !empty($result)) {
- $badResult = true;
- $msg = "Le nouveau mot de passe est sujet à des attaques. Veuillez le changer";
- }
- if (!$badResult) {
- $valeur = preg_replace($pattern, $replacement, $motDePasseNouveau);
- unset($sqlparam);
- $sqlparam["connexion"] = "maitre";
- $sqlparam["table"][] = "dictionnaire_mdp";
- $sqlparam["where"][] = "entree like '%" . $valeur . "%'";
- $result = executerRequeteSql($sqlparam);
- if (isset($result)) {
- $badResult = true;
- $msg = "Le nouveau mot de passe est sujet à des attaques. Veuillez le changer";
- }
- }
- }
- // Le nouveau mot de passe ne peut pas être un mot de passe déjà utilisé
- if (!$badResult) {
- unset($sqlparam);
- $sqlparam["connexion"] = "maitre";
- $sqlparam["table"][] = "historique_mdp";
- $sqlparam["where"][] = "noutilisateur = " . $_SESSION["noutilisateur"];
- $sqlparam["champs"][] = "hashloginmps";
- $sqlparam["limite"] = 10;
- $result = executerRequeteSql($sqlparam);
- if (isset($result)) {
- foreach ($result as &$valeur) {
- if (password_verify($motDePasseNouveau, $valeur["hashloginmps"])) {
- $badResult = true;
- $msg = "Vous avez déjà utilisé ce mot de passe auparavant.";
- break;
- }
- }
- }
- }
- // Mise à jour du mot de passe si tout est ok.
- if (!$badResult) {
- unset($sqlparam);
- $sqlparam["connexion"] = "maitre";
- $sqlparam["type"] = "UPDATE";
- $sqlparam["table"][] = "administration";
- $sqlparam["champs"]["hashloginmps"] = sprintf("'%s'", password_hash($motDePasseNouveau, PASSWORD_DEFAULT));
- $sqlparam["champs"]["temporaire"] = 0;
- $sqlparam["where"][] = "refutilisateur =" . $_SESSION["noutilisateur"];
- $result = executerRequeteSql($sqlparam);
- if (isset($result)) {
- $module["resultatSQL"] = true;
- $module["message"] = $module["msg"]["maj_ok"];
- unset($sqlparam);
- $sqlparam["connexion"] = "maitre";
- $sqlparam["table"][] = "administration";
- $sqlparam["champs"][] = "hashloginmps";
- $sqlparam["where"][] = "refutilisateur =" . $_SESSION["noutilisateur"];
- $result = executerRequeteSql($sqlparam);
- unset($sqlparam);
- $sqlparam["connexion"] = "maitre";
- $sqlparam["type"] = "INSERT";
- $sqlparam["table"][] = "historique_mdp";
- $sqlparam["champs"]["noutilisateur"] = "'" . $_SESSION["noutilisateur"] . "'";
- $sqlparam["champs"]["hashloginmps"] = sprintf("'%s'", $result[0]["hashloginmps"]);
- executerRequeteSql($sqlparam);
- $_SESSION["temporaire"] = 0;
- } else {
- $module["resultatSQL"] = false;
- $module["message"] = $module["msg"]["maj_echec"];
- }
- } else {
- $module["resultatSQL"] = false;
- $module["message"] = $msg;
- }
- } elseif ($action == "Appliquer votre jeton de sécurité") {
- if (!empty($jetonsec)) {
- $secret = $_SESSION["temporary2fa"];
- unset($sqlparam);
- $sqlparam["connexion"] = "maitre";
- $sqlparam["type"] = "UPDATE";
- $sqlparam["table"][] = "administration";
- $sqlparam["champs"]["secret2fa"] = "'$secret'";
- $sqlparam["where"][] = "refutilisateur =" . $_SESSION["noutilisateur"];
- $result = executerRequeteSql($sqlparam);
- if (isset($result) && check2fa($secret, $jetonsec)) {
- $module["resultatSQL"] = true;
- $module["message"] = $module["msg"]["maj_jeton_ok"];
- $_SESSION["2fa_set"] = true;
- unset($_SESSION["temporary2fa"]);
- } else {
- //En cas d'erreur, vider le champ
- unset($sqlparam);
- $sqlparam["connexion"] = "maitre";
- $sqlparam["type"] = "UPDATE";
- $sqlparam["table"][] = "administration";
- $sqlparam["champs"]["secret2fa"] = "NULL";
- $sqlparam["where"][] = "refutilisateur =" . $_SESSION["noutilisateur"];
- executerRequeteSql($sqlparam);
- $module["resultatSQL"] = false;
- $module["message"] = $module["msg"]["maj_jeton_echec"];
- $_SESSION["2fa_set"] = false;
- }
- } else {
- $module["resultatSQL"] = false;
- $module["message"] = "Jeton de sécurité vide";
- }
- } elseif ($action == "Mettre à jour vos informations personnelles") {
- unset($sqlparam);
- $sqlparam["connexion"] = "maitre";
- $sqlparam["type"] = "UPDATE";
- $sqlparam["table"][] = "administration";
- $sqlparam["champs"]["cellulaire"] = "'$cellulaire'";
- $sqlparam["champs"]["fournisseur"] = "'$fournisseur'";
- $sqlparam["where"][] = "refutilisateur =" . $_SESSION["noutilisateur"];
- $result = executerRequeteSql($sqlparam);
- if (isset($result)) {
- $module["resultatSQL"] = true;
- $module["message"] = $module["msg"]["maj_info_ok"];
- } else {
- $module["resultatSQL"] = false;
- $module["message"] = $module["msg"]["maj_info_echec"];
- }
- }
- }
- //Afficher les symboles permis dans le mot de passe.
- function afficheSymboles($ALLOWED_SYMBOLS) {
- $symboles="";
- foreach ($ALLOWED_SYMBOLS as $clef => $valeur) {
- $symboles .= " ".$valeur." ";
- }
- return $symboles;
- }
- // Barre de menu
- print preparerModule($module);
- ?>
- <form Method="Post" Action="index2.php?page=profil" name="formulaire">
- <?php
- if ($_SESSION["temporaire"] == 0 && $_SESSION["2fa_set"]) {
- ?>
- <div class="boitelogin2">
- <fieldset>
- <legend>Zone de contrôle 1</legend>
- <div class='mdp'>
- <div style='width:200px; float:left;'>
- <label for="motDePasseActuel">Mot de passe actuel : </label>
- </div>
- <input type="text" id="motDePasseActuel" name="motDePasseActuel"/>
- </div>
- <div style='clear:both;'></div>
- <div class='mdp'>
- <div style='width:200px; float:left;'>
- <label for="motDePasseNouveau">Nouveau mot de passe : </label>
- </div>
- <input type="text" id="motDePasseNouveau" name="motDePasseNouveau"/>
- </div>
- <div style='clear:both;'></div>
- <div class='mdp'>
- <div style='width:200px; float:left;'>
- <label for="Confirmation">Confirmation : </label>
- </div>
- <input type="text" id="confirmation" name="confirmation"/>
- </div>
- <br />
- <input type="submit" class="button2" name="action" value="Changer votre mot de passe"/>
- <input type="hidden" name="jeton" value="<?php print $jeton; ?>"/>
- </fieldset>
- <br />
- Règles pour la création d'un mot de passe :<br>
- <ul>
- <li>Longueur minimale : 12 caractères</LI>
- <li>Minimum de 6 lettres</li>
- <li>2 nombres présents (0-9)</li>
- <li>3 caractères en minuscule</li>
- <li>3 caractères en majuscule</li>
- <li> Présence de 2 à 3 caractères spéciaux ci-dessous<br>
- <pre><?php print afficheSymboles($ALLOWED_SYMBOLS); ?></pre>
- </li>
- </ul>
- Truc : L'emploi d'une phrase facile à retenir est aussi possible.<br/>
- <i>Exemple : L'été sera Merveilleux au Chalet en 2030![</i>
- </div>
- <div class="boitelogin2">
- <fieldset>
- <legend>Informations personnelles</legend>
- <div class='mdp'>
- <div style='width:125px; float:left;'>
- <label for="cellulaire">Cellulaire : </label>
- </div>
- <input type="text" id="cellulaire" name="cellulaire" value="<?php print $lcellulaire; ?>" SIZE='14' MAXLENGTH='14'/>
- </div>
- <div style='clear:both;'></div>
- <div class='mdp'>
- <div style='width:125px; float:left;'>
- <label for="fournisseur">Fournisseur : </label>
- </div>
- <?php
- unset($result2);
- $result2 = getFournisseursCellulaire();
- unset($param);
- $param["form"] = "menu2";
- $param["nom"] = "fournisseur";
- $param["etq"] = "";
- $param["defaut"] = $lfournisseur;
- $param["donnees"] = $result2;
- $param["menu"] = true;
- //TODO Mettre un évènement vide pour contourner le gestionnaire interne. À corriger.
- $param["evt"] = "blank";
- print formListbox2($param);
- ?>
- </div>
- <div style='clear:both;'></div>
- <br />
- <input type="submit" class="button2" name="action" value="Mettre à jour vos informations personnelles"/>
- <input type="hidden" name="jeton" value="<?php print $jeton; ?>"/>
- </fieldset>
- </div>
- <script type='text/javascript'>
- // Mise en place des masques de saisie
- $(document).ready(function () {
- $("#cellulaire").mask("(999) 999-9999");
- });
- </script>
- <?php
- } else if ($_SESSION["temporaire"] == 1 && (!$_SESSION["2fa_set"] || empty($_SESSION["2fa_set"]))) {
- ?>
- <div class="boitelogin">
- <fieldset>
- <legend>Zone de contrôle2</legend>
- <div class='mdp'>
- <div style='width:200px; float:left;'>
- <label for="motDePasse">Mot de passe actuel : </label>
- </div>
- <input type="text" id="motDePasseActuel" name="motDePasseActuel"/>
- </div>
- <div style='clear:both;'></div>
- <div class='mdp'>
- <div style='width:200px; float:left;'>
- <label for="motDePasseNouveau">Nouveau mot de passe : </label>
- </div>
- <input type="text" id="motDePasseNouveau" name="motDePasseNouveau"/>
- </div>
- <div style='clear:both;'></div>
- <div class='mdp'>
- <div style='width:200px; float:left;'>
- <label for="Confirmation">Confirmation : </label>
- </div>
- <input type="text" id="confirmation" name="confirmation"/>
- </div>
- <br />
- <input type="submit" class="button2" name="action" value="Changer votre mot de passe"/>
- <input type="hidden" name="jeton" value="<?php print $jeton; ?>"/>
- </fieldset>
- <br />
- Règles pour la création d'un mot de passe :<br>
- <ul>
- <li>Longueur minimale : 12 caractères</LI>
- <li>Minimum de 6 lettres</li>
- <li>Minimum de 2 nombres présents (0-9)</li>
- <li>Minimum de 3 lettres en minuscule</li>
- <li>Minimum de 3 lettres en majuscule</li>
- <li>Présence de 2 à 3 caractères spéciaux <br>
- <?php
- //( '#', '_', '-', '!', '[', ']', '=', '~', '*' )
- print afficheSymboles($ALLOWED_SYMBOLS);
- ?>
- </li>
- </ul>
- Truc : L'emploi d'une phrase facile à retenir est aussi possible.<br/>
- Exemple : L'été sera Merveilleux AU chalet en 2030!*
- </div>
- <?php
- } else if (!$_SESSION["2fa_set"] || empty($_SESSION["2fa_set"])) {
- $secret = getUser2faSecret();
- $_SESSION["temporary2fa"] = $secret;
- ?>
- <div class = 'authenticator'>
- <center><h1>Nouveau</h1></center>
- <p>
- Ce nouveau processus renforce la sécurité de connexion à l'application et
- s'assure que l'utilisateur est vraiment vous, comme personne.
- </p>
- <p>
- Désormais, l'utilisation d'une application sera requise pour votre sécurité.
- Ce processus est simple.
- </p>
- <ol>
- <li>
- Installer l'application Microsoft Authenticator sur votre téléphone cellulaire.<br>
- <a href="https://www.microsoft.com/fr-ca/security/mobile-authenticator-app">Cliquer ici</a>
- <br>
- <img id = "authenticator" src = "images/ms_authenticator.png" alt = "Microsoft Authenticator" width = "400" height = "96" />
- <br>
- <span style="color:blue;font-size:11px;">
- <i>Cliquer sur l'image pour l'agrandir.</i>
- </span>
- </li>
- <li>
- <p>
- Dans l'application Microsoft Authenticator, effectuer ces quelques étapes.
- </p>
- <ol>
- <li>Cliquer sur le symbole «+» pour ajouter un compte</li>
- <li>Choisissez le type de compte professionnel ou scolaire</li>
- <li>Lire (scanner) le code QR ci-dessous afin
- d'ajouter le site web des libérations comme émetteur de jeton de sécurité</li>
- </ol>
- <p>
- <?php
- // Voir la librairie lib2fa pour savoir comment créer des code qr avec Microsoft Authenticator.
- //TODO changer l'émetteur dans l'adresse de l'image
- $data = "otpauth://totp/liberations:" . $_SESSION["adressecourriel"] . "?secret=$secret&issuer=https://liberations.infinityfreeapp.com/";
- print "<img src='" . (new QRCode)->render($data) . "' alt='Code QR' />";
- ?>
- </p>
- </li>
- <li>
- Inscrire un jeton de sécurité provenant de Microsoft Authenticator afin d'activer la sécurité renforcée
- et confirmer que la nouvelle sécurité est active.
- <div class='mdp'>
- <div style='width:200px; float:left;'>
- <label for="jeton">Jeton de sécurité : </label>
- </div>
- <input type="text" id="jetonsec" name="jetonsec"/>
- </div>
- <br />
- <input type="submit" class="button2" name="action" value="Appliquer votre jeton de sécurité"/>
- </li>
- </ol>
- </div>
- <div id="image-viewer">
- <span class="close">×</span>
- <img class="modal-content" id="full-image">
- </div>
- <script type='text/javascript'>
- $("#authenticator").click(function () {
- $("#full-image").attr("src", $(this).attr("src"));
- $('#image-viewer').show();
- });
- $("#image-viewer .close").click(function () {
- $('#image-viewer').hide();
- });
- </script>
- <?php
- }
- ?>
- </form>
|