diff --git a/admin/forms/settings.xml b/admin/forms/settings.xml index 2b2f4e0..b3c111d 100644 --- a/admin/forms/settings.xml +++ b/admin/forms/settings.xml @@ -2,7 +2,7 @@
- @@ -10,11 +10,11 @@ - - @@ -32,13 +32,13 @@
- - @@ -47,14 +47,14 @@ - - @@ -65,7 +65,7 @@ - @@ -78,13 +78,13 @@
- - @@ -99,20 +99,20 @@ description="PLG_SYSTEM_BFSTOP_PROXY_IP_DESC" />
- - - @@ -120,9 +120,9 @@ - + - @@ -138,13 +138,13 @@ - - @@ -155,13 +155,13 @@ - - @@ -178,13 +178,13 @@ min="0" max="3650" step="1" filter="integer" label="COM_BFSTOP_SETTINGS_LOG_KEEP_DAYS_LABEL" description="COM_BFSTOP_SETTINGS_LOG_KEEP_DAYS_DESC" /> - - @@ -192,13 +192,13 @@ - - @@ -208,45 +208,45 @@ description="PLG_SYSTEM_BFSTOP_HTACCESS_PATH_DESC" />
- - - - -
- - - - @@ -258,7 +258,7 @@ description="COM_BFSTOP_SETTINGS_GEOIP_DB_PATH_DESC" />
- @@ -267,31 +267,31 @@ - - - - - - @@ -301,29 +301,29 @@ default="admin administrator root test webmaster" label="COM_BFSTOP_SETTINGS_RISK_COMMONUSER_LIST_LABEL" description="COM_BFSTOP_SETTINGS_RISK_COMMONUSER_LIST_DESC" /> - - - - - - diff --git a/admin/language/de-DE/de-DE.com_bfstop.ini b/admin/language/de-DE/de-DE.com_bfstop.ini index 35a4580..c11c444 100644 --- a/admin/language/de-DE/de-DE.com_bfstop.ini +++ b/admin/language/de-DE/de-DE.com_bfstop.ini @@ -54,6 +54,9 @@ COM_BFSTOP_SETTINGS_VERSION_UNKNOWN="unbekannt" COM_BFSTOP_HEADING_IPINFO="Informationen zur IP-Adresse %s" COM_BFSTOP_SUBMENU_ALLOWLIST="Ausnahme-Liste" COM_BFSTOP_HEADING_ALLOWLIST="Brute Force Stop: Ausnahme-Liste" +COM_BFSTOP_ALLOWLIST_REMOVED="Aus der Positivliste entfernt." +COM_BFSTOP_ALLOWLIST_REMOVE_FAILED="Die Einträge konnten nicht aus der Positivliste entfernt werden." +COM_BFSTOP_ALLOWLIST_NOTHING_REMOVED="Es wurde nichts ausgewählt." COM_BFSTOP_ALLOWLIST_DELETE_CONFIRM="Sind Sie sicher, dass Sie die ausgewählte(n) IP-Adresse(n) löschen wollen?" COM_BFSTOP_BLOCK_UNLIMITED="dauerhaft" COM_BFSTOP_BLOCK_5MINUTES="5 Minuten" @@ -120,6 +123,7 @@ COM_BFSTOP_SETTINGS_UNKNOWN_USERNAME_MODE_LABEL="Benutzernamen ohne passendes Ko COM_BFSTOP_SETTINGS_UNKNOWN_USERNAME_MODE_DESC="Benutzer tippen oft ihr Passwort in das Benutzernamenfeld. Mit 'Hash' wird der Benutzername eines fehlgeschlagenen Logins nur dann so wie eingegeben gespeichert (angezeigt, protokolliert und per E-Mail gesendet), wenn er zu einem bestehenden Konto gehört oder in der Liste der häufigen Benutzernamen steht; alles andere wird durch einen unlesbaren Wert ersetzt, der für dieselbe Eingabe immer gleich ist, sodass Versuche damit zusammen gezählt werden. 'Wie eingegeben speichern' lässt jeden eingegebenen Benutzernamen lesbar, speichert dann aber auch Passwörter, die ins Benutzernamenfeld getippt wurden." COM_BFSTOP_SETTINGS_UNKNOWN_USERNAME_MODE_HASH="Hash (empfohlen)" COM_BFSTOP_SETTINGS_UNKNOWN_USERNAME_MODE_PLAIN="Wie eingegeben speichern" +COM_BFSTOP_SETTINGS_EMAIL_INVALID="Keine gültige E-Mail-Adresse: %s" COM_BFSTOP_SETTINGS_HTACCESS_PATH_INVALID="Der .htaccess-Pfad muss ein existierendes Verzeichnis im Dateisystem des Servers sein." COM_BFSTOP_SETTINGS_GEOIP_DB_PATH_INVALID="Der Pfad der GeoIP-Datenbank muss der Name einer MaxMind-Datenbankdatei (Endung .mmdb) im Dateisystem des Servers sein." COM_BFSTOP_SETTINGS_IPV6_PREFIX_LABEL="Genauigkeit bei IPv6" diff --git a/admin/language/en-GB/en-GB.com_bfstop.ini b/admin/language/en-GB/en-GB.com_bfstop.ini index e9b25bd..3f198f8 100644 --- a/admin/language/en-GB/en-GB.com_bfstop.ini +++ b/admin/language/en-GB/en-GB.com_bfstop.ini @@ -54,6 +54,9 @@ COM_BFSTOP_SETTINGS_VERSION_UNKNOWN="unknown" COM_BFSTOP_HEADING_IPINFO="Information for IP Address %s" COM_BFSTOP_SUBMENU_ALLOWLIST="Allow List" COM_BFSTOP_HEADING_ALLOWLIST="Brute Force Stop: Allow List" +COM_BFSTOP_ALLOWLIST_REMOVED="Removed from the allow list." +COM_BFSTOP_ALLOWLIST_REMOVE_FAILED="Could not remove the entries from the allow list." +COM_BFSTOP_ALLOWLIST_NOTHING_REMOVED="Nothing was selected." COM_BFSTOP_ALLOWLIST_DELETE_CONFIRM="Are you sure you want to delete the marked IP-Address(es)?" COM_BFSTOP_BLOCK_UNLIMITED="unlimited" COM_BFSTOP_BLOCK_5MINUTES="5 minutes" @@ -172,6 +175,7 @@ COM_BFSTOP_SETTINGS_UNKNOWN_USERNAME_MODE_LABEL="Usernames Not Matching an Accou COM_BFSTOP_SETTINGS_UNKNOWN_USERNAME_MODE_DESC="Users often type their password into the username field. With 'Hash', the username of a failed login is only stored (and shown, logged and mailed) as typed if it belongs to an existing account or is on the list of common usernames; anything else is replaced by an unreadable value, which is still the same for the same input, so attempts against it are counted together. 'Store as typed' keeps every entered username readable, but then also stores passwords typed into the username field." COM_BFSTOP_SETTINGS_UNKNOWN_USERNAME_MODE_HASH="Hash (recommended)" COM_BFSTOP_SETTINGS_UNKNOWN_USERNAME_MODE_PLAIN="Store as typed" +COM_BFSTOP_SETTINGS_EMAIL_INVALID="Not a valid email address: %s" COM_BFSTOP_SETTINGS_HTACCESS_PATH_INVALID="The .htaccess path has to be an existing directory of the server's file system." COM_BFSTOP_SETTINGS_GEOIP_DB_PATH_INVALID="The GeoIP database path has to be the name of a MaxMind database file (ending in .mmdb) in the server's file system." COM_BFSTOP_SETTINGS_IPV6_PREFIX_LABEL="IPv6 Tracking Granularity" diff --git a/admin/rules/emaillist.php b/admin/rules/emaillist.php new file mode 100644 index 0000000..f1d7aed --- /dev/null +++ b/admin/rules/emaillist.php @@ -0,0 +1,39 @@ +input; + $input = Factory::getApplication()->getInput(); $ids = $input->post->get('cid', array(), 'array'); ArrayHelper::toInteger($ids); $model = $this->getModel('allowlist'); diff --git a/admin/src/Controller/BlocklistController.php b/admin/src/Controller/BlocklistController.php index 00abab0..e5b06db 100644 --- a/admin/src/Controller/BlocklistController.php +++ b/admin/src/Controller/BlocklistController.php @@ -36,7 +36,7 @@ function unblock() return; } $logger = LogHelper::getLogger(); - $input = Factory::getApplication()->input; + $input = Factory::getApplication()->getInput(); $ids = $input->post->get('cid', array(), 'array'); $model = $this->getModel('blocklist'); $message = $model->unblock($ids, $logger); diff --git a/admin/src/Controller/DisplayController.php b/admin/src/Controller/DisplayController.php index fe31faa..7241823 100644 --- a/admin/src/Controller/DisplayController.php +++ b/admin/src/Controller/DisplayController.php @@ -18,12 +18,13 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Controller\BaseController; use Joomla\CMS\Router\Route; +use Joomla\Database\DatabaseInterface; class DisplayController extends BaseController { function display($cachable = false, $urlparams = false) { - $input = Factory::getApplication()->input; + $input = Factory::getApplication()->getInput(); $view = $input->getCmd('view', 'blocklist'); $pluginInstalled = $this->checkWhetherPluginInstalled(); @@ -42,7 +43,7 @@ function warnIfAdminUserExists() { try { - $db = Factory::getDbo(); + $db = Factory::getContainer()->get(DatabaseInterface::class); // LOWER: also catch "Admin" etc. on PostgreSQL, which (unlike // MySQL's default collations) compares case-sensitively $query = "SELECT COUNT(*) FROM #__users u WHERE LOWER(u.username)='admin'"; @@ -101,7 +102,7 @@ function checkWhetherPluginInstalled() { try { - $db = Factory::getDbo(); + $db = Factory::getContainer()->get(DatabaseInterface::class); $query = "SELECT manifest_cache,enabled FROM #__extensions WHERE name='plg_system_bfstop'"; $db->setQuery($query); $plugin = $db->loadObject(); diff --git a/admin/src/Controller/FailedloginlistController.php b/admin/src/Controller/FailedloginlistController.php index 600848b..f4fb343 100644 --- a/admin/src/Controller/FailedloginlistController.php +++ b/admin/src/Controller/FailedloginlistController.php @@ -34,7 +34,7 @@ function purge() $this->setRedirect($listUrl, Text::_('COM_BFSTOP_NOT_AUTHORISED'), 'error'); return; } - $age = Factory::getApplication()->input->post->getInt('age', 0); + $age = Factory::getApplication()->getInput()->post->getInt('age', 0); if ($age < 1) { $this->setRedirect($listUrl, Text::_('COM_BFSTOP_FAILEDLOGIN_PURGE_INVALID_AGE'), 'error'); diff --git a/admin/src/Controller/HtblockController.php b/admin/src/Controller/HtblockController.php index ee957b9..5248aa6 100644 --- a/admin/src/Controller/HtblockController.php +++ b/admin/src/Controller/HtblockController.php @@ -57,7 +57,7 @@ public function save($key = null, $urlVar = null) $htaccess = new HtaccessHelper($htaccessPath, null); $model = $this->getModel('block'); $form = $model->getForm(null, false); - $input = Factory::getApplication()->input; + $input = Factory::getApplication()->getInput(); $data = $input->post->get('jform', array(), 'array'); $validData = $model->validate($form, $data); if ($validData === false) @@ -66,16 +66,11 @@ public function save($key = null, $urlVar = null) $msg = ""; foreach ($errors as $error) { - if ($error instanceof \Exception) - { - $msg .= $error->getMessage(); - } - else - { - $msg .= $error; - } + // the messages have been escaped where they were made (they may + // contain what was typed in), see IpValidateHelper + $msg .= ($error instanceof \Exception) ? $error->getMessage() : $error; } - $this->returnToFormWithMessage($data['ipaddress'], $msg); + $this->returnToFormWithMessage(is_string($data['ipaddress'] ?? null) ? $data['ipaddress'] : '', $msg); return false; } $ipaddress = $validData['ipaddress']; diff --git a/admin/src/Controller/HtblocklistController.php b/admin/src/Controller/HtblocklistController.php index b6f80e2..38e21af 100644 --- a/admin/src/Controller/HtblocklistController.php +++ b/admin/src/Controller/HtblocklistController.php @@ -36,7 +36,7 @@ function unblock() return; } $logger = LogHelper::getLogger(); - $input = Factory::getApplication()->input; + $input = Factory::getApplication()->getInput(); $ips = $input->post->get('cid', array(), 'array'); $model = $this->getModel('htblocklist'); $message = $model->unblock($ips, $logger); diff --git a/admin/src/Controller/UsernamestatsController.php b/admin/src/Controller/UsernamestatsController.php index e8735ce..e96c1e6 100644 --- a/admin/src/Controller/UsernamestatsController.php +++ b/admin/src/Controller/UsernamestatsController.php @@ -34,7 +34,7 @@ function purge() $this->setRedirect($listUrl, Text::_('COM_BFSTOP_NOT_AUTHORISED'), 'error'); return; } - $age = Factory::getApplication()->input->post->getInt('age', 0); + $age = Factory::getApplication()->getInput()->post->getInt('age', 0); if ($age < 1) { $this->setRedirect($listUrl, Text::_('COM_BFSTOP_USERNAMESTATS_PURGE_INVALID_AGE'), 'error'); diff --git a/admin/src/Helper/IpValidateHelper.php b/admin/src/Helper/IpValidateHelper.php index 9f26fed..e407a11 100644 --- a/admin/src/Helper/IpValidateHelper.php +++ b/admin/src/Helper/IpValidateHelper.php @@ -16,6 +16,15 @@ class IpValidateHelper { + /** + * Joomla shows the messages it is given as HTML, so what was typed into + * a form must not be put into one as it is. + */ + private static function e($text) + { + return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8'); + } + public static function validIPRange($address) { $ip = $address; @@ -31,18 +40,18 @@ public static function validIPRange($address) // up (e.g. the web server's configuration) if (preg_match('/^[0-9]{1,3}\z/', $subnet) !== 1 || (int) $subnet > $maxBits) { - Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_IP_INVALID_SUBNET', $subnet), 'warning'); + Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_IP_INVALID_SUBNET', self::e($subnet)), 'warning'); return false; } } if (!filter_var($ip, FILTER_VALIDATE_IP)) { - Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_IP_INVALID_ADDRESS', $ip), 'warning'); + Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_IP_INVALID_ADDRESS', self::e($ip)), 'warning'); return false; } if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { - Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_IP_PRIVATE_OR_RESERVED', $ip), 'warning'); + Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_IP_PRIVATE_OR_RESERVED', self::e($ip)), 'warning'); } return true; } @@ -86,7 +95,7 @@ public static function matchesCurrentIP($range) $result = self::cidrMatch($curIP, $range); if ($result) { - Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_IP_BLOCKS_USER', $range, $curIP), 'warning'); + Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_IP_BLOCKS_USER', self::e($range), self::e($curIP)), 'warning'); } return $result; } diff --git a/admin/src/Helper/LinkHelper.php b/admin/src/Helper/LinkHelper.php index fa7bbb6..7f5a30a 100644 --- a/admin/src/Helper/LinkHelper.php +++ b/admin/src/Helper/LinkHelper.php @@ -16,7 +16,7 @@ class LinkHelper { public static function getIpInfoLink($ipaddress) { - $input = Factory::getApplication()->input; + $input = Factory::getApplication()->getInput(); $menuId = $input->get('Itemid', 0, 'INTEGER'); $link = 'index.php?option=com_bfstop&Itemid='.$menuId.'&view=ipinfo&ipaddress='.rawurlencode($ipaddress); return $link; diff --git a/admin/src/Helper/LogHelper.php b/admin/src/Helper/LogHelper.php index 5545595..2bab53a 100644 --- a/admin/src/Helper/LogHelper.php +++ b/admin/src/Helper/LogHelper.php @@ -19,8 +19,10 @@ class LogHelper { public static function getLogger() { + // false if the plugin is disabled: the page of an unblock link and + // the lists still work then $plugin = PluginHelper::getPlugin('system', 'bfstop'); - $params = new Registry($plugin->params); + $params = new Registry($plugin ? $plugin->params : null); $loglevel = $params->get('logLevel', Log::ERROR); return new LoggerHelper($loglevel); } diff --git a/admin/src/Helper/ParamHelper.php b/admin/src/Helper/ParamHelper.php index 49cbef4..b55f388 100644 --- a/admin/src/Helper/ParamHelper.php +++ b/admin/src/Helper/ParamHelper.php @@ -11,12 +11,13 @@ defined('_JEXEC') or die; use Joomla\CMS\Factory; +use Joomla\Database\DatabaseInterface; class ParamHelper { public static function get($name, $column, $defaultValue) { - $db = Factory::getDbo(); + $db = Factory::getContainer()->get(DatabaseInterface::class); $sql = "SELECT $column FROM #__extensions WHERE name = 'plg_system_bfstop'"; $db->setQuery($sql); $rawSettings = $db->loadResult(); diff --git a/admin/src/Helper/UnblockHelper.php b/admin/src/Helper/UnblockHelper.php index 602a91c..d9b88f5 100644 --- a/admin/src/Helper/UnblockHelper.php +++ b/admin/src/Helper/UnblockHelper.php @@ -47,6 +47,7 @@ public static function unblockDB($db, $ids, $source, $logger) $unblockDate = date('Y-m-d H:i:s'); foreach ($ids as $id) { + $curResult = false; try { $id = (int) $id; diff --git a/admin/src/Helper/VersionHelper.php b/admin/src/Helper/VersionHelper.php index 6b91e66..106f354 100644 --- a/admin/src/Helper/VersionHelper.php +++ b/admin/src/Helper/VersionHelper.php @@ -11,6 +11,7 @@ defined('_JEXEC') or die; use Joomla\CMS\Factory; +use Joomla\Database\DatabaseInterface; class VersionHelper { @@ -31,7 +32,7 @@ public static function checkSameMajorMinor($version1, $version2) // treat that as "not installed", not as an empty version string). public static function getInstalledVersions() { - $db = Factory::getDbo(); + $db = Factory::getContainer()->get(DatabaseInterface::class); $query = "SELECT manifest_cache FROM #__extensions WHERE name='plg_system_bfstop'"; $db->setQuery($query); diff --git a/admin/src/Model/AllowlistModel.php b/admin/src/Model/AllowlistModel.php index dd03524..aef848d 100644 --- a/admin/src/Model/AllowlistModel.php +++ b/admin/src/Model/AllowlistModel.php @@ -10,7 +10,7 @@ defined('_JEXEC') or die; -use Joomla\CMS\Factory; +use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; use Joomla\CMS\MVC\Model\ListModel; @@ -28,7 +28,7 @@ public function __construct($config = array()) protected function getListQuery() { - $db = Factory::getDbo(); + $db = $this->getDatabase(); $query = $db->getQuery(true); $query->select('a.id, a.ipaddress, a.notes'); $query->from('#__bfstop_allowlist a'); @@ -47,9 +47,14 @@ protected function populateState($ordering = null, $direction = null) public function remove($ids, $logger) { + $ids = array_values(array_filter(array_map('intval', (array) $ids))); + if (count($ids) === 0) + { + return Text::_('COM_BFSTOP_ALLOWLIST_NOTHING_REMOVED'); + } try { - $db = Factory::getDbo(); + $db = $this->getDatabase(); $query = $db->getQuery(true); $conditions = array( $db->quoteName('id').' IN ('.implode(", ", $ids).')' @@ -58,10 +63,12 @@ public function remove($ids, $logger) $query->where($conditions); $db->setQuery($query); $db->execute(); + return Text::_('COM_BFSTOP_ALLOWLIST_REMOVED'); } catch (\RuntimeException $e) { $logger->log($e->getMessage(), Log::ERROR); + return Text::_('COM_BFSTOP_ALLOWLIST_REMOVE_FAILED'); } } } diff --git a/admin/src/Model/BlocklistModel.php b/admin/src/Model/BlocklistModel.php index fe5ac93..9ce6c71 100644 --- a/admin/src/Model/BlocklistModel.php +++ b/admin/src/Model/BlocklistModel.php @@ -11,7 +11,6 @@ defined('_JEXEC') or die; use Codeling\Component\Bfstop\Administrator\Helper\UnblockHelper; -use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\ListModel; @@ -33,7 +32,7 @@ public function __construct($config = array()) protected function getListQuery() { - $db = Factory::getDbo(); + $db = $this->getDatabase(); $query = $db->getQuery(true); $query->select('b.id, b.ipaddress, b.crdate, b.duration, b.attempts, b.last_attempt, u.crdate as unblocked'); $query->from('#__bfstop_bannedip b left join #__bfstop_unblock u on b.id=u.block_id'); @@ -58,7 +57,7 @@ protected function populateState($ordering = null, $direction = null) public function unblock($ids, $logger) { - if (UnblockHelper::unblockDB(Factory::getDbo(), $ids, 0, $logger)) + if (UnblockHelper::unblockDB($this->getDatabase(), $ids, 0, $logger)) { return Text::_("COM_BFSTOP_UNBLOCK_SUCCESS"); } diff --git a/admin/src/Model/FailedloginlistModel.php b/admin/src/Model/FailedloginlistModel.php index a3a16a6..d9b0698 100644 --- a/admin/src/Model/FailedloginlistModel.php +++ b/admin/src/Model/FailedloginlistModel.php @@ -29,7 +29,7 @@ public function __construct($config = array()) protected function getListQuery() { - $db = Factory::getDbo(); + $db = $this->getDatabase(); $query = $db->getQuery(true); $query->select('l.id, l.username, l.ipaddress, l.logtime, l.origin'); $query->from('#__bfstop_failedlogin l'); @@ -40,7 +40,7 @@ protected function getListQuery() ->bind(':username', $username); } $ordering = $this->getState('list.ordering', 'l.id'); - $ordering = (strcmp($ordering, '') == 0) ? 'b.id' : $ordering; + $ordering = (strcmp($ordering, '') == 0) ? 'l.id' : $ordering; $direction = $this->getState('list.direction', 'ASC'); $direction = (strcmp($direction, '') == 0) ? 'ASC' : $direction; $query->order($db->escape($ordering).' '.$db->escape($direction)); @@ -53,7 +53,7 @@ protected function populateState($ordering = null, $direction = null) // set when coming from the username statistics view; deliberately not // persisted in the user state, so the full list shows otherwise $this->setState('filter.username', - Factory::getApplication()->input->getString('filter_username', '')); + Factory::getApplication()->getInput()->getString('filter_username', '')); } /** @@ -68,7 +68,7 @@ public function purgeOlderThan(int $days) // logtime is written with PHP's date() by the plugin, so compute the // cutoff with the same clock instead of the database's NOW() $cutoff = date('Y-m-d H:i:s', time() - $days * 86400); - $db = Factory::getDbo(); + $db = $this->getDatabase(); $query = $db->getQuery(true); $query->delete($db->quoteName('#__bfstop_failedlogin')) ->where($db->quoteName('logtime').' < :cutoff') diff --git a/admin/src/Model/LogModel.php b/admin/src/Model/LogModel.php index f8f7b3d..7e6c89e 100644 --- a/admin/src/Model/LogModel.php +++ b/admin/src/Model/LogModel.php @@ -28,7 +28,7 @@ public function __construct($config = array()) private function getLogFilePath() { $application = Factory::getApplication(); - $log_path = $application->getCfg('log_path'); + $log_path = $application->get('log_path'); return $log_path."/plg_system_bfstop.log.php"; } diff --git a/admin/src/Model/SettingsModel.php b/admin/src/Model/SettingsModel.php index 7ca1316..1a5e12a 100644 --- a/admin/src/Model/SettingsModel.php +++ b/admin/src/Model/SettingsModel.php @@ -12,13 +12,14 @@ use Joomla\CMS\Factory; use Joomla\CMS\MVC\Model\AdminModel; -use Joomla\CMS\Table\Table; +use Joomla\CMS\Table\Extension; class SettingsModel extends AdminModel { - public function getTable($type = 'Extension', $prefix = '\\Joomla\\CMS\\Table\\', $config = array()) + // the settings are the plugin's row of Joomla's extensions table + public function getTable($name = '', $prefix = '', $options = array()) { - return Table::getInstance($type, $prefix, $config); + return new Extension($this->getDatabase()); } public function getForm($data = array(), $loadData = true) diff --git a/admin/src/Model/UsernamestatsModel.php b/admin/src/Model/UsernamestatsModel.php index eb0a8f2..9a75e97 100644 --- a/admin/src/Model/UsernamestatsModel.php +++ b/admin/src/Model/UsernamestatsModel.php @@ -10,7 +10,6 @@ defined('_JEXEC') or die; -use Joomla\CMS\Factory; use Joomla\CMS\MVC\Model\ListModel; /** @@ -33,7 +32,7 @@ public function __construct($config = array()) protected function getListQuery() { - $db = Factory::getDbo(); + $db = $this->getDatabase(); $query = $db->getQuery(true); $query->select('s.username, s.attempts, s.first_attempt, s.last_attempt, u.id AS user_id'); $query->from('#__bfstop_username_stats s'); @@ -57,7 +56,7 @@ protected function populateState($ordering = null, $direction = null) */ public function getMaxAttempts() { - $db = Factory::getDbo(); + $db = $this->getDatabase(); $query = $db->getQuery(true); $query->select('MAX(attempts)') ->from($db->quoteName('#__bfstop_username_stats')); @@ -76,7 +75,7 @@ public function purgeNotSeenFor(int $days) // last_attempt is written with PHP's date() by the plugin, so compute // the cutoff with the same clock instead of the database's NOW() $cutoff = date('Y-m-d H:i:s', time() - $days * 86400); - $db = Factory::getDbo(); + $db = $this->getDatabase(); $query = $db->getQuery(true); $query->delete($db->quoteName('#__bfstop_username_stats')) ->where($db->quoteName('last_attempt').' < :cutoff') diff --git a/admin/src/View/Allow/HtmlView.php b/admin/src/View/Allow/HtmlView.php index b39d6ba..3577cc7 100644 --- a/admin/src/View/Allow/HtmlView.php +++ b/admin/src/View/Allow/HtmlView.php @@ -16,25 +16,25 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\ToolbarHelper; -use Joomla\CMS\Uri\Uri; class HtmlView extends BaseHtmlView { public function display($tpl = null) { - $this->form = $this->get('Form'); - $this->item = $this->get('Item'); + $this->form = $this->getModel()->getForm(); + $this->item = $this->getModel()->getItem(); $this->addToolbar(); - $document = Factory::getDocument(); - $document->addStyleSheet(Uri::base(true). - '/components/com_bfstop/tmpl/block/edit.css'); + // the stylesheet is in the component's template folder, not in media/: a + // path from the site's root, Joomla adds the prefix of a sub-folder install + $this->getDocument()->getWebAssetManager()->registerAndUseStyle( + 'com_bfstop.block.edit', 'administrator/components/com_bfstop/tmpl/block/edit.css'); Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_YOUR_IP_IS', IpHelper::getAddress(LogHelper::getLogger())), 'message'); parent::display($tpl); } protected function addToolbar() { - $input = Factory::getApplication()->input; + $input = Factory::getApplication()->getInput(); $input->set('hidemainmenu', true); $isNew = ($this->item->id == 0); ToolbarHelper::title($isNew diff --git a/admin/src/View/Allowlist/HtmlView.php b/admin/src/View/Allowlist/HtmlView.php index d6060c3..0dbd8c9 100644 --- a/admin/src/View/Allowlist/HtmlView.php +++ b/admin/src/View/Allowlist/HtmlView.php @@ -20,9 +20,9 @@ class HtmlView extends BaseHtmlView { function display($tpl = null) { - $this->items = $this->get('Items'); - $this->pagination = $this->get('Pagination'); - $state = $this->get('State'); + $this->items = $this->getModel()->getItems(); + $this->pagination = $this->getModel()->getPagination(); + $state = $this->getModel()->getState(); $this->sortColumn = $state->get('list.ordering'); $this->sortDirection = $state->get('list.direction'); $this->addToolBar(); diff --git a/admin/src/View/Block/HtmlView.php b/admin/src/View/Block/HtmlView.php index cda7015..51f9868 100644 --- a/admin/src/View/Block/HtmlView.php +++ b/admin/src/View/Block/HtmlView.php @@ -14,24 +14,24 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\ToolbarHelper; -use Joomla\CMS\Uri\Uri; class HtmlView extends BaseHtmlView { public function display($tpl = null) { - $this->form = $this->get('Form'); - $this->item = $this->get('Item'); + $this->form = $this->getModel()->getForm(); + $this->item = $this->getModel()->getItem(); $this->addToolbar(); - $document = Factory::getDocument(); - $document->addStyleSheet(Uri::base(true). - '/components/com_bfstop/tmpl/block/edit.css'); + // the stylesheet is in the component's template folder, not in media/: a + // path from the site's root, Joomla adds the prefix of a sub-folder install + $this->getDocument()->getWebAssetManager()->registerAndUseStyle( + 'com_bfstop.block.edit', 'administrator/components/com_bfstop/tmpl/block/edit.css'); parent::display($tpl); } protected function addToolbar() { - $input = Factory::getApplication()->input; + $input = Factory::getApplication()->getInput(); $input->set('hidemainmenu', true); $isNew = ($this->item->id == 0); ToolbarHelper::title($isNew diff --git a/admin/src/View/Blocklist/HtmlView.php b/admin/src/View/Blocklist/HtmlView.php index 0c3b55b..18940fe 100644 --- a/admin/src/View/Blocklist/HtmlView.php +++ b/admin/src/View/Blocklist/HtmlView.php @@ -21,9 +21,9 @@ class HtmlView extends BaseHtmlView { function display($tpl = null) { - $this->items = $this->get('Items'); - $this->pagination = $this->get('Pagination'); - $state = $this->get('State'); + $this->items = $this->getModel()->getItems(); + $this->pagination = $this->getModel()->getPagination(); + $state = $this->getModel()->getState(); $this->sortColumn = $state->get('list.ordering'); $this->sortDirection = $state->get('list.direction'); // with .htaccess blocking, blocked requests never reach Joomla, diff --git a/admin/src/View/Failedloginlist/HtmlView.php b/admin/src/View/Failedloginlist/HtmlView.php index 4214c4a..3da8b88 100644 --- a/admin/src/View/Failedloginlist/HtmlView.php +++ b/admin/src/View/Failedloginlist/HtmlView.php @@ -21,9 +21,9 @@ class HtmlView extends BaseHtmlView { function display($tpl = null) { - $this->items = $this->get('Items'); - $this->pagination = $this->get('Pagination'); - $state = $this->get('State'); + $this->items = $this->getModel()->getItems(); + $this->pagination = $this->getModel()->getPagination(); + $state = $this->getModel()->getState(); $this->sortColumn = $state->get('list.ordering'); $this->sortDirection = $state->get('list.direction'); $this->filterUsername = (string) $state->get('filter.username', ''); diff --git a/admin/src/View/Htblock/HtmlView.php b/admin/src/View/Htblock/HtmlView.php index e8ff7ec..946e496 100644 --- a/admin/src/View/Htblock/HtmlView.php +++ b/admin/src/View/Htblock/HtmlView.php @@ -14,7 +14,6 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\ToolbarHelper; -use Joomla\CMS\Uri\Uri; class HtmlView extends BaseHtmlView { @@ -22,22 +21,23 @@ class HtmlView extends BaseHtmlView public function display($tpl = null) { - $this->form = $this->get('Form'); - $this->item = $this->get('Item'); + $this->form = $this->getModel()->getForm(); + $this->item = $this->getModel()->getItem(); $user = Factory::getApplication()->getIdentity(); $this->canSave = $user && $user->authorise('core.create', 'com_bfstop'); $this->addToolbar(); - $document = Factory::getDocument(); - $document->addStyleSheet(Uri::base(true). - '/components/com_bfstop/tmpl/htblock/edit.css'); + // the stylesheet is in the component's template folder, not in media/: a + // path from the site's root, Joomla adds the prefix of a sub-folder install + $this->getDocument()->getWebAssetManager()->registerAndUseStyle( + 'com_bfstop.htblock.edit', 'administrator/components/com_bfstop/tmpl/htblock/edit.css'); parent::display($tpl); } protected function addToolbar() { - $input = Factory::getApplication()->input; + $input = Factory::getApplication()->getInput(); $input->set('hidemainmenu', true); ToolbarHelper::title(Text::_('COM_BFSTOP_BLOCK_NEW')); if ($this->canSave) diff --git a/admin/src/View/Htblocklist/HtmlView.php b/admin/src/View/Htblocklist/HtmlView.php index d29bc5d..049fe6f 100644 --- a/admin/src/View/Htblocklist/HtmlView.php +++ b/admin/src/View/Htblocklist/HtmlView.php @@ -20,9 +20,9 @@ class HtmlView extends BaseHtmlView { function display($tpl = null) { - $this->items = $this->get('Items'); - $this->pagination = $this->get('Pagination'); - $state = $this->get('State'); + $this->items = $this->getModel()->getItems(); + $this->pagination = $this->getModel()->getPagination(); + $state = $this->getModel()->getState(); $this->sortColumn = $state->get('list.ordering'); $this->sortDirection = $state->get('list.direction'); $this->addToolBar(); diff --git a/admin/src/View/Ipinfo/HtmlView.php b/admin/src/View/Ipinfo/HtmlView.php index 37f2b97..58ac721 100644 --- a/admin/src/View/Ipinfo/HtmlView.php +++ b/admin/src/View/Ipinfo/HtmlView.php @@ -22,7 +22,7 @@ class HtmlView extends BaseHtmlView { public function display($tpl = null) { - $input = Factory::getApplication()->input; + $input = Factory::getApplication()->getInput(); $this->ipAddress = $input->getString("ipaddress"); // looked up locally via a MaxMind .mmdb database (see GeoHelper) - diff --git a/admin/src/View/Log/HtmlView.php b/admin/src/View/Log/HtmlView.php index 02c2ff5..719b0b2 100644 --- a/admin/src/View/Log/HtmlView.php +++ b/admin/src/View/Log/HtmlView.php @@ -13,6 +13,7 @@ use Codeling\Component\Bfstop\Administrator\Helper\ToolbarHelper as BfstopToolbarHelper; use Codeling\Component\Bfstop\Administrator\Helper\ParamHelper; use Codeling\Plugin\System\Bfstop\Helper\LoggerHelper; +use Joomla\CMS\Access\Exception\NotAllowed; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; @@ -22,9 +23,15 @@ class HtmlView extends BaseHtmlView { function display($tpl = null) { - $this->items = $this->get('Items'); - $this->pagination = $this->get('Pagination'); - $state = $this->get('State'); + // the log holds addresses and usernames of failed logins and details + // of how the plugin is set up + if (!Factory::getApplication()->getIdentity()->authorise('core.admin', 'com_bfstop')) + { + throw new NotAllowed(Text::_('JERROR_ALERTNOAUTHOR'), 403); + } + $this->items = $this->getModel()->getItems(); + $this->pagination = $this->getModel()->getPagination(); + $state = $this->getModel()->getState(); $this->sortColumn = $state->get('list.ordering'); $this->sortDirection = $state->get('list.direction'); $this->keepDays = (int) ParamHelper::get('logKeepDays', 'params', LoggerHelper::DefaultKeepDays); diff --git a/admin/src/View/Settings/HtmlView.php b/admin/src/View/Settings/HtmlView.php index 5db1b79..4a671be 100644 --- a/admin/src/View/Settings/HtmlView.php +++ b/admin/src/View/Settings/HtmlView.php @@ -12,6 +12,7 @@ use Codeling\Component\Bfstop\Administrator\Helper\ToolbarHelper as BfstopToolbarHelper; use Codeling\Component\Bfstop\Administrator\Helper\VersionHelper; +use Joomla\CMS\Access\Exception\NotAllowed; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; @@ -27,16 +28,23 @@ class HtmlView extends BaseHtmlView public function display($tpl = null) { + // the settings show where the plugin writes files, which proxy it + // trusts and who gets the notifications: not for everybody who may + // merely look at the lists + if (!Factory::getApplication()->getIdentity()->authorise('core.admin', 'com_bfstop')) + { + throw new NotAllowed(Text::_('JERROR_ALERTNOAUTHOR'), 403); + } // the form field labels/descriptions are reused verbatim from the // plugin's own language file; that file isn't auto-loaded for us. // the strings live in the .sys.ini, not the plain .ini - see // InstallerAdapter::doLoadLanguage() for the same load pattern. - $language = Factory::getLanguage(); + $language = Factory::getApplication()->getLanguage(); $language->load('plg_system_bfstop.sys', JPATH_ADMINISTRATOR) || $language->load('plg_system_bfstop.sys', JPATH_PLUGINS . '/system/bfstop'); - $this->form = $this->get('Form'); - $this->item = $this->get('Item'); + $this->form = $this->getModel()->getForm(); + $this->item = $this->getModel()->getItem(); $user = Factory::getApplication()->getIdentity(); $this->canSave = $user && $user->authorise('core.admin', 'com_bfstop'); diff --git a/admin/src/View/Usernamestats/HtmlView.php b/admin/src/View/Usernamestats/HtmlView.php index 8bedde9..58a96c5 100644 --- a/admin/src/View/Usernamestats/HtmlView.php +++ b/admin/src/View/Usernamestats/HtmlView.php @@ -22,12 +22,12 @@ class HtmlView extends BaseHtmlView { function display($tpl = null) { - $this->items = $this->get('Items'); - $this->pagination = $this->get('Pagination'); - $state = $this->get('State'); + $this->items = $this->getModel()->getItems(); + $this->pagination = $this->getModel()->getPagination(); + $state = $this->getModel()->getState(); $this->sortColumn = $state->get('list.ordering'); $this->sortDirection = $state->get('list.direction'); - $this->maxAttempts = $this->get('MaxAttempts'); + $this->maxAttempts = $this->getModel()->getMaxAttempts(); $this->maxUsernames = DatabaseHelper::$USERNAME_STATS_MAX_ROWS; $this->canPurge = Factory::getApplication()->getIdentity()->authorise('core.delete', 'com_bfstop'); if ($this->canPurge) diff --git a/installscript.php b/installscript.php index 2ff7e98..e9de5dc 100644 --- a/installscript.php +++ b/installscript.php @@ -44,7 +44,7 @@ public function update(InstallerAdapter $adapter) } function postflight($type, InstallerAdapter $adapter) { - $lang = Factory::getLanguage(); + $lang = Factory::getApplication()->getLanguage(); $lang->load('com_bfstop', JPATH_ADMINISTRATOR); Factory::getApplication()->enqueueMessage(Text::sprintf('COM_BFSTOP_INSTALL_HINT', Route::_('index.php?option=com_plugins&view=plugins', false), diff --git a/site/src/Model/TokenunblockModel.php b/site/src/Model/TokenunblockModel.php index 676b99d..5f700f2 100644 --- a/site/src/Model/TokenunblockModel.php +++ b/site/src/Model/TokenunblockModel.php @@ -11,6 +11,7 @@ defined('_JEXEC') or die; use Codeling\Component\Bfstop\Administrator\Helper\UnblockHelper; +use Codeling\Plugin\System\Bfstop\Helper\DatabaseHelper; use Codeling\Plugin\System\Bfstop\Helper\IpHelper; use Joomla\CMS\Log\Log; use Joomla\CMS\MVC\Model\BaseDatabaseModel; @@ -61,10 +62,11 @@ private function getBlockedIp($token) { try { - $this->_db->setQuery('SELECT b.ipaddress FROM #__bfstop_unblock_token t '. + $db = $this->getDatabase(); + $db->setQuery('SELECT b.ipaddress FROM #__bfstop_unblock_token t '. 'INNER JOIN #__bfstop_bannedip b ON b.id = t.block_id '. - 'WHERE t.token='.$this->_db->quote($token)); - $ip = $this->_db->loadResult(); + 'WHERE t.token='.$db->quote(DatabaseHelper::hashToken($token))); + $ip = $db->loadResult(); return ($ip === null || $ip === false) ? null : (string) $ip; } catch (\RuntimeException $e) @@ -126,28 +128,31 @@ public function unblock($token, $logger) private function unblockWithResult($token, $logger) { + $db = $this->getDatabase(); // prune old tokens: try { // cutoff computed in PHP, as DATE_ADD is MySQL-only (issue bfstop#206) - $this->_db->setQuery('DELETE FROM #__bfstop_unblock_token '. + $db->setQuery('DELETE FROM #__bfstop_unblock_token '. 'WHERE crdate < '. - $this->_db->quote(date('Y-m-d H:i:s', time() - self::TokenValidDays * 86400))); - $this->_db->execute(); + $db->quote(date('Y-m-d H:i:s', time() - self::TokenValidDays * 86400))); + $db->execute(); // get token: - $this->_db->setQuery('SELECT * FROM #__bfstop_unblock_token WHERE token='. - $this->_db->quote($token)); - $unblockTokenEntry = $this->_db->loadObject(); + // only the hash of a token is stored, see DatabaseHelper::hashToken() + $stored = DatabaseHelper::hashToken($token); + $db->setQuery('SELECT * FROM #__bfstop_unblock_token WHERE token='. + $db->quote($stored)); + $unblockTokenEntry = $db->loadObject(); if ($unblockTokenEntry == null) { $logger->log("com_bfstop-tokenunblock: Token not found.", Log::ERROR); return self::ResultNotFound; } - UnblockHelper::unblockDB($this->_db, array($unblockTokenEntry->block_id), 1, $logger); + UnblockHelper::unblockDB($db, array($unblockTokenEntry->block_id), 1, $logger); $sql = 'DELETE FROM #__bfstop_unblock_token WHERE token='. - $this->_db->quote($token); - $this->_db->setQuery($sql); - $success = $this->_db->execute(); + $db->quote($stored); + $db->setQuery($sql); + $success = $db->execute(); } catch (\RuntimeException $e) { diff --git a/site/src/View/Tokenunblock/HtmlView.php b/site/src/View/Tokenunblock/HtmlView.php index f6777fc..3c3f4f9 100644 --- a/site/src/View/Tokenunblock/HtmlView.php +++ b/site/src/View/Tokenunblock/HtmlView.php @@ -34,10 +34,9 @@ function getPasswordResetLink() function display($tpl = null) { // clear the messages still enqueued from the invalid login attempt: - $session = Factory::getSession(); - $session->set('application.queue', null); $app = Factory::getApplication(); - $input = $app->input; + $app->getSession()->set('application.queue', null); + $input = $app->getInput(); $this->token = $input->getString('token', ''); $this->showConfirmation = false; $logger = LogHelper::getLogger();