From c5544b81b3220ec0583f5cdda3878491c9f0846f Mon Sep 17 00:00:00 2001 From: Jean-Christian Denis Date: Sat, 31 Dec 2022 01:48:40 +0100 Subject: [PATCH] full rewrite for dotclear 2.24 --- _admin.php | 47 ++- _define.php | 46 ++- _init.php | 21 ++ _install.php | 73 ++-- _prepend.php | 24 ++ _public.php | 154 +++----- inc/class.httppassword.php | 107 ++++++ index.php | 714 ++++++++++++++----------------------- js/index.js | 13 + locales/fr/main.po | 84 +++++ 10 files changed, 656 insertions(+), 627 deletions(-) create mode 100644 _init.php create mode 100644 _prepend.php create mode 100644 inc/class.httppassword.php create mode 100644 js/index.js create mode 100644 locales/fr/main.po diff --git a/_admin.php b/_admin.php index bc35b3a..9ed469f 100644 --- a/_admin.php +++ b/_admin.php @@ -1,27 +1,26 @@ addItem('httpPassword', - 'plugin.php?p=httpPassword', - 'index.php?pf=httpPassword/icon.png', - preg_match('/plugin.php\?p=httpPassword(&.*)?$/', - $_SERVER['REQUEST_URI']), - $core->auth->check('usage,contentadmin',$core->blog->id) +dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( + __('Http password'), + dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)), + urldecode(dcPage::getPF(basename(__DIR__) . '/icon.png')), + preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__))) . '(&.*)?$/', $_SERVER['REQUEST_URI']), + dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ + dcAuth::PERMISSION_USAGE, + initHttpPassword::PERMISSION, + ]), dcCore::app()->blog->id) ); - -$core->auth->setPermissionType( - 'httpPassword', - 'Gestion de la protection du site httpPassword' -); -?> diff --git a/_define.php b/_define.php index c792639..08a6e6b 100644 --- a/_define.php +++ b/_define.php @@ -1,21 +1,33 @@ registerModule( - /* Name */ "httpPassword", - /* Description*/ "Manage .htpasswd file to make the blog private", - /* Author */ "Frederic PLE ", - /* Version */ '0.5.10', - /* Permissions */ 'httpPassword' + 'Http password', + 'Manage .htpasswd file to make the blog private', + 'Frederic PLE and contributors', + '1.0', + [ + 'requires' => [['core', '2.24']], + 'permissions' => dcCore::app()->auth->makePermissions([ + dcAuth::PERMISSION_USAGE, + initHttpPassword::PERMISSION, + ]), + 'type' => 'plugin', + 'support' => 'https://github.com/JcDenis/' . basename(__DIR__), + 'details' => 'http://plugins.dotaddict.org/dc2/details/' . basename(__DIR__), + 'repository' => 'https://raw.githubusercontent.com/JcDenis/' . basename(__DIR__) . '/master/dcstore.xml', + ] ); -?> diff --git a/_init.php b/_init.php new file mode 100644 index 0000000..6728c42 --- /dev/null +++ b/_init.php @@ -0,0 +1,21 @@ +plugins->moduleInfo('httpPassword','version'); - -$i_version = $core->getVersion('httpPassword'); - -if (version_compare($i_version,$m_version,'>=')) { - return; -} - -# Création du setting (s'il existe, il ne sera pas écrasé) -$settings = new dcSettings($core,null); -$settings->setNamespace('httppassword'); -$mydomain = preg_replace('/^.*\.([^.]+[^.])$/','$1',gethostbyaddr($_SERVER['SERVER_ADDR'])); -$defaultcrypt = ''; - -$settings->put('httppassword_active',false,'boolean','Activer',false,false); -$settings->put('httppassword_crypt',$defaultcrypt,'string','Fonction de cryptage',false,false); -$settings->put('httppassword_message','Zone Privee','String','Message personnalisable dans le popup d\'authentification',false,false); -$settings->put('httppassword_trace',false,'boolean','Activation des traces (debug)',false,false); -$settings->put('httppassword_debugmode',false,'boolean','Activation du mode Debug',false,false); - -$core->setVersion('httpPassword',$m_version); -?> +newVersion( + basename(__DIR__), + dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version') + )) { + return null; + } + + // Set settings + $s = dcCore::app()->blog->settings->get(basename(__DIR__)); + $s->put('active', false, 'boolean', 'Enable plugin', false, false); + $s->put('crypt', 'crypt_md5', 'string', 'Crypt algorithm', false, false); + $s->put('message', 'Private space', 'String', 'Personalized message on Authentication popup', false, false); + + return true; +} catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); +} + +return false; diff --git a/_prepend.php b/_prepend.php new file mode 100644 index 0000000..ae410e7 --- /dev/null +++ b/_prepend.php @@ -0,0 +1,24 @@ +autoload([ + 'httpPassword' => implode(DIRECTORY_SEPARATOR, [__DIR__, 'inc', 'class.httppassword.php']), +]); + +dcCore::app()->auth->setPermissionType( + initHttpPassword::PERMISSION, + __('Manage http password blog protection') +); diff --git a/_public.php b/_public.php index c17ea4f..233c44e 100644 --- a/_public.php +++ b/_public.php @@ -1,101 +1,65 @@ blog->settings->httppassword_active) { - $core->addBehavior('publicPrepend',array('httpPassword','Check')); - //$core->addBehavior('publicPrepend',array('httpPassword','LastLogin')); +/** + * @brief httpPassword, a plugin for Dotclear 2 + * + * @package Dotclear + * @subpackage Plugin + * + * @author Frederic PLE and contributors + * + * @copyright Jean-Christian Denis + * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html + */ +if (!dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')) { + return null; } -class httpPassword { +dcCore::app()->addBehavior('publicPrependV2', function (): void { + $PHP_AUTH_USER = $PHP_AUTH_PW = ''; - private static function __debuglog ($core,$trace) { - static $fic = false; - if (!$core->blog->settings->httppassword_trace) - return; - if ($fic === false) - $fic = fopen($core->blog->public_path . '/.htpasswd.trc.txt','a'); - if ($fic !== false) { - fprintf($fic,"%s - %s\n",date('Ymd-His'),$trace); - } - } + if (isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW'])) { + $PHP_AUTH_USER = $_SERVER['PHP_AUTH_USER']; + $PHP_AUTH_PW = $_SERVER['PHP_AUTH_PW']; + } elseif (isset($_ENV['REMOTE_USER'])) { + [$PHP_AUTH_PW, $PHP_AUTH_USER] = explode(' ', $_ENV['REMOTE_USER'], 2); + [$PHP_AUTH_USER, $PHP_AUTH_PW] = explode(':', base64_decode($PHP_AUTH_USER)); + } + if ($PHP_AUTH_PW === '' or $PHP_AUTH_USER === '') { + httpPassword::sendHttp401(); + } - private static function __debugmode ($core) { - $fic = fopen($core->blog->public_path . '/.debugmode','a'); - fprintf($fic,"\n%s\n%s\n", str_repeat('-', 30), date('Ymd-His')); - fprintf($fic,".... \$_SERVER =\n%s\n",var_export($_SERVER,true)); - fprintf($fic,".... \$_ENV =\n%s\n",var_export($_ENV,true)); - fprintf($fic,".... Apache headers =\n%s\n",var_export(apache_request_headers(),true)); - } - - private static function __HTTP401($core) { - httpPassword::__debuglog($core,__FUNCTION__); - header('HTTP/1.1 401 Unauthorized'); - header('WWW-Authenticate: Basic realm="'. utf8_decode(htmlspecialchars_decode($core->blog->settings->httppassword_message)) .'"'); - exit(0); - } - public static function Check($core) { - httpPassword::__debuglog($core,'ENV = ' . var_export($_ENV,true)); - if ($core->blog->settings->httppassword_debugmode) - httpPassword::__debugmode($core); - if (isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW'])) { - $PHP_AUTH_USER = $_SERVER['PHP_AUTH_USER']; - $PHP_AUTH_PW = $_SERVER['PHP_AUTH_PW']; - httpPassword::__debuglog($core,__FUNCTION__ . ' user identication found in $_SERVER'); - } else if (isset($_ENV['REMOTE_USER'])) { - list($PHP_AUTH_PW,$PHP_AUTH_USER) = explode(' ',$_ENV['REMOTE_USER'],2); - list($PHP_AUTH_USER,$PHP_AUTH_PW) = explode(':',base64_decode($PHP_AUTH_USER)); - httpPassword::__debuglog($core,__FUNCTION__ . ' user identication found in $_ENV'); - } - if (!isset($PHP_AUTH_USER) or !isset($PHP_AUTH_PW) or $PHP_AUTH_USER === '') - httpPassword::__HTTP401($core); + if (!is_file(dcCore::app()->blog->public_path . DIRECTORY_SEPARATOR . initHttpPassword::FILE_PASSWORD)) { + header('HTTP/1.0 500 Internal Server Error'); + echo 'httpPassword plugin is not well configured.'; + exit(1); + } - httpPassword::__debuglog($core,'Testing user: '.$PHP_AUTH_USER.' pass: '.$PHP_AUTH_PW); - - if (!is_file($core->blog->public_path . '/.htpasswd')) { - header('HTTP/1.0 500 Internal Server Error'); - echo "Le plugin httppassword présente une anomalie de configuration"; - exit(1); - } - - $htpasswd = file($core->blog->public_path . '/.htpasswd',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES); - $authenticated = false; - foreach($htpasswd as $ligne) { - list($cur_user,$cur_pass) = explode(':',trim($ligne),2); - httpPassword::__debuglog($core,'cur_user: '.$cur_user.' cur_pass: '.$cur_pass); - if ($cur_user == $PHP_AUTH_USER and crypt($PHP_AUTH_PW,$cur_pass) == $cur_pass) { - $authenticated = true; - httpPassword::__debuglog($core,' OK'); - } - if ($authenticated) break; - } - unset($htpasswd); - if (!$authenticated) httpPassword::__HTTP401($core); - else httpPassword::LastLogin($core,$PHP_AUTH_USER); - - return(true); - } - - public static function LastLogin($core,$user) { - $fic = $core->blog->public_path . '/.lastlogin'; - - $httpPasswordLastLogin = array(); - if (is_file($fic)) - $httpPasswordLastLogin = unserialize(file_get_contents($fic)); - - $httpPasswordLastLogin[$user] = date('Y-m-d H:i'); - - file_put_contents($fic,serialize($httpPasswordLastLogin)); - - return(true); - } -} -?> + $htpasswd = file(dcCore::app()->blog->public_path . DIRECTORY_SEPARATOR . initHttpPassword::FILE_PASSWORD, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $authenticated = false; + foreach ($htpasswd as $ligne) { + [$cur_user, $cur_pass] = explode(':', trim($ligne), 2); + if ($cur_user == $PHP_AUTH_USER and crypt($PHP_AUTH_PW, $cur_pass) == $cur_pass) { + $authenticated = true; + } + if ($authenticated) { + break; + } + } + unset($htpasswd); + if (!$authenticated) { + httpPassword::sendHttp401(); + } else { + $logs = dcCore::app()->log->getLogs(['log_table' => basename(__DIR__), 'log_msg' => $PHP_AUTH_USER]); + if (!$logs->isEmpty()) { + $ids = []; + while ($logs->fetch()) { + $ids[] = $logs->__get('log_id'); + } + $logs = dcCore::app()->log->delLogs($ids); + } + $cursor = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcLog::LOG_TABLE_NAME); + $cursor->__set('log_table', basename(__DIR__)); + $cursor->__set('log_msg', $PHP_AUTH_USER); + dcCore::app()->log->addLog($cursor); + } +}); diff --git a/inc/class.httppassword.php b/inc/class.httppassword.php new file mode 100644 index 0000000..d2b7c30 --- /dev/null +++ b/inc/class.httppassword.php @@ -0,0 +1,107 @@ +blog->settings->get(self::id())->get('crypt')) { + case 'plaintext': + $saltlen = -1; + $salt = ''; + + break; + case 'crypt_std_des': + $saltlen = 2; + $salt = ''; + + break; + case 'crypt_ext_des': + $saltlen = 9; + $salt = ''; + + break; + case 'crypt_md5': + $saltlen = 12; + $salt = '$1$'; + + break; + case 'crypt_blowfish': + $saltlen = 16; + $salt = '$2$'; + + break; + case 'crypt_sha256': + $saltlen = 16; + $salt = '$5$'; + + break; + case 'crypt_sha512': + $saltlen = 16; + $salt = '$6$'; + + break; + default: + return ''; + } + + if ($saltlen > 0) { + $salt .= substr( + sha1(dcCore::app()->getNonce() . date('U')), + 2, + $saltlen - strlen($salt) + ); + $secret = crypt($secret, $salt); + } + + return($secret); + } + + public static function isWritable(): bool + { + if (false === ($fp = fopen(dcCore::app()->blog->public_path . DIRECTORY_SEPARATOR . initHttpPassword::FILE_PASSWORD, 'a+'))) { + return false; + } + fclose($fp); + + return true; + } + + public static function getCryptCombo(): array + { + return [ + __('No encryption') => 'plaintext', + __('Crypt DES standard') => 'crypt_std_des', + __('Crypt DES étendu') => 'crypt_ext_des', + __('Crypt MD5') => 'crypt_md5', + __('Crypt Blowfish') => 'crypt_blowfish', + __('Crypt SHA256') => 'crypt_sha256', + __('Crypt SHA512') => 'crypt_sha512', + ]; + } + + public static function sendHttp401(): void + { + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Basic realm="' . utf8_decode(htmlspecialchars_decode(dcCore::app()->blog->settings->get(self::id())->get('message'))) . '"'); + exit(0); + } +} diff --git a/index.php b/index.php index 8b2dd0f..818592b 100644 --- a/index.php +++ b/index.php @@ -1,475 +1,279 @@ blog->settings->httppassword_crypt) { - case "plaintext": - $saltlen = -1; - break; - case "crypt_std_des": - $saltlen = 2; - $salt = ""; - break; - case "crypt_ext_des": - $saltlen = 9; - $salt = ""; - break; - case "crypt_md5": - $saltlen = 12; - $salt = '$1$'; - break; - case "crypt_blowfish": - $saltlen = 16; - $salt = '$2$'; - break; - default: - return(false); - } - - if ($saltlen > 0) { - $salt .= substr( - sha1($core->getNonce() . date('U')), - 2, - $saltlen - strlen($salt) - ); - $secret = crypt($secret,$salt); - } - - return($secret); +/** + * @brief httpPassword, a plugin for Dotclear 2 + * + * @package Dotclear + * @subpackage Plugin + * + * @author Frederic PLE and contributors + * + * @copyright Jean-Christian Denis + * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html + */ +if (!defined('DC_CONTEXT_ADMIN')) { + return null; } -if (!defined('DC_CONTEXT_ADMIN')) { return; } +$s = dcCore::app()->blog->settings->get(basename(__DIR__)); +$pwd_file = dcCore::app()->blog->public_path . DIRECTORY_SEPARATOR . initHttpPassword::FILE_PASSWORD; +$action = $_POST['action'] ?? ''; +$redir = $_REQUEST['redir'] ?? ''; +$part = $_REQUEST['part'] ?? 'settings'; +$passwords = []; +$writable = httpPassword::isWritable(); +$section_menu = [ + __('Settings') => 'settings', + __('Logins history') => 'logins', + __('Authorized users') => 'passwords', +]; -$crypt_algo = array( - 'plaintext' => 'Aucun', -); -if (CRYPT_STD_DES == 1) - $crypt_algo['crypt_std_des'] = 'Crypt DES standard'; - -if (CRYPT_EXT_DES == 1) - $crypt_algo['crypt_ext_des'] = 'Crypt DES étendu'; - -if (CRYPT_MD5 == 1) - $crypt_algo['crypt_md5'] = 'Crypt MD5'; - -if (CRYPT_BLOWFISH == 1) - $crypt_algo['crypt_blowfish'] = 'Crypt Blowfish'; - -$htpasswdfile = $core->blog->public_path . '/.htpasswd' ; -$htp = file($htpasswdfile); -if (!is_array($htp)) $htp = array(); -sort($htp); - -$u = array(); -$v = array(); - -foreach($htp as $ligne) { - list($login, $pwd) = explode(':', $ligne, 2); - $u[trim($login)] = trim($pwd); +if (!in_array($part, $section_menu) || !$writable) { + $part = 'settings'; } -unset($ftp); - -$txt = !empty($_POST['txt']) ? $_POST['txt'] : null; -$action = !empty($_POST['httppasswordaction']) - ? $_POST['httppasswordaction'] - : null; - -$core->blog->settings->setNamespace('httppassword'); - -$debugmodefile = $core->blog->public_path . '/.debugmode'; - -switch($action) { - case "mod": - // traitement des donnees du formulaire - foreach(preg_split('/\n/m',$txt) as $ligne) - { - if (strpos($ligne, ':') === false) - $ligne = trim($ligne) . ':'; - list($login, $pwd) = explode(':', $ligne); - $v[trim($login)] = trim($pwd); - } - - // Rechercher les suppressions - foreach(array_keys($u) as $login) - { - if (!isset($v[$login])) - unset($u[$login]); - } - - // Rechercher les modifs + nouveaux - foreach(array_keys($v) as $login) - { - if ($v[$login] != "") { - $u[$login] = htpasswd_crypt( - $core, - $v[$login] - ); - if ($u[$login] === false) - unset($u[$login]); - } - } - - $txt = ""; - foreach(array_keys($u) as $login) - $txt .= $login.":".$u[$login]."\r\n"; - file_put_contents($htpasswdfile,$txt); - break; - - case "desactive": - case "active": - $active = !$core->blog->settings->httppassword_active; - $core->blog->settings->put( - 'httppassword_active', - $active, - 'boolean' - ); - $core->blog->settings->httppassword_active = $active; - break; - - case "cryptfunc": - $httppassword_crypt = trim($_POST['cryptage']); - if (in_array($httppassword_crypt,array_keys($crypt_algo))) { - $core->blog->settings->put( - 'httppassword_crypt', - $httppassword_crypt, - 'string' - ); - $core->blog->settings->httppassword_crypt = - $httppassword_crypt; - } - break; - - case "auth_message": - $message = htmlspecialchars($_POST['auth_message']); - $core->blog->settings->put( - 'httppassword_message', - $message, - 'string' - ); - $core->blog->settings->httppassword_message = $message; - break; - - case "debugmode": - if ($_POST['debugmode'] === "true") - $debugmode = true; - else { - $debugmode = false; - if (is_file($debugmodefile)) - unlink($debugmodefile); - } - $core->blog->settings->put( - 'httppassword_debugmode', - $debugmode, - 'boolean' - ); - $core->blog->settings->httppassword_debugmode = $debugmode; - break; +if (empty($redir)) { + $redir = dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__), ['part' => $part]); +} +if (!$writable) { + dcAdminNotices::addWarningNotice( + __('No write permissions on blogs directories.') + ); } -$fic = $core->blog->public_path . '/.lastlogin'; -if (is_file($fic)) { - $httpPasswordLastLogin = unserialize(file_get_contents($fic)); - if ($httpPasswordLastLogin === false) $httpPasswordLastLogin = array(); -} else - $httpPasswordLastLogin = array(); - -$form_block=' style="display: none;"'; -if (strlen($core->blog->settings->httppassword_crypt) > 0) $form_block=""; -?> - - httpPassword - - - - - -

