File manager - Edit - /home/ferretapmx/public_html/com_config.zip
Back
PK ��\.� 0 config.xmlnu �[��� <?xml version="1.0" encoding="UTF-8"?> <extension type="component" method="upgrade"> <name>com_config</name> <author>Joomla! Project</author> <creationDate>2006-04</creationDate> <copyright>(C) 2006 Open Source Matters, Inc.</copyright> <license>GNU General Public License version 2 or later; see LICENSE.txt</license> <authorEmail>admin@joomla.org</authorEmail> <authorUrl>www.joomla.org</authorUrl> <version>4.0.0</version> <description>COM_CONFIG_XML_DESCRIPTION</description> <namespace path="src">Joomla\Component\Config</namespace> <files folder="site"> <folder>forms</folder> <folder>src</folder> <folder>tmpl</folder> </files> <languages folder="site"> <language tag="en-GB">language/en-GB/com_config.ini</language> </languages> <media destination="com_config" folder="media"> <folder>js</folder> </media> <administration> <files folder="admin"> <filename>access.xml</filename> <filename>config.xml</filename> <folder>forms</folder> <folder>services</folder> <folder>src</folder> <folder>tmpl</folder> </files> <languages folder="admin"> <language tag="en-GB">language/en-GB/com_config.ini</language> <language tag="en-GB">language/en-GB/com_config.sys.ini</language> </languages> </administration> </extension> PK ��\�K o o src/Helper/ConfigHelper.phpnu �[��� <?php /** * @package Joomla.Administrator * @subpackage com_config * * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Config\Administrator\Helper; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Factory; use Joomla\CMS\Helper\ContentHelper; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Components helper for com_config * * @since 3.0 */ class ConfigHelper extends ContentHelper { /** * Get an array of all enabled components. * * @return array * * @since 3.0 */ public static function getAllComponents() { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('element') ->from('#__extensions') ->where('type = ' . $db->quote('component')) ->where('enabled = 1'); $db->setQuery($query); $result = $db->loadColumn(); return $result; } /** * Returns true if the component has configuration options. * * @param string $component Component name * * @return boolean * * @since 3.0 */ public static function hasComponentConfig($component) { return is_file(JPATH_ADMINISTRATOR . '/components/' . $component . '/config.xml'); } /** * Returns true if the current user has permission to access and change configuration options. * * @param string $component Component name * * @return boolean * * @since 4.2.9 */ public static function canChangeComponentConfig(string $component) { $user = Factory::getApplication()->getIdentity(); if (!\in_array(strtolower($component), ['com_joomlaupdate', 'com_privacy'], true)) { return $user->authorise('core.admin', $component) || $user->authorise('core.options', $component); } return $user->authorise('core.admin'); } /** * Returns an array of all components with configuration options. * Optionally return only those components for which the current user has 'core.manage' rights. * * @param boolean $authCheck True to restrict to components where current user has 'core.manage' rights. * * @return array * * @since 3.0 */ public static function getComponentsWithConfig($authCheck = true) { $result = []; $components = self::getAllComponents(); // Remove com_config from the array as that may have weird side effects $components = array_diff($components, ['com_config']); foreach ($components as $component) { if (self::hasComponentConfig($component) && (!$authCheck || self::canChangeComponentConfig($component))) { self::loadLanguageForComponent($component); $result[$component] = ApplicationHelper::stringURLSafe(Text::_($component)) . '_' . $component; } } asort($result); return array_keys($result); } /** * Load the sys language for the given component. * * @param array $components Array of component names. * * @return void * * @since 3.0 */ public static function loadLanguageForComponents($components) { foreach ($components as $component) { self::loadLanguageForComponent($component); } } /** * Load the sys language for the given component. * * @param string $component component name. * * @return void * * @since 3.5 */ public static function loadLanguageForComponent($component) { if (empty($component)) { return; } $lang = Factory::getLanguage(); // Load the core file then // Load extension-local file. $lang->load($component . '.sys', JPATH_BASE) || $lang->load($component . '.sys', JPATH_ADMINISTRATOR . '/components/' . $component); } } PK ��\�Sʉ� � src/Helper/.htaccessnu �7��m <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>PK ��\�"\� � src/Dispatcher/Dispatcher.phpnu �[��� <?php /** * @package Joomla.Administrator * @subpackage com_config * * @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Config\Administrator\Dispatcher; use Joomla\CMS\Access\Exception\NotAllowed; use Joomla\CMS\Dispatcher\ComponentDispatcher; use Joomla\Component\Config\Administrator\Helper\ConfigHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * ComponentDispatcher class for com_config * * @since 4.2.9 */ class Dispatcher extends ComponentDispatcher { /** * Check if the user have the right access to the component config * * @return void * * @since 4.2.9 * * @throws \Exception */ protected function checkAccess(): void { // sendtestmail and store do their own checks, so leave the method to handle the permission and send response itself if (\in_array($this->input->getCmd('task'), ['application.sendtestmail', 'application.store'], true)) { return; } $task = $this->input->getCmd('task', 'display'); $view = $this->input->getCmd('view'); $component = $this->input->getCmd('component'); if ($component && (str_starts_with($task, 'component.') || $view === 'component')) { // User is changing component settings, check if he has permission to do that $canAccess = ConfigHelper::canChangeComponentConfig($component); } else { // For everything else, user is required to have global core.admin permission to perform action $canAccess = $this->app->getIdentity()->authorise('core.admin'); } if (!$canAccess) { throw new NotAllowed($this->app->getLanguage()->_('JERROR_ALERTNOAUTHOR'), 403); } } } PK ��\�Sʉ� � src/Dispatcher/.htaccessnu �7��m <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>PK ��\�� �� � src/Field/FiltersField.phpnu �[��� <?php /** * @package Joomla.Administrator * @subpackage com_config * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Config\Administrator\Field; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\LayoutHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Text Filters form field. * * @since 1.6 */ class FiltersField extends FormField { /** * The form field type. * * @var string * @since 1.6 */ public $type = 'Filters'; /** * Method to get the field input markup. * * @todo: Add access check. * * @return string The field input markup. * * @since 1.6 */ protected function getInput() { // Add translation string for notification Text::script('COM_CONFIG_TEXT_FILTERS_NOTE'); // Add Javascript Factory::getDocument()->getWebAssetManager()->useScript('com_config.filters'); // Get the available user groups. $groups = $this->getUserGroups(); // Build the form control. $html = []; // Open the table. $html[] = '<table id="filter-config" class="table">'; $html[] = '<caption class="visually-hidden">' . Text::_('COM_CONFIG_TEXT_FILTERS') . '</caption>'; // The table heading. $html[] = ' <thead>'; $html[] = ' <tr>'; $html[] = ' <th scope="col">'; $html[] = ' <span class="acl-action">' . Text::_('JGLOBAL_FILTER_GROUPS_LABEL') . '</span>'; $html[] = ' </th>'; $html[] = ' <th scope="col">'; $html[] = ' <span class="acl-action">' . Text::_('JGLOBAL_FILTER_TYPE_LABEL') . '</span>'; $html[] = ' </th>'; $html[] = ' <th scope="col">'; $html[] = ' <span class="acl-action">' . Text::_('JGLOBAL_FILTER_TAGS_LABEL') . '</span>'; $html[] = ' </th>'; $html[] = ' <th scope="col">'; $html[] = ' <span class="acl-action">' . Text::_('JGLOBAL_FILTER_ATTRIBUTES_LABEL') . '</span>'; $html[] = ' </th>'; $html[] = ' </tr>'; $html[] = ' </thead>'; // The table body. $html[] = ' <tbody>'; foreach ($groups as $group) { if (!isset($this->value[$group->value])) { $this->value[$group->value] = ['filter_type' => 'BL', 'filter_tags' => '', 'filter_attributes' => '']; } $group_filter = $this->value[$group->value]; $group_filter['filter_tags'] = !empty($group_filter['filter_tags']) ? $group_filter['filter_tags'] : ''; $group_filter['filter_attributes'] = !empty($group_filter['filter_attributes']) ? $group_filter['filter_attributes'] : ''; $html[] = ' <tr>'; $html[] = ' <th class="acl-groups left" scope="row">'; $html[] = ' ' . LayoutHelper::render('joomla.html.treeprefix', ['level' => $group->level + 1]) . $group->text; $html[] = ' </th>'; $html[] = ' <td>'; $html[] = ' <label for="' . $this->id . $group->value . '_filter_type" class="visually-hidden">' . Text::_('JGLOBAL_FILTER_TYPE_LABEL') . '</label>'; $html[] = ' <select' . ' name="' . $this->name . '[' . $group->value . '][filter_type]"' . ' id="' . $this->id . $group->value . '_filter_type"' . ' data-parent="' . ($group->parent) . '" ' . ' data-id="' . ($group->value) . '" ' . ' class="novalidate form-select"' . '>'; $html[] = ' <option value="BL"' . ($group_filter['filter_type'] == 'BL' ? ' selected="selected"' : '') . '>' . Text::_('COM_CONFIG_FIELD_FILTERS_DEFAULT_FORBIDDEN_LIST') . '</option>'; $html[] = ' <option value="CBL"' . ($group_filter['filter_type'] == 'CBL' ? ' selected="selected"' : '') . '>' . Text::_('COM_CONFIG_FIELD_FILTERS_CUSTOM_FORBIDDEN_LIST') . '</option>'; $html[] = ' <option value="WL"' . ($group_filter['filter_type'] == 'WL' ? ' selected="selected"' : '') . '>' . Text::_('COM_CONFIG_FIELD_FILTERS_ALLOWED_LIST') . '</option>'; $html[] = ' <option value="NH"' . ($group_filter['filter_type'] == 'NH' ? ' selected="selected"' : '') . '>' . Text::_('COM_CONFIG_FIELD_FILTERS_NO_HTML') . '</option>'; $html[] = ' <option value="NONE"' . ($group_filter['filter_type'] == 'NONE' ? ' selected="selected"' : '') . '>' . Text::_('COM_CONFIG_FIELD_FILTERS_NO_FILTER') . '</option>'; $html[] = ' </select>'; $html[] = ' </td>'; $html[] = ' <td>'; $html[] = ' <label for="' . $this->id . $group->value . '_filter_tags" class="visually-hidden">' . Text::_('JGLOBAL_FILTER_TAGS_LABEL') . '</label>'; $html[] = ' <input' . ' name="' . $this->name . '[' . $group->value . '][filter_tags]"' . ' type="text"' . ' id="' . $this->id . $group->value . '_filter_tags" class="novalidate form-control"' . ' value="' . htmlspecialchars($group_filter['filter_tags'], ENT_QUOTES) . '"' . '>'; $html[] = ' </td>'; $html[] = ' <td>'; $html[] = ' <label for="' . $this->id . $group->value . '_filter_attributes"' . ' class="visually-hidden">' . Text::_('JGLOBAL_FILTER_ATTRIBUTES_LABEL') . '</label>'; $html[] = ' <input' . ' name="' . $this->name . '[' . $group->value . '][filter_attributes]"' . ' type="text"' . ' id="' . $this->id . $group->value . '_filter_attributes" class="novalidate form-control"' . ' value="' . htmlspecialchars($group_filter['filter_attributes'], ENT_QUOTES) . '"' . '>'; $html[] = ' </td>'; $html[] = ' </tr>'; } $html[] = ' </tbody>'; // Close the table. $html[] = '</table>'; return implode("\n", $html); } /** * A helper to get the list of user groups. * * @return array * * @since 1.6 */ protected function getUserGroups() { // Get a database object. $db = $this->getDatabase(); // Get the user groups from the database. $query = $db->getQuery(true); $query->select('a.id AS value, a.title AS text, COUNT(DISTINCT b.id) AS level, a.parent_id as parent'); $query->from('#__usergroups AS a'); $query->join('LEFT', '#__usergroups AS b on a.lft > b.lft AND a.rgt < b.rgt'); $query->group('a.id, a.title, a.lft'); $query->order('a.lft ASC'); $db->setQuery($query); $options = $db->loadObjectList(); return $options; } } PK ��\ZU=�� � # src/Field/ConfigComponentsField.phpnu �[��� <?php /** * @package Joomla.Administrator * @subpackage com_config * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Config\Administrator\Field; use Joomla\CMS\Factory; use Joomla\CMS\Form\Field\ListField; use Joomla\CMS\Language\Text; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Text Filters form field. * * @since 3.7.0 */ class ConfigComponentsField extends ListField { /** * The form field type. * * @var string * @since 3.7.0 */ public $type = 'ConfigComponents'; /** * Method to get a list of options for a list input. * * @return array An array of JHtml options. * * @since 3.7.0 */ protected function getOptions() { $db = $this->getDatabase(); $query = $db->getQuery(true) ->select('name AS text, element AS value') ->from('#__extensions') ->where('enabled >= 1') ->where('type =' . $db->quote('component')); $items = $db->setQuery($query)->loadObjectList(); if ($items) { $lang = Factory::getLanguage(); foreach ($items as &$item) { // Load language $extension = $item->value; if (is_file(JPATH_ADMINISTRATOR . '/components/' . $extension . '/config.xml')) { $source = JPATH_ADMINISTRATOR . '/components/' . $extension; $lang->load("$extension.sys", JPATH_ADMINISTRATOR) || $lang->load("$extension.sys", $source); // Translate component name $item->text = Text::_($item->text); } else { $item = null; } } // Sort by component name $items = ArrayHelper::sortObjects(array_filter($items), 'text', 1, true, true); } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $items); return $options; } } PK ��\�Sʉ� � src/Field/.htaccessnu �7��m <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>PK ��\�o?S�� �� src/Model/ApplicationModel.phpnu �[��� <?php /** * @package Joomla.Administrator * @subpackage com_config * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Config\Administrator\Model; use Joomla\CMS\Access\Access; use Joomla\CMS\Access\Rules; use Joomla\CMS\Cache\Exception\CacheConnectingException; use Joomla\CMS\Cache\Exception\UnsupportedCacheException; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Event\Application\AfterSaveConfigurationEvent; use Joomla\CMS\Event\Application\BeforeSaveConfigurationEvent; use Joomla\CMS\Factory; use Joomla\CMS\Http\HttpFactory; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; use Joomla\CMS\Mail\Exception\MailDisabledException; use Joomla\CMS\Mail\MailerFactoryAwareInterface; use Joomla\CMS\Mail\MailerFactoryAwareTrait; use Joomla\CMS\Mail\MailTemplate; use Joomla\CMS\MVC\Model\FormModel; use Joomla\CMS\Table\Asset; use Joomla\CMS\Table\Table; use Joomla\CMS\Uri\Uri; use Joomla\CMS\User\UserHelper; use Joomla\Database\DatabaseDriver; use Joomla\Database\ParameterType; use Joomla\Filesystem\File; use Joomla\Filesystem\Folder; use Joomla\Filesystem\Path; use Joomla\Filter\OutputFilter; use Joomla\Registry\Registry; use Joomla\Utilities\ArrayHelper; use PHPMailer\PHPMailer\Exception as phpMailerException; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model for the global configuration * * @since 3.2 */ class ApplicationModel extends FormModel implements MailerFactoryAwareInterface { use MailerFactoryAwareTrait; /** * Array of protected password fields from the configuration.php * * @var array * @since 3.9.23 */ private $protectedConfigurationFields = ['password', 'secret', 'smtppass', 'redis_server_auth', 'session_redis_server_auth']; /** * Method to get a form object. * * @param array $data Data for the form. * @param boolean $loadData True if the form is to load its own data (default case), false if not. * * @return mixed A Form object on success, false on failure * * @since 1.6 */ public function getForm($data = [], $loadData = true) { // Get the form. $form = $this->loadForm('com_config.application', 'application', ['control' => 'jform', 'load_data' => $loadData]); if (empty($form)) { return false; } return $form; } /** * Method to get the configuration data. * * This method will load the global configuration data straight from * JConfig. If configuration data has been saved in the session, that * data will be merged into the original data, overwriting it. * * @return array An array containing all global config data. * * @since 1.6 */ public function getData() { // Get the config data. $config = new \JConfig(); $data = ArrayHelper::fromObject($config); // Get the correct driver at runtime $data['dbtype'] = $this->getDatabase()->getName(); // Prime the asset_id for the rules. $data['asset_id'] = 1; // Get the text filter data $params = ComponentHelper::getParams('com_config'); $data['filters'] = ArrayHelper::fromObject($params->get('filters')); // If no filter data found, get from com_content (update of 1.6/1.7 site) if (empty($data['filters'])) { $contentParams = ComponentHelper::getParams('com_content'); $data['filters'] = ArrayHelper::fromObject($contentParams->get('filters')); } // Check for data in the session. $temp = Factory::getApplication()->getUserState('com_config.config.global.data'); // Merge in the session data. if (!empty($temp)) { // $temp can sometimes be an object, and we need it to be an array if (\is_object($temp)) { $temp = ArrayHelper::fromObject($temp); } $data = array_merge($temp, $data); } return $data; } /** * Method to validate the db connection properties. * * @param array $data An array containing all global config data. * * @return array|boolean Array with the validated global config data or boolean false on a validation failure. * * @since 4.0.0 */ public function validateDbConnection($data) { // Validate database connection encryption options if ((int) $data['dbencryption'] === 0) { // Reset unused options if (!empty($data['dbsslkey'])) { $data['dbsslkey'] = ''; } if (!empty($data['dbsslcert'])) { $data['dbsslcert'] = ''; } if ((bool) $data['dbsslverifyservercert'] === true) { $data['dbsslverifyservercert'] = false; } if (!empty($data['dbsslca'])) { $data['dbsslca'] = ''; } if (!empty($data['dbsslcipher'])) { $data['dbsslcipher'] = ''; } } else { // Check localhost if (strtolower($data['host']) === 'localhost') { Factory::getApplication()->enqueueMessage(Text::_('COM_CONFIG_ERROR_DATABASE_ENCRYPTION_LOCALHOST'), 'error'); return false; } // Check CA file and folder depending on database type if server certificate verification if ((bool) $data['dbsslverifyservercert'] === true) { if (empty($data['dbsslca'])) { Factory::getApplication()->enqueueMessage( Text::sprintf( 'COM_CONFIG_ERROR_DATABASE_ENCRYPTION_FILE_FIELD_EMPTY', Text::_('COM_CONFIG_FIELD_DATABASE_ENCRYPTION_CA_LABEL') ), 'error' ); return false; } if (!is_file(Path::clean($data['dbsslca']))) { Factory::getApplication()->enqueueMessage( Text::sprintf( 'COM_CONFIG_ERROR_DATABASE_ENCRYPTION_FILE_FIELD_BAD', Text::_('COM_CONFIG_FIELD_DATABASE_ENCRYPTION_CA_LABEL') ), 'error' ); return false; } } else { // Reset unused option if (!empty($data['dbsslca'])) { $data['dbsslca'] = ''; } } // Check key and certificate if two-way encryption if ((int) $data['dbencryption'] === 2) { if (empty($data['dbsslkey'])) { Factory::getApplication()->enqueueMessage( Text::sprintf( 'COM_CONFIG_ERROR_DATABASE_ENCRYPTION_FILE_FIELD_EMPTY', Text::_('COM_CONFIG_FIELD_DATABASE_ENCRYPTION_KEY_LABEL') ), 'error' ); return false; } if (!is_file(Path::clean($data['dbsslkey']))) { Factory::getApplication()->enqueueMessage( Text::sprintf( 'COM_CONFIG_ERROR_DATABASE_ENCRYPTION_FILE_FIELD_BAD', Text::_('COM_CONFIG_FIELD_DATABASE_ENCRYPTION_KEY_LABEL') ), 'error' ); return false; } if (empty($data['dbsslcert'])) { Factory::getApplication()->enqueueMessage( Text::sprintf( 'COM_CONFIG_ERROR_DATABASE_ENCRYPTION_FILE_FIELD_EMPTY', Text::_('COM_CONFIG_FIELD_DATABASE_ENCRYPTION_CERT_LABEL') ), 'error' ); return false; } if (!is_file(Path::clean($data['dbsslcert']))) { Factory::getApplication()->enqueueMessage( Text::sprintf( 'COM_CONFIG_ERROR_DATABASE_ENCRYPTION_FILE_FIELD_BAD', Text::_('COM_CONFIG_FIELD_DATABASE_ENCRYPTION_CERT_LABEL') ), 'error' ); return false; } } else { // Reset unused options if (!empty($data['dbsslkey'])) { $data['dbsslkey'] = ''; } if (!empty($data['dbsslcert'])) { $data['dbsslcert'] = ''; } } } return $data; } /** * Method to save the configuration data. * * @param array $data An array containing all global config data. * * @return boolean True on success, false on failure. * * @since 1.6 */ public function save($data) { $app = Factory::getApplication(); // Try to load the values from the configuration file foreach ($this->protectedConfigurationFields as $fieldKey) { if (!isset($data[$fieldKey])) { $data[$fieldKey] = $app->get($fieldKey, ''); } } // Check that we aren't setting wrong database configuration $options = [ 'driver' => $data['dbtype'], 'host' => $data['host'], 'user' => $data['user'], 'password' => $data['password'], 'database' => $data['db'], 'prefix' => $data['dbprefix'], ]; // Validate database name if (\in_array($options['driver'], ['pgsql', 'postgresql']) && !preg_match('#^[a-zA-Z_][0-9a-zA-Z_$]*$#', $options['database'])) { $app->enqueueMessage(Text::_('COM_CONFIG_FIELD_DATABASE_NAME_INVALID_MSG_POSTGRES'), 'warning'); return false; } if (\in_array($options['driver'], ['mysql', 'mysqli']) && preg_match('#[\\\\\/]#', $options['database'])) { $app->enqueueMessage(Text::_('COM_CONFIG_FIELD_DATABASE_NAME_INVALID_MSG_MYSQL'), 'warning'); return false; } if ((int) $data['dbencryption'] !== 0) { $options['ssl'] = [ 'enable' => true, 'verify_server_cert' => (bool) $data['dbsslverifyservercert'], ]; foreach (['cipher', 'ca', 'key', 'cert'] as $value) { $confVal = trim($data['dbssl' . $value]); if ($confVal !== '') { $options['ssl'][$value] = $confVal; } } } try { $revisedDbo = DatabaseDriver::getInstance($options); $revisedDbo->getVersion(); } catch (\Exception $e) { $app->enqueueMessage(Text::sprintf('COM_CONFIG_ERROR_DATABASE_NOT_AVAILABLE', $e->getCode(), $e->getMessage()), 'error'); return false; } if ((int) $data['dbencryption'] !== 0 && empty($revisedDbo->getConnectionEncryption())) { if ($revisedDbo->isConnectionEncryptionSupported()) { Factory::getApplication()->enqueueMessage(Text::_('COM_CONFIG_ERROR_DATABASE_ENCRYPTION_CONN_NOT_ENCRYPT'), 'error'); } else { Factory::getApplication()->enqueueMessage(Text::_('COM_CONFIG_ERROR_DATABASE_ENCRYPTION_SRV_NOT_SUPPORTS'), 'error'); } return false; } // Check if we can set the Force SSL option if ((int) $data['force_ssl'] !== 0 && (int) $data['force_ssl'] !== (int) $app->get('force_ssl', '0')) { try { // Make an HTTPS request to check if the site is available in HTTPS. $host = Uri::getInstance()->getHost(); $options = new Registry(); $options->set('userAgent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0'); // Do not check for valid server certificate here, leave this to the user, moreover disable using a proxy if any is configured. $options->set( 'transport.curl', [ CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_PROXY => null, CURLOPT_PROXYUSERPWD => null, ] ); $response = HttpFactory::getHttp($options)->get('https://' . $host . Uri::root(true) . '/', ['Host' => $host], 10); // If available in HTTPS check also the status code. if (!\in_array($response->getStatusCode(), [200, 503, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 401], true)) { throw new \RuntimeException(Text::_('COM_CONFIG_ERROR_SSL_NOT_AVAILABLE_HTTP_CODE')); } } catch (\RuntimeException $e) { $data['force_ssl'] = 0; // Also update the user state $app->setUserState('com_config.config.global.data.force_ssl', 0); // Inform the user $app->enqueueMessage(Text::sprintf('COM_CONFIG_ERROR_SSL_NOT_AVAILABLE', $e->getMessage()), 'warning'); } } // Save the rules if (isset($data['rules'])) { $rules = new Rules($data['rules']); // Check that we aren't removing our Super User permission // Need to get groups from database, since they might have changed $myGroups = Access::getGroupsByUser($this->getCurrentUser()->id); $myRules = $rules->getData(); $hasSuperAdmin = $myRules['core.admin']->allow($myGroups); if (!$hasSuperAdmin) { $app->enqueueMessage(Text::_('COM_CONFIG_ERROR_REMOVING_SUPER_ADMIN'), 'error'); return false; } $asset = Table::getInstance('asset'); if ($asset->loadByName('root.1')) { $asset->rules = (string) $rules; if (!$asset->check() || !$asset->store()) { $app->enqueueMessage($asset->getError(), 'error'); return false; } } else { $app->enqueueMessage(Text::_('COM_CONFIG_ERROR_ROOT_ASSET_NOT_FOUND'), 'error'); return false; } unset($data['rules']); } // Save the text filters if (isset($data['filters'])) { $registry = new Registry(['filters' => $data['filters']]); $extension = Table::getInstance('extension'); // Get extension_id $extensionId = $extension->find(['name' => 'com_config']); if ($extension->load((int) $extensionId)) { $extension->params = (string) $registry; if (!$extension->check() || !$extension->store()) { $app->enqueueMessage($extension->getError(), 'error'); return false; } } else { $app->enqueueMessage(Text::_('COM_CONFIG_ERROR_CONFIG_EXTENSION_NOT_FOUND'), 'error'); return false; } unset($data['filters']); } // Get the previous configuration. $prev = new \JConfig(); $prev = ArrayHelper::fromObject($prev); // Merge the new data in. We do this to preserve values that were not in the form. $data = array_merge($prev, $data); /* * Perform miscellaneous options based on configuration settings/changes. */ // Escape the offline message if present. if (isset($data['offline_message'])) { $data['offline_message'] = OutputFilter::ampReplace($data['offline_message']); } // Purge the database session table if we are changing to the database handler. if ($prev['session_handler'] != 'database' && $data['session_handler'] == 'database') { $db = $this->getDatabase(); $query = $db->getQuery(true) ->delete($db->quoteName('#__session')) ->where($db->quoteName('time') . ' < ' . (time() - 1)); $db->setQuery($query); $db->execute(); } // Purge the database session table if we are disabling session metadata if ($prev['session_metadata'] == 1 && $data['session_metadata'] == 0) { try { // If we are are using the session handler, purge the extra columns, otherwise truncate the whole session table if ($data['session_handler'] === 'database') { $revisedDbo->setQuery( $revisedDbo->getQuery(true) ->update('#__session') ->set( [ $revisedDbo->quoteName('client_id') . ' = 0', $revisedDbo->quoteName('guest') . ' = NULL', $revisedDbo->quoteName('userid') . ' = NULL', $revisedDbo->quoteName('username') . ' = NULL', ] ) )->execute(); } else { $revisedDbo->truncateTable('#__session'); } } catch (\RuntimeException) { /* * The database API logs errors on failures so we don't need to add any error handling mechanisms here. * Also, this data won't be added or checked anymore once the configuration is saved, so it'll purge itself * through normal garbage collection anyway or if not using the database handler someone can purge the * table on their own. Either way, carry on Soldier! */ } } // Ensure custom session file path exists or try to create it if changed if (!empty($data['session_filesystem_path'])) { $currentPath = $prev['session_filesystem_path'] ?? null; if ($currentPath) { $currentPath = Path::clean($currentPath); } $data['session_filesystem_path'] = Path::clean($data['session_filesystem_path']); if ($currentPath !== $data['session_filesystem_path']) { if (!is_dir(Path::clean($data['session_filesystem_path'])) && !Folder::create($data['session_filesystem_path'])) { try { Log::add( Text::sprintf( 'COM_CONFIG_ERROR_CUSTOM_SESSION_FILESYSTEM_PATH_NOTWRITABLE_USING_DEFAULT', $data['session_filesystem_path'] ), Log::WARNING, 'jerror' ); } catch (\RuntimeException) { $app->enqueueMessage( Text::sprintf( 'COM_CONFIG_ERROR_CUSTOM_SESSION_FILESYSTEM_PATH_NOTWRITABLE_USING_DEFAULT', $data['session_filesystem_path'] ), 'warning' ); } $data['session_filesystem_path'] = $currentPath; } } } // Set the shared session configuration if (isset($data['shared_session'])) { $currentShared = $prev['shared_session'] ?? '0'; // Has the user enabled shared sessions? if ($data['shared_session'] == 1 && $currentShared == 0) { // Generate a random shared session name $data['session_name'] = UserHelper::genRandomPassword(16); } // Has the user disabled shared sessions? if ($data['shared_session'] == 0 && $currentShared == 1) { // Remove the session name value unset($data['session_name']); } } // Set the shared session configuration if (isset($data['shared_session'])) { $currentShared = $prev['shared_session'] ?? '0'; // Has the user enabled shared sessions? if ($data['shared_session'] == 1 && $currentShared == 0) { // Generate a random shared session name $data['session_name'] = UserHelper::genRandomPassword(16); } // Has the user disabled shared sessions? if ($data['shared_session'] == 0 && $currentShared == 1) { // Remove the session name value unset($data['session_name']); } } if (empty($data['cache_handler'])) { $data['caching'] = 0; } /* * Look for a custom cache_path * First check if a path is given in the submitted data, then check if a path exists in the previous data, otherwise use the default */ if (!empty($data['cache_path'])) { $path = $data['cache_path']; } elseif (!empty($prev['cache_path'])) { $path = $prev['cache_path']; } else { $path = JPATH_CACHE; } // Give a warning if the cache-folder can not be opened if ($data['caching'] > 0 && $data['cache_handler'] == 'file' && @opendir($path) === false) { $error = true; // If a custom path is in use, try using the system default instead of disabling cache if ($path !== JPATH_CACHE && @opendir(JPATH_CACHE) !== false) { try { Log::add( Text::sprintf('COM_CONFIG_ERROR_CUSTOM_CACHE_PATH_NOTWRITABLE_USING_DEFAULT', $path, JPATH_CACHE), Log::WARNING, 'jerror' ); } catch (\RuntimeException) { $app->enqueueMessage( Text::sprintf('COM_CONFIG_ERROR_CUSTOM_CACHE_PATH_NOTWRITABLE_USING_DEFAULT', $path, JPATH_CACHE), 'warning' ); } $path = JPATH_CACHE; $error = false; $data['cache_path'] = ''; } if ($error) { try { Log::add(Text::sprintf('COM_CONFIG_ERROR_CACHE_PATH_NOTWRITABLE', $path), Log::WARNING, 'jerror'); } catch (\RuntimeException) { $app->enqueueMessage(Text::sprintf('COM_CONFIG_ERROR_CACHE_PATH_NOTWRITABLE', $path), 'warning'); } $data['caching'] = 0; } } // Did the user remove their custom cache path? Don't save the variable to the config if (empty($data['cache_path'])) { unset($data['cache_path']); } // Clean the cache if disabled but previously enabled or changing cache handlers; these operations use the `$prev` data already in memory if ((!$data['caching'] && $prev['caching']) || $data['cache_handler'] !== $prev['cache_handler']) { try { Factory::getCache()->clean(); } catch (CacheConnectingException) { try { Log::add(Text::_('COM_CONFIG_ERROR_CACHE_CONNECTION_FAILED'), Log::WARNING, 'jerror'); } catch (\RuntimeException) { $app->enqueueMessage(Text::_('COM_CONFIG_ERROR_CACHE_CONNECTION_FAILED'), 'warning'); } } catch (UnsupportedCacheException) { try { Log::add(Text::_('COM_CONFIG_ERROR_CACHE_DRIVER_UNSUPPORTED'), Log::WARNING, 'jerror'); } catch (\RuntimeException) { $app->enqueueMessage(Text::_('COM_CONFIG_ERROR_CACHE_DRIVER_UNSUPPORTED'), 'warning'); } } } /* * Look for a custom tmp_path * First check if a path is given in the submitted data, then check if a path exists in the previous data, otherwise use the default */ $defaultTmpPath = JPATH_ROOT . '/tmp'; if (!empty($data['tmp_path'])) { $path = $data['tmp_path']; } elseif (!empty($prev['tmp_path'])) { $path = $prev['tmp_path']; } else { $path = $defaultTmpPath; } $path = Path::clean($path); // Give a warning if the tmp-folder is not valid or not writable if (!is_dir($path) || !is_writable($path)) { $error = true; // If a custom path is in use, try using the system default tmp path if ($path !== $defaultTmpPath && is_dir($defaultTmpPath) && is_writable($defaultTmpPath)) { try { Log::add( Text::sprintf('COM_CONFIG_ERROR_CUSTOM_TEMP_PATH_NOTWRITABLE_USING_DEFAULT', $path, $defaultTmpPath), Log::WARNING, 'jerror' ); } catch (\RuntimeException) { $app->enqueueMessage( Text::sprintf('COM_CONFIG_ERROR_CUSTOM_TEMP_PATH_NOTWRITABLE_USING_DEFAULT', $path, $defaultTmpPath), 'warning' ); } $error = false; $data['tmp_path'] = $defaultTmpPath; } if ($error) { try { Log::add(Text::sprintf('COM_CONFIG_ERROR_TMP_PATH_NOTWRITABLE', $path), Log::WARNING, 'jerror'); } catch (\RuntimeException) { $app->enqueueMessage(Text::sprintf('COM_CONFIG_ERROR_TMP_PATH_NOTWRITABLE', $path), 'warning'); } } } /* * Look for a custom log_path * First check if a path is given in the submitted data, then check if a path exists in the previous data, otherwise use the default */ $defaultLogPath = JPATH_ADMINISTRATOR . '/logs'; if (!empty($data['log_path'])) { $path = $data['log_path']; } elseif (!empty($prev['log_path'])) { $path = $prev['log_path']; } else { $path = $defaultLogPath; } $path = Path::clean($path); // Give a warning if the log-folder is not valid or not writable if (!is_dir($path) || !is_writable($path)) { $error = true; // If a custom path is in use, try using the system default log path if ($path !== $defaultLogPath && is_dir($defaultLogPath) && is_writable($defaultLogPath)) { try { Log::add( Text::sprintf('COM_CONFIG_ERROR_CUSTOM_LOG_PATH_NOTWRITABLE_USING_DEFAULT', $path, $defaultLogPath), Log::WARNING, 'jerror' ); } catch (\RuntimeException) { $app->enqueueMessage( Text::sprintf('COM_CONFIG_ERROR_CUSTOM_LOG_PATH_NOTWRITABLE_USING_DEFAULT', $path, $defaultLogPath), 'warning' ); } $error = false; $data['log_path'] = $defaultLogPath; } if ($error) { try { Log::add(Text::sprintf('COM_CONFIG_ERROR_LOG_PATH_NOTWRITABLE', $path), Log::WARNING, 'jerror'); } catch (\RuntimeException) { $app->enqueueMessage(Text::sprintf('COM_CONFIG_ERROR_LOG_PATH_NOTWRITABLE', $path), 'warning'); } } } // Create the new configuration object. $config = new Registry($data); // Overwrite webservices cors settings $app->set('cors', $data['cors'] ?? 0); $app->set('cors_allow_origin', $data['cors_allow_origin'] ?? '*'); $app->set('cors_allow_headers', $data['cors_allow_headers'] ?? 'Content-Type,X-Joomla-Token'); $app->set('cors_allow_methods', $data['cors_allow_methods'] ?? ''); // Clear cache of com_config component. $this->cleanCache('_system'); $dispatcher = $this->getDispatcher(); $eventBefore = new BeforeSaveConfigurationEvent('onApplicationBeforeSave', ['subject' => $config]); $result = $dispatcher->dispatch('onApplicationBeforeSave', $eventBefore)->getArgument('result', []); // Store the data. if (\in_array(false, $result, true)) { throw new \RuntimeException(Text::_('COM_CONFIG_ERROR_UNKNOWN_BEFORE_SAVING')); } // Write the configuration file. $result = $this->writeConfigFile($config); // Trigger the after save event. $this->getDispatcher()->dispatch('onApplicationAfterSave', new AfterSaveConfigurationEvent( 'onApplicationAfterSave', ['subject' => $config] )); return $result; } /** * Method to unset the root_user value from configuration data. * * This method will load the global configuration data straight from * JConfig and remove the root_user value for security, then save the configuration. * * @return boolean True on success, false on failure. * * @since 1.6 */ public function removeroot() { // Get the previous configuration. $prev = new \JConfig(); $prev = ArrayHelper::fromObject($prev); // Create the new configuration object, and unset the root_user property unset($prev['root_user']); $config = new Registry($prev); $dispatcher = $this->getDispatcher(); $eventBefore = new BeforeSaveConfigurationEvent('onApplicationBeforeSave', ['subject' => $config]); $result = $dispatcher->dispatch('onApplicationBeforeSave', $eventBefore)->getArgument('result', []); // Store the data. if (\in_array(false, $result, true)) { throw new \RuntimeException(Text::_('COM_CONFIG_ERROR_UNKNOWN_BEFORE_SAVING')); } // Write the configuration file. $result = $this->writeConfigFile($config); // Trigger the after save event. $this->getDispatcher()->dispatch('onApplicationAfterSave', new AfterSaveConfigurationEvent( 'onApplicationAfterSave', ['subject' => $config] )); return $result; } /** * Method to write the configuration to a file. * * @param Registry $config A Registry object containing all global config data. * * @return boolean True on success, false on failure. * * @since 2.5.4 * @throws \RuntimeException */ private function writeConfigFile(Registry $config) { // Set the configuration file path. $file = JPATH_CONFIGURATION . '/configuration.php'; $app = Factory::getApplication(); // Attempt to make the file writable. if (Path::isOwner($file) && !Path::setPermissions($file, '0644')) { $app->enqueueMessage(Text::_('COM_CONFIG_ERROR_CONFIGURATION_PHP_NOTWRITABLE'), 'notice'); } // Attempt to write the configuration file as a PHP class named JConfig. $configuration = $config->toString('PHP', ['class' => 'JConfig', 'closingtag' => false]); if (!File::write($file, $configuration)) { throw new \RuntimeException(Text::_('COM_CONFIG_ERROR_WRITE_FAILED')); } // Attempt to make the file unwritable. if (Path::isOwner($file) && !Path::setPermissions($file, '0444')) { $app->enqueueMessage(Text::_('COM_CONFIG_ERROR_CONFIGURATION_PHP_NOTUNWRITABLE'), 'notice'); } return true; } /** * Method to store the permission values in the asset table. * * This method will get an array with permission key value pairs and transform it * into json and update the asset table in the database. * * @param string $permission Need an array with Permissions (component, rule, value and title) * * @return array|bool A list of result data or false on failure. * * @since 3.5 */ public function storePermissions($permission = null) { $app = Factory::getApplication(); $input = $app->getInput(); $user = $this->getCurrentUser(); if (\is_null($permission)) { // Get data from input. $permission = [ 'component' => $input->json->get('comp'), 'action' => $input->json->get('action'), 'rule' => $input->json->get('rule'), 'value' => $input->json->get('value'), 'title' => $input->json->get('title', '', 'RAW'), ]; } // We are creating a new item so we don't have an item id so don't allow. if (str_ends_with($permission['component'], '.false')) { $app->enqueueMessage(Text::_('JLIB_RULES_SAVE_BEFORE_CHANGE_PERMISSIONS'), 'error'); return false; } // Check if the user is authorized to do this. if (!$user->authorise('core.admin', $permission['component'])) { $app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'error'); return false; } $permission['component'] = empty($permission['component']) ? 'root.1' : $permission['component']; // Current view is global config? $isGlobalConfig = $permission['component'] === 'root.1'; // Check if changed group has Super User permissions. $isSuperUserGroupBefore = Access::checkGroup($permission['rule'], 'core.admin'); // Check if current user belongs to changed group. $currentUserBelongsToGroup = \in_array((int) $permission['rule'], $user->groups); // Get current user groups tree. $currentUserGroupsTree = Access::getGroupsByUser($user->id, true); // Check if current user belongs to changed group. $currentUserSuperUser = $user->authorise('core.admin'); // If user is not Super User cannot change the permissions of a group it belongs to. if (!$currentUserSuperUser && $currentUserBelongsToGroup) { $app->enqueueMessage(Text::_('JLIB_USER_ERROR_CANNOT_CHANGE_OWN_GROUPS'), 'error'); return false; } // If user is not Super User cannot change the permissions of a group it belongs to. if (!$currentUserSuperUser && \in_array((int) $permission['rule'], $currentUserGroupsTree)) { $app->enqueueMessage(Text::_('JLIB_USER_ERROR_CANNOT_CHANGE_OWN_PARENT_GROUPS'), 'error'); return false; } // If user is not Super User cannot change the permissions of a Super User Group. if (!$currentUserSuperUser && $isSuperUserGroupBefore && !$currentUserBelongsToGroup) { $app->enqueueMessage(Text::_('JLIB_USER_ERROR_CANNOT_CHANGE_SUPER_USER'), 'error'); return false; } // If user is not Super User cannot change the Super User permissions in any group it belongs to. if ($isSuperUserGroupBefore && $currentUserBelongsToGroup && $permission['action'] === 'core.admin') { $app->enqueueMessage(Text::_('JLIB_USER_ERROR_CANNOT_DEMOTE_SELF'), 'error'); return false; } try { /** @var Asset $asset */ $asset = Table::getInstance('asset'); $result = $asset->loadByName($permission['component']); if ($result === false) { $data = [$permission['action'] => [$permission['rule'] => $permission['value']]]; $rules = new Rules($data); $asset->rules = (string) $rules; $asset->name = (string) $permission['component']; $asset->title = (string) $permission['title']; // Get the parent asset id so we have a correct tree. /** @var Asset $parentAsset */ $parentAsset = Table::getInstance('Asset'); if (str_contains($asset->name, '.')) { $assetParts = explode('.', $asset->name); $parentAsset->loadByName($assetParts[0]); $parentAssetId = $parentAsset->id; } else { $parentAssetId = $parentAsset->getRootId(); } /** * @todo: incorrect ACL stored * When changing a permission of an item that doesn't have a row in the asset table the row a new row is created. * This works fine for item <-> component <-> global config scenario and component <-> global config scenario. * But doesn't work properly for item <-> section(s) <-> component <-> global config scenario, * because a wrong parent asset id (the component) is stored. * Happens when there is no row in the asset table (ex: deleted or not created on update). */ $asset->setLocation($parentAssetId, 'last-child'); } else { // Decode the rule settings. $temp = json_decode($asset->rules, true); // Check if a new value is to be set. if (isset($permission['value'])) { // Check if we already have an action entry. if (!isset($temp[$permission['action']])) { $temp[$permission['action']] = []; } // Check if we already have a rule entry. if (!isset($temp[$permission['action']][$permission['rule']])) { $temp[$permission['action']][$permission['rule']] = []; } // Set the new permission. $temp[$permission['action']][$permission['rule']] = (int) $permission['value']; // Check if we have an inherited setting. if ($permission['value'] === '') { unset($temp[$permission['action']][$permission['rule']]); } // Check if we have any rules. if (!$temp[$permission['action']]) { unset($temp[$permission['action']]); } } else { // There is no value so remove the action as it's not needed. unset($temp[$permission['action']]); } $asset->rules = json_encode($temp, JSON_FORCE_OBJECT); } if (!$asset->check() || !$asset->store()) { $app->enqueueMessage(Text::_('JLIB_UNKNOWN'), 'error'); return false; } } catch (\Exception $e) { $app->enqueueMessage($e->getMessage(), 'error'); return false; } // All checks done. $result = [ 'text' => '', 'class' => '', 'result' => true, ]; // Show the current effective calculated permission considering current group, path and cascade. try { // The database instance $db = $this->getDatabase(); // Get the asset id by the name of the component. $query = $db->getQuery(true) ->select($db->quoteName('id')) ->from($db->quoteName('#__assets')) ->where($db->quoteName('name') . ' = :component') ->bind(':component', $permission['component']); $db->setQuery($query); $assetId = (int) $db->loadResult(); // Fetch the parent asset id. $parentAssetId = null; /** * @todo: incorrect info * When creating a new item (not saving) it uses the calculated permissions from the component (item <-> component <-> global config). * But if we have a section too (item <-> section(s) <-> component <-> global config) this is not correct. * Also, currently it uses the component permission, but should use the calculated permissions for a child of the component/section. */ // If not in global config we need the parent_id asset to calculate permissions. if (!$isGlobalConfig) { // In this case we need to get the component rules too. $query->clear() ->select($db->quoteName('parent_id')) ->from($db->quoteName('#__assets')) ->where($db->quoteName('id') . ' = :assetid') ->bind(':assetid', $assetId, ParameterType::INTEGER); $db->setQuery($query); $parentAssetId = (int) $db->loadResult(); } // Get the group parent id of the current group. $rule = (int) $permission['rule']; $query->clear() ->select($db->quoteName('parent_id')) ->from($db->quoteName('#__usergroups')) ->where($db->quoteName('id') . ' = :rule') ->bind(':rule', $rule, ParameterType::INTEGER); $db->setQuery($query); $parentGroupId = (int) $db->loadResult(); // Count the number of child groups of the current group. $query->clear() ->select('COUNT(' . $db->quoteName('id') . ')') ->from($db->quoteName('#__usergroups')) ->where($db->quoteName('parent_id') . ' = :rule') ->bind(':rule', $rule, ParameterType::INTEGER); $db->setQuery($query); $totalChildGroups = (int) $db->loadResult(); } catch (\Exception $e) { $app->enqueueMessage($e->getMessage(), 'error'); return false; } // Clear access statistics. Access::clearStatics(); // After current group permission is changed we need to check again if the group has Super User permissions. $isSuperUserGroupAfter = Access::checkGroup($permission['rule'], 'core.admin'); // Get the rule for just this asset (non-recursive) and get the actual setting for the action for this group. $assetRule = Access::getAssetRules($assetId, false, false)->allow($permission['action'], $permission['rule']); // Get the group, group parent id, and group global config recursive calculated permission for the chosen action. $inheritedGroupRule = Access::checkGroup($permission['rule'], $permission['action'], $assetId); if (!empty($parentAssetId)) { $inheritedGroupParentAssetRule = Access::checkGroup($permission['rule'], $permission['action'], $parentAssetId); } else { $inheritedGroupParentAssetRule = null; } $inheritedParentGroupRule = !empty($parentGroupId) ? Access::checkGroup($parentGroupId, $permission['action'], $assetId) : null; // Current group is a Super User group, so calculated setting is "Allowed (Super User)". if ($isSuperUserGroupAfter) { $result['class'] = 'badge bg-success'; $result['text'] = '<span class="icon-lock icon-white" aria-hidden="true"></span>' . Text::_('JLIB_RULES_ALLOWED_ADMIN'); } else { // Not super user. // First get the real recursive calculated setting and add (Inherited) to it. // If recursive calculated setting is "Denied" or null. Calculated permission is "Not Allowed (Inherited)". if ($inheritedGroupRule === null || $inheritedGroupRule === false) { $result['class'] = 'badge bg-danger'; $result['text'] = Text::_('JLIB_RULES_NOT_ALLOWED_INHERITED'); } else { // If recursive calculated setting is "Allowed". Calculated permission is "Allowed (Inherited)". $result['class'] = 'badge bg-success'; $result['text'] = Text::_('JLIB_RULES_ALLOWED_INHERITED'); } // Second part: Overwrite the calculated permissions labels if there is an explicit permission in the current group. /** * @todo: incorrect info * If a component has a permission that doesn't exists in global config (ex: frontend editing in com_modules) by default * we get "Not Allowed (Inherited)" when we should get "Not Allowed (Default)". */ // If there is an explicit permission "Not Allowed". Calculated permission is "Not Allowed". if ($assetRule === false) { $result['class'] = 'badge bg-danger'; $result['text'] = Text::_('JLIB_RULES_NOT_ALLOWED'); } elseif ($assetRule === true) { // If there is an explicit permission is "Allowed". Calculated permission is "Allowed". $result['class'] = 'badge bg-success'; $result['text'] = Text::_('JLIB_RULES_ALLOWED'); } // Third part: Overwrite the calculated permissions labels for special cases. // Global configuration with "Not Set" permission. Calculated permission is "Not Allowed (Default)". if (empty($parentGroupId) && $isGlobalConfig === true && $assetRule === null) { $result['class'] = 'badge bg-danger'; $result['text'] = Text::_('JLIB_RULES_NOT_ALLOWED_DEFAULT'); } elseif ($inheritedGroupParentAssetRule === false || $inheritedParentGroupRule === false) { /** * Component/Item with explicit "Denied" permission at parent Asset (Category, Component or Global config) configuration. * Or some parent group has an explicit "Denied". * Calculated permission is "Not Allowed (Locked)". */ $result['class'] = 'badge bg-danger'; $result['text'] = '<span class="icon-lock icon-white" aria-hidden="true"></span>' . Text::_('JLIB_RULES_NOT_ALLOWED_LOCKED'); } } // If removed or added super user from group, we need to refresh the page to recalculate all settings. if ($isSuperUserGroupBefore != $isSuperUserGroupAfter) { $app->enqueueMessage(Text::_('JLIB_RULES_NOTICE_RECALCULATE_GROUP_PERMISSIONS'), 'notice'); } // If this group has child groups, we need to refresh the page to recalculate the child settings. if ($totalChildGroups > 0) { $app->enqueueMessage(Text::_('JLIB_RULES_NOTICE_RECALCULATE_GROUP_CHILDS_PERMISSIONS'), 'notice'); } return $result; } /** * Method to send a test mail which is called via an AJAX request * * @return boolean * * @since 3.5 */ public function sendTestMail() { // Set the new values to test with the current settings $app = Factory::getApplication(); $user = $this->getCurrentUser(); $input = $app->getInput()->json; $smtppass = $input->get('smtppass', null, 'RAW'); $config = new Registry(); $config->set('smtpauth', $input->get('smtpauth')); $config->set('smtpuser', $input->get('smtpuser', '', 'STRING')); $config->set('smtphost', $input->get('smtphost')); $config->set('smtpsecure', $input->get('smtpsecure')); $config->set('smtpport', $input->get('smtpport')); $config->set('mailfrom', $input->get('mailfrom', '', 'STRING')); $config->set('fromname', $input->get('fromname', '', 'STRING')); $config->set('mailer', $input->get('mailer')); $config->set('mailonline', $input->get('mailonline')); // Use smtppass only if it was submitted if ($smtppass !== null) { $config->set('smtppass', $smtppass); } $mail = $this->getMailerFactory()->createMailer($config); // Prepare email and try to send it $mailer = new MailTemplate('com_config.test_mail', $user->getParam('language', $app->get('language')), $mail); $mailer->addTemplateData( [ // Replace the occurrences of "@" and "|" in the site name 'sitename' => str_replace(['@', '|'], '', $app->get('sitename')), 'method' => Text::_('COM_CONFIG_SENDMAIL_METHOD_' . strtoupper($mail->Mailer)), ] ); $mailer->addRecipient($user->email, $user->name); try { $mailSent = $mailer->send(); } catch (MailDisabledException | phpMailerException $e) { $app->enqueueMessage($e->getMessage(), 'error'); return false; } if ($mailSent === true) { $methodName = Text::_('COM_CONFIG_SENDMAIL_METHOD_' . strtoupper($mail->Mailer)); // If JMail send the mail using PHP Mail as fallback. if ($mail->Mailer !== $app->get('mailer')) { $app->enqueueMessage(Text::sprintf('COM_CONFIG_SENDMAIL_SUCCESS_FALLBACK', $user->email, $methodName), 'warning'); } else { $app->enqueueMessage(Text::sprintf('COM_CONFIG_SENDMAIL_SUCCESS', $user->email, $methodName), 'message'); } return true; } $app->enqueueMessage(Text::_('COM_CONFIG_SENDMAIL_ERROR'), 'error'); return false; } } PK ��\ƐD�! ! src/Model/ComponentModel.phpnu �[��� <?php /** * @package Joomla.Administrator * @subpackage com_config * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Config\Administrator\Model; use Joomla\CMS\Access\Access; use Joomla\CMS\Access\Rules; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\Model\FormModel; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Table\Table; use Joomla\Filesystem\Path; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Model for component configuration * * @since 3.2 */ class ComponentModel extends FormModel { /** * Method to auto-populate the model state. * * Note. Calling getState in this method will result in recursion. * * @return void * * @since 3.2 */ protected function populateState() { $input = Factory::getApplication()->getInput(); // Set the component (option) we are dealing with. $component = $input->get('component'); $this->state->set('component.option', $component); // Set an alternative path for the configuration file. if ($path = $input->getString('path')) { $path = Path::clean(JPATH_SITE . '/' . $path); Path::check($path); $this->state->set('component.path', $path); } } /** * Method to get a form object. * * @param array $data Data for the form. * @param boolean $loadData True if the form is to load its own data (default case), false if not. * * @return mixed A Form object on success, false on failure * * @since 3.2 */ public function getForm($data = [], $loadData = true) { $state = $this->getState(); $option = $state->get('component.option'); if ($path = $state->get('component.path')) { // Add the search path for the admin component config.xml file. Form::addFormPath($path); } else { // Add the search path for the admin component config.xml file. Form::addFormPath(JPATH_ADMINISTRATOR . '/components/' . $option); } // Get the form. $form = $this->loadForm( 'com_config.component', 'config', ['control' => 'jform', 'load_data' => $loadData], false, '/config' ); if (empty($form)) { return false; } $lang = Factory::getLanguage(); $lang->load($option, JPATH_BASE) || $lang->load($option, JPATH_BASE . "/components/$option"); return $form; } /** * Method to get the data that should be injected in the form. * * @return array The default data is an empty array. * * @since 4.0.0 */ protected function loadFormData() { $option = $this->getState()->get('component.option'); // Check the session for previously entered form data. $data = Factory::getApplication()->getUserState('com_config.edit.component.' . $option . '.data', []); if (empty($data)) { return $this->getComponent()->getParams()->toArray(); } return $data; } /** * Get the component information. * * @return object * * @since 3.2 */ public function getComponent() { $state = $this->getState(); $option = $state->get('component.option'); // Load common and local language files. $lang = Factory::getLanguage(); $lang->load($option, JPATH_BASE) || $lang->load($option, JPATH_BASE . "/components/$option"); $result = ComponentHelper::getComponent($option); return $result; } /** * Method to save the configuration data. * * @param array $data An array containing all global config data. * * @return boolean True on success, false on failure. * * @since 3.2 * @throws \RuntimeException */ public function save($data) { $table = Table::getInstance('extension'); $context = $this->option . '.' . $this->name; PluginHelper::importPlugin('extension'); // Check super user group. if (isset($data['params']) && !$this->getCurrentUser()->authorise('core.admin')) { $form = $this->getForm([], false); foreach ($form->getFieldsets() as $fieldset) { foreach ($form->getFieldset($fieldset->name) as $field) { if ( $field->type === 'UserGroupList' && isset($data['params'][$field->fieldname]) && (int) $field->getAttribute('checksuperusergroup', 0) === 1 && Access::checkGroup($data['params'][$field->fieldname], 'core.admin') ) { throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED')); } } } } // Save the rules. if (isset($data['params']['rules'])) { if (!$this->getCurrentUser()->authorise('core.admin', $data['option'])) { throw new \RuntimeException(Text::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED')); } $rules = new Rules($data['params']['rules']); $asset = Table::getInstance('asset'); if (!$asset->loadByName($data['option'])) { $root = Table::getInstance('asset'); $root->loadByName('root.1'); $asset->name = $data['option']; $asset->title = $data['option']; $asset->setLocation($root->id, 'last-child'); } $asset->rules = (string) $rules; if (!$asset->check() || !$asset->store()) { throw new \RuntimeException($asset->getError()); } // We don't need this anymore unset($data['option'], $data['params']['rules']); } // Load the previous Data if (!$table->load($data['id'])) { throw new \RuntimeException($table->getError()); } unset($data['id']); // Bind the data. if (!$table->bind($data)) { throw new \RuntimeException($table->getError()); } // Check the data. if (!$table->check()) { throw new \RuntimeException($table->getError()); } $result = Factory::getApplication()->triggerEvent('onExtensionBeforeSave', [$context, $table, false]); // Store the data. if (\in_array(false, $result, true) || !$table->store()) { throw new \RuntimeException($table->getError()); } Factory::getApplication()->triggerEvent('onExtensionAfterSave', [$context, $table, false]); // Clean the component cache. $this->cleanCache('_system'); return true; } } PK ��\�Sʉ� � src/Model/.htaccessnu �7��m <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>PK ��\��1' ! src/View/Application/HtmlView.phpnu �[��� <?php /** * @package Joomla.Administrator * @subpackage com_config * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Config\Administrator\View\Application; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\ToolbarHelper; use Joomla\Component\Config\Administrator\Helper\ConfigHelper; use Joomla\Component\Config\Administrator\Model\ApplicationModel; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * View for the global configuration * * @since 3.2 */ class HtmlView extends BaseHtmlView { /** * The model state * * @var \Joomla\Registry\Registry * @since 3.2 */ public $state; /** * The form object * * @var \Joomla\CMS\Form\Form * @since 3.2 */ public $form; /** * The data to be displayed in the form * * @var array * @since 3.2 */ public $data; /** * Title of the fieldset * * @var string */ public $name; /** * Name of the fields to display * * @var string */ public $fieldsname; /** * CSS class of the form * * @var string */ public $formclass; /** * Description of the fieldset * * @var string */ public $description; /** * Execute and display a template script. * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void * * @see \JViewLegacy::loadTemplate() * @since 3.0 */ public function display($tpl = null) { try { /** @var ApplicationModel $model */ $model = $this->getModel(); // Load Form and Data $this->form = $model->getForm(); $this->data = $model->getData(); $this->user = $this->getCurrentUser(); } catch (\Exception $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); return; } // Bind data if ($this->form && $this->data) { $this->form->bind($this->data); } // Get the params for com_users. $this->usersParams = ComponentHelper::getParams('com_users'); // Get the params for com_media. $this->mediaParams = ComponentHelper::getParams('com_media'); $this->components = ConfigHelper::getComponentsWithConfig(); ConfigHelper::loadLanguageForComponents($this->components); $this->userIsSuperAdmin = $this->user->authorise('core.admin'); $this->addToolbar(); parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 3.2 */ protected function addToolbar() { $toolbar = $this->getDocument()->getToolbar(); ToolbarHelper::title(Text::_('COM_CONFIG_GLOBAL_CONFIGURATION'), 'cog config'); $toolbar->apply('application.apply'); $toolbar->divider(); $toolbar->save('application.save'); $toolbar->divider(); $toolbar->cancel('application.cancel'); $toolbar->divider(); $toolbar->inlinehelp(); $toolbar->help('Site_Global_Configuration'); } } PK ��\�Sʉ� � src/View/Application/.htaccessnu �7��m <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>PK ��\�M��� � src/View/Component/HtmlView.phpnu �[��� <?php /** * @package Joomla.Administrator * @subpackage com_config * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Config\Administrator\View\Component; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Toolbar\ToolbarHelper; use Joomla\Component\Config\Administrator\Helper\ConfigHelper; use Joomla\Component\Config\Administrator\Model\ComponentModel; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * View for the component configuration * * @since 3.2 */ class HtmlView extends BaseHtmlView { /** * The model state * * @var \Joomla\Registry\Registry * @since 3.2 */ public $state; /** * The form object * * @var \Joomla\CMS\Form\Form * @since 3.2 */ public $form; /** * An object with the information for the component * * @var \Joomla\CMS\Component\ComponentRecord * @since 3.2 */ public $component; /** * List of fieldset objects * * @var object[] * * @since 5.2.0 */ public $fieldsets; /** * Form control * * @var string * * @since 5.2.0 */ public $formControl; /** * Base64 encoded return URL * * @var string * * @since 5.2.0 */ public $return; /** * Execute and display a template script. * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void * * @see \JViewLegacy::loadTemplate() * @since 3.2 */ public function display($tpl = null) { try { /** @var ComponentModel $model */ $model = $this->getModel(); $this->component = $model->getComponent(); if (!$this->component->enabled) { return; } $this->form = $model->getForm(); $user = $this->getCurrentUser(); } catch (\Exception $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); return; } $this->fieldsets = $this->form ? $this->form->getFieldsets() : null; $this->formControl = $this->form ? $this->form->getFormControl() : null; // Don't show permissions fieldset if not authorised. if (!$user->authorise('core.admin', $this->component->option) && isset($this->fieldsets['permissions'])) { unset($this->fieldsets['permissions']); } $this->components = ConfigHelper::getComponentsWithConfig(); $this->userIsSuperAdmin = $user->authorise('core.admin'); $this->currentComponent = Factory::getApplication()->getInput()->get('component'); $this->return = Factory::getApplication()->getInput()->get('return', '', 'base64'); $this->addToolbar(); parent::display($tpl); } /** * Add the page title and toolbar. * * @return void * * @since 3.2 */ protected function addToolbar() { $toolbar = $this->getDocument()->getToolbar(); ToolbarHelper::title(Text::_($this->component->option . '_configuration'), 'cog config'); $toolbar->apply('component.apply'); $toolbar->divider(); $toolbar->save('component.save'); $toolbar->divider(); $toolbar->cancel('component.cancel'); $toolbar->divider(); $inlinehelp = (string) $this->form->getXml()->config->inlinehelp['button'] === 'show'; $targetClass = (string) $this->form->getXml()->config->inlinehelp['targetclass'] ?: 'hide-aware-inline-help'; if ($inlinehelp) { $toolbar->inlinehelp($targetClass); } $helpUrl = $this->form->getData()->get('helpURL'); $helpKey = (string) $this->form->getXml()->config->help['key']; // Try with legacy language key if (!$helpKey) { $language = Factory::getApplication()->getLanguage(); $languageKey = 'JHELP_COMPONENTS_' . strtoupper($this->currentComponent) . '_OPTIONS'; if ($language->hasKey($languageKey)) { $helpKey = $languageKey; } } $toolbar->help($helpKey, (bool) $helpUrl, null, $this->currentComponent); } } PK ��\�Sʉ� � src/View/Component/.htaccessnu �7��m <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>PK ��\�Sʉ� � src/View/.htaccessnu �7��m <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>PK ��\�?��� � ! src/Extension/ConfigComponent.phpnu �[��� <?php /** * @package Joomla.Administrator * @subpackage com_config * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Config\Administrator\Extension; use Joomla\CMS\Component\Router\RouterServiceInterface; use Joomla\CMS\Component\Router\RouterServiceTrait; use Joomla\CMS\Extension\MVCComponent; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Component class for com_config * * @since 4.0.0 */ class ConfigComponent extends MVCComponent implements RouterServiceInterface { use RouterServiceTrait; } PK ��\�Sʉ� � src/Extension/.htaccessnu �7��m <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>PK ��\���6~ ~ &