- $this->getdata(['course', $this->getUrl(2), 'report']),
- 'help' => 'Ne s\'applique pas à l\'inscription anonyme',
+ 'help' => 'Enregistre une trace des consultations. Ne s\'applique pas à l\'inscription anonyme',
]); ?>
diff --git a/core/module/user/user.php b/core/module/user/user.php
index 2954669..563afa7 100644
--- a/core/module/user/user.php
+++ b/core/module/user/user.php
@@ -27,6 +27,7 @@ class user extends common
'logout' => self::GROUP_MEMBER,
'forgot' => self::GROUP_VISITOR,
'login' => self::GROUP_VISITOR,
+ 'auth' => self::GROUP_VISITOR,
'reset' => self::GROUP_VISITOR,
'profil' => self::GROUP_ADMIN,
'profilEdit' => self::GROUP_ADMIN,
@@ -1227,9 +1228,6 @@ class user extends common
}
}
- /**
- * Connexion
- */
public function login()
{
// Soumission du formulaire
@@ -1262,7 +1260,7 @@ class user extends common
'lastFail' => time(),
'ip' => helper::getIp()
]
- ], false);
+ ]);
// Verrouillage des IP
$ipBlackList = helper::arrayColumn($this->getData(['blacklist']), 'ip');
if (
@@ -1303,37 +1301,14 @@ class user extends common
and $this->getData(['user', $userId, 'group']) >= self::GROUP_MEMBER
and $captcha === true
) {
- // RAZ
+
+ // RAZ des compteurs de blocage
$this->setData(['user', $userId, 'connectFail', 0], false);
$this->setData(['user', $userId, 'connectTimeout', 0], false);
- // Clé d'authenfication
- $authKey = uniqid('', true) . bin2hex(random_bytes(8));
- $this->setData(['user', $userId, 'authKey', $authKey], false);
-
- // Validité du cookie
- $expire = $this->getInput('userLoginLongTime', helper::FILTER_BOOLEAN) === true ? strtotime("+1 year") : 0;
- switch ($this->getInput('userLoginLongTime', helper::FILTER_BOOLEAN)) {
- case false:
- // Cookie de session
- setcookie('ZWII_USER_ID', $userId, $expire, helper::baseUrl(false, false), '', helper::isHttps(), true);
- //setcookie('ZWII_USER_PASSWORD', $this->getData(['user', $userId, 'password']), $expire, helper::baseUrl(false, false), '', helper::isHttps(), true);
-
- // Connexion par clé
- setcookie('ZWII_AUTH_KEY', $authKey, $expire, helper::baseUrl(false, false), '', helper::isHttps(), true);
- break;
- default:
- // Cookie persistant
- setcookie('ZWII_USER_ID', $userId, $expire, helper::baseUrl(false, false));
- //setcookie('ZWII_USER_PASSWORD', $this->getData(['user', $userId, 'password']), $expire, helper::baseUrl(false, false));
-
- // Connexion par clé
- setcookie('ZWII_AUTH_KEY', $authKey, $expire, helper::baseUrl(false, false));
- break;
- }
-
// Accès multiples avec le même compte
$this->setData(['user', $userId, 'accessCsrf', $_SESSION['csrf']], false);
+
// Valeurs en sortie lorsque le site est en maintenance et que l'utilisateur n'est pas administrateur
if (
$this->getData(['config', 'maintenance'])
@@ -1345,7 +1320,49 @@ class user extends common
'state' => false
]);
} else {
- $logStatus = 'Connexion réussie';
+ /**
+ * Le site n'est pas en maintenance
+ * Double authentification en cas de saisie correcte
+ */
+
+ // Clé d'authenfication utlisée pour lié le compte au cookie au lieu de stocke le hash du mot de passe
+ $authKey = uniqid('', true) . bin2hex(random_bytes(8));
+ if ($this->getData(['config', 'connect', 'mailAuth']) >= $this->getData(['user', $userId, 'group'])) {
+ $logStatus = 'Envoi du mail d\'authentification';
+ // Redirection vers la page d'authentification
+ $authRedirect = 'user/auth/';
+ // Stocker la clé envoyée par email
+ $this->setData(['user', $userId, 'authKey', rand(100000, 999999)]);
+
+ } else {
+ $logStatus = 'Connexion réussie';
+ // La page d'autentification est vide
+ $authRedirect = '';
+ $this->setData(['user', $userId, 'authKey', $authKey]);
+
+ }
+
+ // Validité du cookie
+ $expire = $this->getInput('userLoginLongTime', helper::FILTER_BOOLEAN) === true ? strtotime("+1 year") : 0;
+ switch ($this->getInput('userLoginLongTime', helper::FILTER_BOOLEAN)) {
+ case false:
+ // Cookie de session
+ setcookie('ZWII_USER_ID', $userId, $expire, helper::baseUrl(false, false), '', helper::isHttps(), true);
+ //setcookie('ZWII_USER_PASSWORD', $this->getData(['user', $userId, 'password']), $expire, helper::baseUrl(false, false), '', helper::isHttps(), true);
+
+ // Connexion par clé
+ setcookie('ZWII_AUTH_KEY', $authKey, $expire, helper::baseUrl(false, false), '', helper::isHttps(), true);
+ break;
+ default:
+ // Cookie persistant
+ setcookie('ZWII_USER_ID', $userId, $expire, helper::baseUrl(false, false));
+ //setcookie('ZWII_USER_PASSWORD', $this->getData(['user', $userId, 'password']), $expire, helper::baseUrl(false, false));
+
+ // Connexion par clé
+ setcookie('ZWII_AUTH_KEY', $authKey, $expire, helper::baseUrl(false, false));
+ break;
+ }
+
$pageId = $this->getUrl(2);
if (
$this->getData(['config', 'page404']) === $pageId
@@ -1353,7 +1370,7 @@ class user extends common
) {
$pageId = '';
}
- $redirect = ($pageId && strpos($pageId, 'user_reset') !== 0) ? helper::baseUrl() . str_replace('_', '/', str_replace('__', '#', $pageId)) : helper::baseUrl();
+ $redirect = ($pageId && strpos($pageId, 'user_reset') !== 0) ? helper::baseUrl() . $authRedirect . str_replace('_', '/', str_replace('__', '#', $pageId)) : helper::baseUrl() . $authRedirect;
// Valeurs en sortie
$this->addOutput([
'notification' => sprintf(helper::translate('Bienvenue %s %s'), $this->getData(['user', $userId, 'firstname']), $this->getData(['user', $userId, 'lastname'])),
@@ -1366,7 +1383,7 @@ class user extends common
$notification = helper::translate('Captcha, identifiant ou mot de passe incorrects');
$logStatus = $captcha === true ? 'Erreur de mot de passe' : 'Erreur de captcha';
// Cas 1 le nombre de connexions est inférieur aux tentatives autorisées : incrément compteur d'échec
- if ($this->getData(['user', $userId, 'connectFail']) < $this->getData(['config', 'connect', 'attempt'])) {
+ if ($this->getData(['user', $userId, 'connectFail']) < $this->getData(['config', 'connect', 'attempt'], false)) {
$this->setData(['user', $userId, 'connectFail', $this->getdata(['user', $userId, 'connectFail']) + 1], false);
}
// Cas 2 la limite du nombre de connexion est atteinte : placer le timer
@@ -1384,10 +1401,9 @@ class user extends common
]);
}
}
- // Sauvegarde la base manuellement
- $this->saveDB(module: 'user');
+ // Force la sauvegarde
+ $this->saveDB('user');
}
-
// Journalisation
$this->saveLog($logStatus);
@@ -1403,16 +1419,108 @@ class user extends common
]);
}
+ /**
+ *
+ * Validation de la connexion par email
+ * @return void
+ */
+ public function auth()
+ {
+ // Soumission du formulaire
+ if (
+ $this->isPost()
+ ) {
+ // Vérifier la clé saisie
+ $targetKey = $this->getData(['user', $this->getUser('id'), 'authKey']);
+ $inputKey = $this->getInput('userAuthKey', helper::FILTER_INT);
+ if (
+ $targetKey === $inputKey &&
+ $this->getData(['user', $this->getUser('id'), 'connectTimeout']) + 3600 >= time()
+ ) {
+ $pageId = $this->getUrl(2);
+ // La fiche de l'utilisateur contient la clé d'authentification
+ $this->setData(['user', $this->getUser('id'), 'authKey', $this->getInput('ZWII_AUTH_KEY')]);
+ $redirect = ($pageId && strpos($pageId, 'user_reset') !== 0) ? helper::baseUrl() . str_replace('_', '/', str_replace('__', '#', $pageId)) : helper::baseUrl();
+ // Journalisation
+ $this->saveLog('Connexion réussie');
+ // Réinitialiser le compteur de temps
+ $this->setData(['user', $this->getUser('id'), 'connectTimeout', 0]);
+ // Valeurs en sortie
+ $this->addOutput([
+ 'redirect' => $redirect,
+ 'notification' => helper::translate('Connexion réussie'),
+ 'state' => true
+ ]);
+ } else {
+
+ // Supprime la clé stockée et le temps limite
+ $this->deleteData(['user', $this->getUser('id'), 'authKey']);
+ // Réinitialiser le compteur de temps
+ $this->setData(['user', $this->getUser('id'), 'connectTimeout', 0]);
+
+ // Détruit les cookies d'authenfication
+ helper::deleteCookie('ZWII_USER_ID');
+ helper::deleteCookie('ZWII_AUTH_KEY');
+
+ // Détruit la session
+ session_destroy();
+
+ // Journalisation
+ $this->saveLog('Erreur de vérification de la clé envoyée par email ' . $this->getUser('id'));
+
+ // Valeurs en sortie
+ $this->addOutput([
+ 'redirect' => helper::baseUrl(),
+ 'notification' => helper::translate('La clé est incorrecte'),
+ 'state' => false
+ ]);
+ }
+ } else {
+ /**
+ * Envoi d'un email contenant une clé
+ * Stockage de la clé dans le compte de l'utilisateur
+ */
+ // La clé est envoyée une seule fois
+ $sent = false;
+ if (
+ $this->getData(['user', $this->getUser('id'), 'authKey'])
+ && $this->getData(['user', $this->getUser('id'), 'connectTimeout']) === 0
+ ) {
+ $sent = $this->sendMail(
+ $this->getUser('mail'),
+ 'Tentative de connexion à votre',
+ //'Bonjour
' . $item['prenom'] . ' ' . $item['nom'] . ',
' .
+ '
Clé de validation à saisir dans le formulaire :
' .
+ '
' . $this->getData(['user', $this->getUser('id'), 'authKey']) . '
',
+ null,
+ $this->getData(['config', 'smtp', 'from'])
+ );
+ // Stocker l'envoi de l'email
+ $this->setData(['user', $this->getUser('id'), 'connectTimeout', time()]);
+ }
+
+ // Message envoyé sinon la connexion est réalisée pour ne pas bloquer.
+ if ($sent === false) {
+
+ }
+ // Valeurs en sortie
+ $this->addOutput([
+ 'title' => helper::translate('Double authentification'),
+ 'view' => 'auth',
+ 'display' => self::DISPLAY_LAYOUT_LIGHT,
+ ]);
+ }
+ }
+
/**
* Déconnexion
*/
public function logout()
{
+ // Détruit les cookies d'authenfication
helper::deleteCookie('ZWII_USER_ID');
- //helper::deleteCookie('ZWII_USER_PASSWORD');
helper::deleteCookie('ZWII_AUTH_KEY');
-
// Détruit la session
session_destroy();
diff --git a/core/module/user/view/auth/auth.css b/core/module/user/view/auth/auth.css
new file mode 100644
index 0000000..e217932
--- /dev/null
+++ b/core/module/user/view/auth/auth.css
@@ -0,0 +1,36 @@
+/**
+ * This file is part of Zwii.
+ *
+ * For full copyright and license information, please see the LICENSE
+ * file that was distributed with this source code.
+ *
+ * @author Rémi Jean
+ * @copyright Copyright (C) 2008-2018, Rémi Jean
+ * @author Frédéric Tempez
+ * @copyright Copyright (C) 2018-2024, Frédéric Tempez
+ * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
+ * @link http://zwiicms.fr/
+ */
+
+/** @import url("site/data/admin.css"); */
+
+/** NE PAS EFFACER
+* admin.css
+*/
+
+@media screen and (max-width: 768px) {
+ #buttonsContainer {
+ display: grid;
+ }
+ #loginContainer {
+ order: 1;
+ }
+ #backContainer{
+ order: 2;
+ }
+}
+
+#userAuthKey {
+ text-align: center;
+ font-size: 1.3rem;
+}
\ No newline at end of file
diff --git a/core/module/user/view/auth/auth.php b/core/module/user/view/auth/auth.php
new file mode 100644
index 0000000..ca948b6
--- /dev/null
+++ b/core/module/user/view/auth/auth.php
@@ -0,0 +1,23 @@
+
+
+
+ helper::translate('Clé reçue par couriel')
+ ]); ?>
+
+
+
+
\ No newline at end of file