blog->name); ?> › httpPasswd

- -
- - -
- > -

Activation du plugin

-put('active', !empty($_POST['active'])); + $s->put('crypt', in_array((string) $_POST['crypt'], httpPassword::getCryptCombo()) ? $_POST['crypt'] : 'paintext'); + $s->put('message', (string) $_POST['message']); -if (!$canwrite) { ?> -

Pour utiliser cette extension, vous devez avoir les permissions -pour écrire dans les fichiers :

-
    -
  • -
  • -
-blog->settings->httppassword_active) { ?> -

Protection ACTIVÉE

-
- Cliquer sur ce bouton pour désactiver la protection : - -formNonce() . - form::hidden(array('p'),'httpPassword') . - form::hidden(array('httppasswordaction'),'desactive'); -?> -
+ dcCore::app()->blog->triggerBlog(); - - utilisateur valide !

-
- Cliquer sur ce bouton pour activer la protection : - -formNonce(). - form::hidden(array('p'),'httpPassword'). - form::hidden(array('httppasswordaction'),'active'); -?> -
+ dcAdminNotices::addSuccessNotice( + __('Settings successfully updated.') + ); - - - -
-

Sécurité des mots de passe

-

Pour modifier la fonction de "cryptage".

-

Attention, le changement de - cryptage s'appliquera individuellement à la prochaine modification - de chacun des comptes (crétion ou changement de mot de passe)

-
- $algo_libelle) { - echo 'blog->settings->httppassword_crypt == $algo_code) - echo 'checked '; - echo '/> ' . $algo_libelle . '
'; -} ?> -formNonce(). - form::hidden(array('p'),'httpPassword'). - form::hidden(array('httppasswordaction'),'cryptfunc'); -?> -
-
- - > -

Message d'authentification

-
-

-
- -formNonce(). - form::hidden(array('p'),'httpPassword'). - form::hidden(array('httppasswordaction'),'auth_message'); -?>

-
- -
- > -
-


- -formNonce(). - form::hidden(array('p'),'httpPassword'). - form::hidden(array('httppasswordaction'),'mod'); -?>

-
- -
-
- -
-

Nous sommes le

- -0) { - $i = 0; - $logins = array_keys($httpPasswordLastLogin); - sort($logins); - foreach($logins as $login) - echo '' . "\n"; + dcCore::app()->adminurl->redirect( + 'admin.plugin.' . basename(__DIR__), + ['part' => $part] + ); } -?> -
' . $login . '' . - $httpPasswordLastLogin[$login] . - '
-
-
-

