diff --git a/CHANGES.md b/CHANGES.md
index 66f671d6..d421e9c6 100755
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,13 +2,15 @@
## Versions 13.5.00
**Améliorations :**
+- Validation de la connexion au site grâce à l'envoi d'un code par email. L'option est activée depuis la configuration du site, onglet connexion. Elle s'active par groupe montant, exemple "éditeur" pour éditeurs et administrateurs.
- Optimisation du chargement des variables de classe.
- Suppression de redondance de déclaration des charset.
-**Corrections : **
+**Corrections :**
- Corrige un bug de changement de mot de passe pour les comptes non admin.
- Blog 7.12, corrige un bug d'affichage des articles lorsque le thème Moderne est sélectionné.
- Corrige un dysfonctionnement de la fonction de tronquage subword qui perturbait l'affichage des articles de blog.
+- Activation de la mémorisation de l'onglet actif dans la configuration après validation du formulaire ou visite d'une autre page du site.
## Versions 13.4.00
** Améliorations :**
diff --git a/core/class/helper.class.php b/core/class/helper.class.php
index 09365b25..f8853c3c 100644
--- a/core/class/helper.class.php
+++ b/core/class/helper.class.php
@@ -343,7 +343,7 @@ class helper
public static function checkRewrite()
{
// N'interroge que le serveur Apache
- if (strpos($_SERVER["SERVER_SOFTWARE"], 'Apache') > 0) {
+ if ((helper::checkServerSoftware() === false)) {
self::$rewriteStatus = false;
} else {
// Ouvre et scinde le fichier .htaccess
@@ -353,6 +353,14 @@ class helper
}
return self::$rewriteStatus;
}
+
+ /**
+ * Retourne vrai ou faux selon que le serveur est comptatible avec htaccess
+ * @return bool
+ */
+ public static function checkServerSoftware() {
+ return (stripos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false || stripos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false);
+ }
/**
* Renvoie le numéro de version de Zwii est en ligne
diff --git a/core/module/config/config.php b/core/module/config/config.php
index 674daa7b..f431f1d6 100644
--- a/core/module/config/config.php
+++ b/core/module/config/config.php
@@ -496,7 +496,8 @@ class config extends common
'autoDisconnect' => $this->getInput('connectAutoDisconnect', helper::FILTER_BOOLEAN),
'captchaType' => $this->getInput('connectCaptchaType'),
'showPassword' => $this->getInput('connectShowPassword', helper::FILTER_BOOLEAN),
- 'redirectLogin' => $this->getInput('connectRedirectLogin', helper::FILTER_BOOLEAN)
+ 'redirectLogin' => $this->getInput('connectRedirectLogin', helper::FILTER_BOOLEAN),
+ 'mailAuth' => $this->getInput('connectAuthMail', helper::FILTER_BOOLEAN),
]
]
]);
diff --git a/core/module/config/view/connect/connect.php b/core/module/config/view/connect/connect.php
index 2f6ee633..86368471 100644
--- a/core/module/config/view/connect/connect.php
+++ b/core/module/config/view/connect/connect.php
@@ -3,13 +3,7 @@
-
-
-
+
'Limitation des tentatives',
'selected' => $this->getData(['config', 'connect', 'attempt'])
]); ?>
-
+
'Blocage après échecs',
'selected' => $this->getData(['config', 'connect', 'timeout'])
]); ?>
+ 'Aucune'], self::$groupNews), [
+ 'label' => 'Validation par messagerie',
+ 'selected' => $this->getData(['config', 'connect', 'mailAuth']),
+ 'help' => 'La connexion est confirmée par une clé adressée par messagerie. Depuis le groupe sélectionnée et les groupes supérieurs.'
]); ?>
diff --git a/core/module/config/view/setup/setup.php b/core/module/config/view/setup/setup.php
index e400b866..d254279a 100644
--- a/core/module/config/view/setup/setup.php
+++ b/core/module/config/view/setup/setup.php
@@ -44,7 +44,7 @@
helper::checkRewrite(),
'help' => 'Supprime le point d\'interrogation dans les URL, l\'option est indisponible avec les autres serveurs Web',
- 'disabled' => stripos($_SERVER["SERVER_SOFTWARE"], 'Apache') === false and $module->isModRewriteEnabled()
+ 'disabled' => helper::checkServerSoftware() === false and $module->isModRewriteEnabled()
]); ?>
diff --git a/core/module/user/user.php b/core/module/user/user.php
index 20c69b36..928e5556 100644
--- a/core/module/user/user.php
+++ b/core/module/user/user.php
@@ -26,6 +26,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,
@@ -66,7 +67,7 @@ class user extends common
public static $groupProfils = [
self::GROUP_MEMBER => 'Membre',
- self::GROUP_EDITOR => 'Éditeur'
+ self::GROUP_EDITOR => 'Éditeur',
];
public static $listModules = [];
@@ -1043,37 +1044,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]);
-
- // 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'])
@@ -1085,7 +1063,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
@@ -1093,7 +1113,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'])),
@@ -1142,16 +1162,107 @@ 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'] . ',