diff --git a/src/Backend.php b/src/Backend.php index 9ed469f..a4bd220 100644 --- a/src/Backend.php +++ b/src/Backend.php @@ -10,17 +10,42 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} +declare(strict_types=1); -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) -); +namespace Dotclear\Plugin\httpPassword; + +use dcAuth; +use dcAdmin; +use dcCore; +use dcPage; +use dcNsProcess; + +class Backend extends dcNsProcess +{ + public static function init(): bool + { + self::$init = defined('DC_CONTEXT_ADMIN'); + + return self::$init; + } + + public static function process(): bool + { + if (!self::$init) { + return false; + } + + dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( + My::name(), + dcCore::app()->adminurl->get('admin.plugin.' . My::id()), + dcPage::getPF(My::id() . '/icon.png'), + preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.' . My::id())) . '(&.*)?$/', $_SERVER['REQUEST_URI']), + dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([ + dcAuth::PERMISSION_USAGE, + My::PERMISSION, + ]), dcCore::app()->blog->id) + ); + + return true; + } +} diff --git a/src/Frontend.php b/src/Frontend.php index 233c44e..d62e8e6 100644 --- a/src/Frontend.php +++ b/src/Frontend.php @@ -10,56 +10,81 @@ * @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; -} +declare(strict_types=1); -dcCore::app()->addBehavior('publicPrependV2', function (): void { - $PHP_AUTH_USER = $PHP_AUTH_PW = ''; +namespace Dotclear\Plugin\httpPassword; - 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(); +use dcCore; +use dcLog; +use dcNsProcess; + +class Frontend extends dcNsProcess +{ + public static function init(): bool + { + self::$init = defined('DC_RC_PATH'); + + return self::$init; } - 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); - } - - $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; + public static function process(): bool + { + if (!self::$init || !Utils::isActive()) { + return false; } - 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'); + + dcCore::app()->addBehavior('publicPrependV2', function (): void { + $PHP_AUTH_USER = $PHP_AUTH_PW = ''; + + 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)); } - $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); + if ($PHP_AUTH_PW === '' or $PHP_AUTH_USER === '') { + Utils::sendHttp401(); + } + + if (!is_file(dcCore::app()->blog->public_path . DIRECTORY_SEPARATOR . My::FILE_PASSWORD)) { + header('HTTP/1.0 500 Internal Server Error'); + echo 'httpPassword plugin is not well configured.'; + exit(1); + } + + $htpasswd = file(dcCore::app()->blog->public_path . DIRECTORY_SEPARATOR . My::FILE_PASSWORD, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $authenticated = false; + if ($htpasswd !== 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) { + Utils::sendHttp401(); + } else { + $logs = dcCore::app()->log->getLogs(['log_table' => My::id(), 'log_msg' => $PHP_AUTH_USER]); + if (!$logs->isEmpty()) { + $ids = []; + while ($logs->fetch()) { + $ids[] = (int) $logs->f('log_id'); + } + $logs = dcCore::app()->log->delLogs($ids); + } + $cursor = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcLog::LOG_TABLE_NAME); + $cursor->setField('log_table', My::id()); + $cursor->setField('log_msg', $PHP_AUTH_USER); + dcCore::app()->log->addLog($cursor); + } + }); + + return true; } -}); +} diff --git a/src/Install.php b/src/Install.php index b070e43..4fc3d4e 100644 --- a/src/Install.php +++ b/src/Install.php @@ -10,28 +10,41 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return; -} +declare(strict_types=1); -try { - // Check versions - if (!dcCore::app()->newVersion( - basename(__DIR__), - dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version') - )) { - return null; +namespace Dotclear\Plugin\httpPassword; + +use dcCore; +use dcNsProcess; +use Exception; + +class Install extends dcNsProcess +{ + public static function init(): bool + { + self::$init = defined('DC_CONTEXT_ADMIN') && dcCore::app()->newVersion(My::id(), dcCore::app()->plugins->moduleInfo(My::id(), 'version')); + + return self::$init; } - // 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); + public static function process(): bool + { + if (!self::$init) { + return false; + } - return true; -} catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); + try { + // Set settings + $s = dcCore::app()->blog->settings->get(My::id()); + $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 true; + } } - -return false; diff --git a/src/Manage.php b/src/Manage.php index 818592b..a585de8 100644 --- a/src/Manage.php +++ b/src/Manage.php @@ -10,270 +10,342 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return null; -} +declare(strict_types=1); -$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', -]; +namespace Dotclear\Plugin\httpPassword; -if (!in_array($part, $section_menu) || !$writable) { - $part = 'settings'; -} -if (empty($redir)) { - $redir = dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__), ['part' => $part]); -} -if (!$writable) { - dcAdminNotices::addWarningNotice( - __('No write permissions on blogs directories.') - ); -} +use dcCore; +use dcNsProcess; +use dcPage; +use Dotclear\Helper\Html\Html; +use Dotclear\Helper\Html\Form\{ + Checkbox, + Div, + Form, + Hidden, + Input, + Label, + Note, + Para, + Select, + Submit, + Text +}; +use dt; -if ('passwords' == $part) { - $lines = file($pwd_file); - if (!is_array($lines)) { - $lines = []; - } - sort($lines); - foreach ($lines as $line) { - [$login, $pwd] = explode(':', $line, 2); - $passwords[trim($login)] = trim($pwd); - } - unset($lines); -} +/** + * Manage contributions list + */ +class Manage extends dcNsProcess +{ + public static function init(): bool + { + if (defined('DC_CONTEXT_ADMIN')) { + dcPage::check(dcCore::app()->auth->makePermissions([ + My::PERMISSION, + ])); -if ('savesettings' == $action) { - $s->put('active', !empty($_POST['active'])); - $s->put('crypt', in_array((string) $_POST['crypt'], httpPassword::getCryptCombo()) ? $_POST['crypt'] : 'paintext'); - $s->put('message', (string) $_POST['message']); - - dcCore::app()->blog->triggerBlog(); - - dcAdminNotices::addSuccessNotice( - __('Settings successfully updated.') - ); - - dcCore::app()->adminurl->redirect( - 'admin.plugin.' . basename(__DIR__), - ['part' => $part] - ); -} - -if ('savelogins' == $action) { - $logs = dcCore::app()->log->getLogs(['log_table' => basename(__DIR__)]); - if (!$logs->isEmpty()) { - $ids = []; - while ($logs->fetch()) { - $ids[] = $logs->__get('log_id'); + self::$init = true; } - $logs = dcCore::app()->log->delLogs($ids); - dcAdminNotices::addSuccessNotice( - __('Logs successfully cleared.') + return self::$init; + } + + public static function process(): bool + { + if (!self::$init) { + return false; + } + + if (!Utils::isWritable()) { + dcPage::addWarningNotice( + __('No write permissions on blogs directories.') + ); + } + + $part = self::getSection(); + $action = $_POST['action'] ?? ''; + if (empty($action)) { + return true; + } + + if ('savesettings' == $action) { + $s = dcCore::app()->blog->settings->get(My::id()); + $s->put('active', !empty($_POST['active'])); + $s->put('crypt', in_array((string) $_POST['crypt'], My::cryptCombo()) ? $_POST['crypt'] : 'paintext'); + $s->put('message', (string) $_POST['message']); + + dcCore::app()->blog->triggerBlog(); + + dcPage::addSuccessNotice( + __('Settings successfully updated.') + ); + + dcCore::app()->adminurl->redirect( + 'admin.plugin.' . My::id(), + ['part' => $part] + ); + } + + if ('savelogins' == $action) { + $logs = dcCore::app()->log->getLogs(['log_table' => My::id()]); + if (!$logs->isEmpty()) { + $ids = []; + while ($logs->fetch()) { + $ids[] = $logs->__get('log_id'); + } + $logs = dcCore::app()->log->delLogs($ids); + + dcPage::addSuccessNotice( + __('Logs successfully cleared.') + ); + + dcCore::app()->adminurl->redirect( + 'admin.plugin.' . My::id(), + ['part' => $part] + ); + } + } + + if ('savepasswords' == $action) { + $passwords = self::getPasswords(); + $lines = []; + if (!empty($_POST['login']) && !empty($_POST['password'])) { + $lines[$_POST['login']] = Utils::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] = Utils::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(Utils::passwordFile(), $contents); + + dcCore::app()->blog->triggerBlog(); + + dcPage::addSuccessNotice( + __('Logins successfully updated.') + ); + + dcCore::app()->adminurl->redirect( + 'admin.plugin.' . My::id(), + ['part' => $part] + ); + } + + return true; + } + + public static function render(): void + { + if (!self::$init) { + return; + } + + $part = self::getSection(); + + dcPage::openModule( + My::name(), + dcPage::jsPageTabs() . + dcPage::jsModuleLoad(My::id() . '/js/backend.js') ); - 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] - ); -} - -echo -'