Gestion des accès restreints

-

Ce plugin permet la gestion d'identifiants et de mots de - passe pour limiter les accès à votre blog aux - personnes que vous aurez choisies.

-

Le formulaire de droite présente la liste des - utilisateurs existants (sans leur mot de passe)

-

Ajout d'un utilisateur

-

Pour ajouter un utilisateur, ajouter une nouvelle ligne - de la forme :

-

login:motdepasse

-

Modifier un mot de passe

-

Pour modifier un mot de passe d'un utilisateur, ajouter - à la suite de son identifiant (sur la même ligne) - le texte suivant :

-

:motdepasse

-

Suppression d'un utilisateur

-

Pour supprimer un utilisateur, supprimer la ligne de - l'utilisateur.

-
+if ('savelogins' == $action) { + $logs = dcCore::app()->log->getLogs(['log_table' => basename(__DIR__)]); + if (!$logs->isEmpty()) { + $ids = []; + while ($logs->fetch()) { + $ids[] = $logs->__get('log_id'); + } + $logs = dcCore::app()->log->delLogs($ids); + + dcAdminNotices::addSuccessNotice( + __('Logs successfully cleared.') + ); + + dcCore::app()->adminurl->redirect( + 'admin.plugin.' . basename(__DIR__), + ['part' => $part] + ); + } +} + +if ('savepasswords' == $action) { + $lines = []; + if (!empty($_POST['login']) && !empty($_POST['password'])) { + $lines[$_POST['login']] = httpPassword::crypt($_POST['password']); + } + foreach ($passwords as $l => $p) { + // add login + if (array_key_exists($l, $lines)) { + continue; + } + // delete login + if (!empty($_POST['delete']) && array_key_exists($l, $_POST['delete'])) { + continue; + } + // change password + if (!empty($_POST['edit']) && array_key_exists($l, $_POST['edit']) + && !empty($_POST['newpassword']) && array_key_exists($l, $_POST['newpassword']) + ) { + $lines[$l] = httpPassword::crypt($_POST['newpassword'][$l]); + } else { + $lines[$l] = $p; + } + } + + $contents = ''; + foreach ($lines as $l => $p) { + $contents .= sprintf("%s:%s\r\n", $l, $p); + } + file_put_contents($pwd_file, $contents); + + dcCore::app()->blog->triggerBlog(); + + dcAdminNotices::addSuccessNotice( + __('Logins successfully updated.') + ); + + dcCore::app()->adminurl->redirect( + 'admin.plugin.' . basename(__DIR__), + ['part' => $part] + ); +} -
-

Le plugin a été développé pour - fonctionner sur une installation "standard" de serveur Web - (PHP en module Apache).

-

Certains hébergeurs utilisent des installations de - PHP en mode CGI, parfois assez spécifiques et - sur lesquelles ce plugin ne fonctionnera pas

-

Le mode debug permet de collecter des informations - nécessaires au développeur pour adapter le plugin - à des contextes particuliers.

-

Quand l'activer

-
    -
  • Vous avez installé la dernière version du plugin - (voir sur http://lab.dotclear.org/plugin/httpPassword)
  • -
  • Vous avez activé le plugin
  • -
  • Vous avez créé un compte
  • -
  • Lorsque vous vous authentifiez sur le site, vous ne parvenez - pas à accéder à la partie publique avec le - compte que vous avez créé
  • -
-

MISE EN GARDE

-

le mode debug est - dangeureux. Il est imperatif de le desactiver juste apres - les tests.

-

Protocole à suivre

-

Le protocole est le suivant. Merci de le suivre pas à pas.

-
    -
  1. Creer un compte "debug" dont le mot de passe est "test"
  2. -
  3. Activer le plugin
  4. -
  5. Activer le mode debug
  6. -
  7. Faire un essai d'authentification
  8. -
  9. Revenir sur cette page et copier le texte de la section "Resultats" - dans un mail
  10. -
  11. Joindre a ce mail le fichier .debugmode que vous trouverez - dans le répertoire public du blog
  12. -
  13. Envoyer le mail à dotclear@frederic.ple.name
  14. -
  15. Desactiver le mode debug
  16. -
  17. Supprimer le de compte "debug"
  18. -
  19. Attendre patiemment la réponse du gentil - développeur
  20. -
-

Activer / Dédactiver le mode DEBUG

-
-

blog->settings->httppassword_debugmode === false) echo 'checked="checked" '; ?>/>Mode normal

-

blog->settings->httppassword_debugmode === true) echo 'checked="checked" '; ?>/>Mode Debug

-

-formNonce(). - form::hidden(array('p'),'httpPassword'). - form::hidden(array('httppasswordaction'),'debugmode'); -?>

-
- -

Résultats

-
-\n"; -echo "URL: " . $core->blog->url . "
\n"; -echo "IP: " . $_SERVER['SERVER_ADDR'] . "
\n"; -echo "DocumentRoot: " . $_SERVER['DOCUMENT_ROOT'] . "
\n"; -echo "DC2 version: " . $core->getVersion('core') . "
\n"; -echo "DC2 path: " ."-" . "
\n"; -echo "Plugins path: " . realpath(dirname(__FILE__) . '/..') . "
\n"; -echo "Public path: " . $core->blog->public_path . "
\n"; -echo "* INFOS HTTPPASSWD *
\n"; -echo "Version: " . $core->getVersion('httpPassword') . "
\n"; -//echo ".... \$_SERVER ....
" . str_replace("\n","
\n",var_export($_SERVER,true)) . "
\n"; -//echo ".... \$_ENV ....
" . str_replace("\n","
\n",var_export($_ENV,true)) . "
\n"; -//echo ".... HTTP Apache HEADERS ....
" . str_replace("\n","
\n",var_export(apache_request_headers(),true)) . "
\n"; -//echo str_replace("\n","
\n",htmlentities(file_get_contents($debugmodefile))); -?> -
- -
+'' . __('Http password') . '' . +dcPage::jsPageTabs() . +dcPage::jsModuleLoad(basename(__DIR__) . '/js/index.js') . +'' . +dcPage::breadcrumb([ + __('Plugins') => '', + __('Http password') => dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)), + array_search($part, $section_menu) => '', +]) . +dcPage::notices() . -
-

Plugin

- +# Filters select menu list +'
' . +'

' . +form::combo('part', $section_menu, $part) . ' ' . +'' . +form::hidden('p', basename(__DIR__)) . '

' . +'
' . +'

' . array_search($part, $section_menu) . '

'; -

Développeur

-
    -
  • Frédéric PLÉ <dotclear@frederic.ple.name>
  • -
-

Remerciements

-
    -
  • Aux développeurs de Dotclear pour la grande qualité du code
  • -
  • A Tomtom33, Moe, et les autres qui m'ont aidé sur le -forum
  • -
  • A Pep de Dotaddict
  • -
  • Stephanie "piloue" pour ses tests, ses suggestions et sa patience
  • -
  • Gabriel Recope pour ses tests et reports de bugs.
  • -
+if ('settings' == $part) { + echo ' +
-
Plugin réalisé v.getVersion('httpPassword'); ?> par Frédéric PLÉ - <dotclear@frederic.ple.name>
-
+

- - +

' . + form::combo('crypt', httpPassword::getCryptCombo(), (string) $s->get('crypt')) . '

+

' . + __('Some web servers does not surpport plaintext (no) encryption.') . ' ' . + __('If you change crypt algo, you must edit and resave each users passwords.') . + '

+ +

' . + form::field('message', 60, 255, html::escapeHTML((string) $s->get('message'))) . ' +

+ +
+

' . + dcCore::app()->formNonce() . + form::hidden(['action'], 'savesettings') . + form::hidden(['part'], $part) . ' + +

'; +} + +if ('logins' == $part) { + $logs = dcCore::app()->log->getLogs(['log_table' => basename(__DIR__)]); + if ($logs->isEmpty()) { + echo + '

' . __('Logins history is empty.') . '

'; + } else { + echo ' +
+

' . + dcCore::app()->formNonce() . + form::hidden(['action'], 'savelogins') . + form::hidden(['part'], $part) . ' + +

' . + + '
' . + '' . + '' . + '' . + '' . + ''; + + while ($logs->fetch()) { + echo + '' . + '' . + '' . + ''; + } + + echo + '
' . sprintf(__('List of %s last logins.'), $logs->count()) . '
' . __('Login') . '' . __('Date') . '
' . html::escapeHTML($logs->__get('log_msg')) . '' . html::escapeHTML(dt::dt2str(__('%Y-%m-%d %H:%M'), $logs->__get('log_dt'))) . '
'; + } +} + +if ('passwords' == $part) { + if (empty($passwords)) { + echo + '

' . __('Authorized users list is empty.') . '

'; + } else { + echo + '
' . + '
' . + '' . + '' . + '' . + '' . + '' . + ''; + + foreach ($passwords as $login => $pwd) { + echo + '' . + '' . + '' . + '' . + ''; + } + + echo + '
' . sprintf(__('List of %s authorized users.'), count($passwords)) . '
' . __('Login') . '' . __('New password') . '' . __('Action') . '
' . + html::escapeHTML($login) . + '' . + form::field(['newpassword[' . html::escapeHTML($login) . ']'], 60, 255, '') . + '' . + ' ' . + '' . + '
+

' . + dcCore::app()->formNonce() . + form::hidden(['action'], 'savepasswords') . + form::hidden(['part'], $part) . ' +

'; + } + + echo ' +
+

' . __('Add a user') . '

+ +

' . + form::field('login', 60, 255, '') . ' +

+ +

' . + form::field('password', 60, 255, '') . ' +

+ +

' . + dcCore::app()->formNonce() . + form::hidden(['action'], 'savepasswords') . + form::hidden(['part'], $part) . ' + +

'; +} + +echo +''; diff --git a/js/index.js b/js/index.js new file mode 100644 index 0000000..3b09c53 --- /dev/null +++ b/js/index.js @@ -0,0 +1,13 @@ +/*global $, dotclear */ +'use strict'; + +$(function () { + $('#section_menu input[type=submit]').hide(); + $('#section_menu #part').on('change', function () {this.form.submit();}); + + $('.checkboxes-helpers').each(function () { + dotclear.checkboxesHelpers(this, undefined, '#form-records td input[type=checkbox]', '#form-records #del-action'); + }); + $('#form-records td input[type=checkbox]').enableShiftClick(); + dotclear.condSubmit('#form-records td input[type=checkbox]', '#form-records #del-action'); +}); \ No newline at end of file diff --git a/locales/fr/main.po b/locales/fr/main.po new file mode 100644 index 0000000..0d72a09 --- /dev/null +++ b/locales/fr/main.po @@ -0,0 +1,84 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: httpPassword 1.0\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2022-12-31T00:45:53+00:00\n" +"Last-Translator: Jean-Christian Denis\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +msgid "Manage http password blog protection" +msgstr "Gérer la protection du blog par mot de passe HTTP" + +msgid "No encryption" +msgstr "pas de cryptage" + +msgid "Logins history" +msgstr "Historique des logins" + +msgid "Authorized users" +msgstr "Utilisateurs autorisés" + +msgid "No write permissions on blogs directories." +msgstr "Aucun droit d'écriture sur le répertoire du blog." + +msgid "Settings successfully updated." +msgstr "Paramètres mis à jour." + +msgid "Logs successfully cleared." +msgstr "Logs effacé." + +msgid "Logins successfully updated." +msgstr "Logins mis à jour." + +msgid "Select section:" +msgstr "Sélectionner une section :" + +msgid "Enable http password protection on this blog" +msgstr "Activer la protection du blog par mot de passe http" + +msgid "Crypt algorithm:" +msgstr "Algorithme de cryptage :" + +msgid "Some web servers does not surpport plaintext (no) encryption." +msgstr "Certains serveurs web ne supportent pas le cryptage \"plaintext\"." + +msgid "If you change crypt algo, you must edit and resave each users passwords." +msgstr "Si vous changer l'algorithme de cryptage, vous devrez modifier et sauver tous les mots de passes." + +msgid "Authentication message:" +msgstr "Message d'authentification :" + +msgid "Logins history is empty." +msgstr "L'historique des logins est vide." + +msgid "Clear logs" +msgstr "Effacer les logs" + +msgid "List of %s last logins." +msgstr "Liste des %s derniers logins." + +msgid "Authorized users list is empty." +msgstr "La listes des utilisateurs autorisés est vide." + +msgid "List of %s authorized users." +msgstr "Liste des %s utilisateurs autorisés." + +msgid "New password" +msgstr "Nouveau mot de passe" + +msgid "Change password" +msgstr "Modifier le mot de passe" + +msgid "Add a user" +msgstr "Ajouter un utilisateur" + +msgid "Login:" +msgstr "Identifiant :" + +msgid "Manage .htpasswd file to make the blog private" +msgstr "Gestion du fichier .htpasswd pour rendre le blog privé." +