Current File : /home/pacjaorg/public_html/nsa/libraries/src/Application/AdministratorApplication.php
<?php
/**
 * Joomla! Content Management System
 *
 * @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\CMS\Application;

\defined('JPATH_PLATFORM') or die;

use Joomla\Application\Web\WebClient;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Input\Input;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Router;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\ParameterType;
use Joomla\DI\Container;
use Joomla\Registry\Registry;

/**
 * Joomla! Administrator Application class
 *
 * @since  3.2
 */
class AdministratorApplication extends CMSApplication
{
	/**
	 * List of allowed components for guests and users which do not have the core.login.admin privilege.
	 *
	 * By default we allow two core components:
	 *
	 * - com_login   Absolutely necessary to let users log into the backend of the site. Do NOT remove!
	 * - com_ajax    Handle AJAX requests or other administrative callbacks without logging in. Required for
	 *               passwordless authentication using WebAuthn.
	 *
	 * @var array
	 */
	protected $allowedUnprivilegedOptions = [
		'com_login',
		'com_ajax',
	];

	/**
	 * Class constructor.
	 *
	 * @param   Input      $input      An optional argument to provide dependency injection for the application's input
	 *                                 object.  If the argument is a JInput object that object will become the
	 *                                 application's input object, otherwise a default input object is created.
	 * @param   Registry   $config     An optional argument to provide dependency injection for the application's config
	 *                                 object.  If the argument is a Registry object that object will become the
	 *                                 application's config object, otherwise a default config object is created.
	 * @param   WebClient  $client     An optional argument to provide dependency injection for the application's
	 *                                 client object.  If the argument is a WebClient object that object will become the
	 *                                 application's client object, otherwise a default client object is created.
	 * @param   Container  $container  Dependency injection container.
	 *
	 * @since   3.2
	 */
	public function __construct(Input $input = null, Registry $config = null, WebClient $client = null, Container $container = null)
	{
		// Register the application name
		$this->name = 'administrator';

		// Register the client ID
		$this->clientId = 1;

		// Execute the parent constructor
		parent::__construct($input, $config, $client, $container);

		// Set the root in the URI based on the application name
		Uri::root(null, rtrim(\dirname(Uri::base(true)), '/\\'));
	}

	/**
	 * Dispatch the application
	 *
	 * @param   string  $component  The component which is being rendered.
	 *
	 * @return  void
	 *
	 * @since   3.2
	 */
	public function dispatch($component = null)
	{
		if ($component === null)
		{
			$component = $this->findOption();
		}

		// Load the document to the API
		$this->loadDocument();

		// Set up the params
		$document = Factory::getDocument();

		// Register the document object with Factory
		Factory::$document = $document;

		switch ($document->getType())
		{
			case 'html':
				// Get the template
				$template = $this->getTemplate(true);
				$clientId = $this->getClientId();

				// Store the template and its params to the config
				$this->set('theme', $template->template);
				$this->set('themeParams', $template->params);

				// Add Asset registry files
				$wr = $document->getWebAssetManager()->getRegistry();

				if ($component)
				{
					$wr->addExtensionRegistryFile($component);
				}

				if (!empty($template->parent))
				{
					$wr->addTemplateRegistryFile($template->parent, $clientId);
				}

				$wr->addTemplateRegistryFile($template->template, $clientId);

				break;

			default:
				break;
		}

		$document->setTitle($this->get('sitename') . ' - ' . Text::_('JADMINISTRATION'));
		$document->setDescription($this->get('MetaDesc'));
		$document->setGenerator('Joomla! - Open Source Content Management');

		$contents = ComponentHelper::renderComponent($component);
		$document->setBuffer($contents, 'component');

		// Trigger the onAfterDispatch event.
		PluginHelper::importPlugin('system');
		$this->triggerEvent('onAfterDispatch');
	}

	/**
	 * Method to run the Web application routines.
	 *
	 * @return  void
	 *
	 * @since   3.2
	 */
	protected function doExecute()
	{
		// Get the language from the (login) form or user state
		$login_lang = ($this->input->get('option') === 'com_login') ? $this->input->get('lang') : '';
		$options    = array('language' => $login_lang ?: $this->getUserState('application.lang'));

		// Initialise the application
		$this->initialiseApp($options);

		// Mark afterInitialise in the profiler.
		JDEBUG ? $this->profiler->mark('afterInitialise') : null;

		// Route the application
		$this->route();

		// Mark afterRoute in the profiler.
		JDEBUG ? $this->profiler->mark('afterRoute') : null;

		/*
		 * Check if the user is required to reset their password
		 *
		 * Before $this->route(); "option" and "view" can't be safely read using:
		 * $this->input->getCmd('option'); or $this->input->getCmd('view');
		 * ex: due of the sef urls
		 */
		$this->checkUserRequireReset('com_users', 'user', 'edit', 'com_users/user.edit,com_users/user.save,com_users/user.apply,com_login/logout');

		// Dispatch the application
		$this->dispatch();

		// Mark afterDispatch in the profiler.
		JDEBUG ? $this->profiler->mark('afterDispatch') : null;
	}

	/**
	 * Return a reference to the Router object.
	 *
	 * @param   string  $name     The name of the application.
	 * @param   array   $options  An optional associative array of configuration settings.
	 *
	 * @return  Router
	 *
	 * @since	3.2
	 */
	public static function getRouter($name = 'administrator', array $options = array())
	{
		return parent::getRouter($name, $options);
	}

	/**
	 * Gets the name of the current template.
	 *
	 * @param   boolean  $params  True to return the template parameters
	 *
	 * @return  string  The name of the template.
	 *
	 * @since   3.2
	 * @throws  \InvalidArgumentException
	 */
	public function getTemplate($params = false)
	{
		if (\is_object($this->template))
		{
			if ($params)
			{
				return $this->template;
			}

			return $this->template->template;
		}

		$admin_style = (int) Factory::getUser()->getParam('admin_style');

		// Load the template name from the database
		$db = Factory::getDbo();

		$query = $db->getQuery(true)
			->select($db->quoteName(['s.template', 's.params', 's.inheritable', 's.parent']))
			->from($db->quoteName('#__template_styles', 's'))
			->join(
				'LEFT',
				$db->quoteName('#__extensions', 'e'),
				$db->quoteName('e.type') . ' = ' . $db->quote('template')
					. ' AND ' . $db->quoteName('e.element') . ' = ' . $db->quoteName('s.template')
					. ' AND ' . $db->quoteName('e.client_id') . ' = ' . $db->quoteName('s.client_id')
			)
			->where(
				[
					$db->quoteName('s.client_id') . ' = 1',
					$db->quoteName('s.home') . ' = ' . $db->quote('1'),
				]
			);

		if ($admin_style)
		{
			$query->extendWhere(
				'OR',
				[
					$db->quoteName('s.client_id') . ' = 1',
					$db->quoteName('s.id') . ' = :style',
					$db->quoteName('e.enabled') . ' = 1',
				]
			)
				->bind(':style', $admin_style, ParameterType::INTEGER);
		}

		$query->order($db->quoteName('s.home'));
		$db->setQuery($query);
		$template = $db->loadObject();

		$template->template = InputFilter::getInstance()->clean($template->template, 'cmd');
		$template->params = new Registry($template->params);

		// Fallback template
		if (!is_file(JPATH_THEMES . '/' . $template->template . '/index.php')
			&& !is_file(JPATH_THEMES . '/' . $template->parent . '/index.php'))
		{
			$this->getLogger()->error(Text::_('JERROR_ALERTNOTEMPLATE'), ['category' => 'system']);
			$template->params = new Registry;
			$template->template = 'atum';

			// Check, the data were found and if template really exists
			if (!is_file(JPATH_THEMES . '/' . $template->template . '/index.php'))
			{
				throw new \InvalidArgumentException(Text::sprintf('JERROR_COULD_NOT_FIND_TEMPLATE', $template->template));
			}
		}

		// Cache the result
		$this->template = $template;

		// Pass the parent template to the state
		$this->set('themeInherits', $template->parent);

		if ($params)
		{
			return $template;
		}

		return $template->template;
	}

	/**
	 * Initialise the application.
	 *
	 * @param   array  $options  An optional associative array of configuration settings.
	 *
	 * @return  void
	 *
	 * @since   3.2
	 */
	protected function initialiseApp($options = array())
	{
		$user = Factory::getUser();

		// If the user is a guest we populate it with the guest user group.
		if ($user->guest)
		{
			$guestUsergroup = ComponentHelper::getParams('com_users')->get('guest_usergroup', 1);
			$user->groups = array($guestUsergroup);
		}

		// If a language was specified it has priority, otherwise use user or default language settings
		if (empty($options['language']))
		{
			$lang = $user->getParam('admin_language');

			// Make sure that the user's language exists
			if ($lang && LanguageHelper::exists($lang))
			{
				$options['language'] = $lang;
			}
			else
			{
				$params = ComponentHelper::getParams('com_languages');
				$options['language'] = $params->get('administrator', $this->get('language', 'en-GB'));
			}
		}

		// One last check to make sure we have something
		if (!LanguageHelper::exists($options['language']))
		{
			$lang = $this->get('language', 'en-GB');

			if (LanguageHelper::exists($lang))
			{
				$options['language'] = $lang;
			}
			else
			{
				// As a last ditch fail to english
				$options['language'] = 'en-GB';
			}
		}

		// Finish initialisation
		parent::initialiseApp($options);
	}

	/**
	 * Login authentication function
	 *
	 * @param   array  $credentials  Array('username' => string, 'password' => string)
	 * @param   array  $options      Array('remember' => boolean)
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   3.2
	 */
	public function login($credentials, $options = array())
	{
		// The minimum group
		$options['group'] = 'Public Backend';

		// Make sure users are not auto-registered
		$options['autoregister'] = false;

		// Set the application login entry point
		if (!\array_key_exists('entry_url', $options))
		{
			$options['entry_url'] = Uri::base() . 'index.php?option=com_users&task=login';
		}

		// Set the access control action to check.
		$options['action'] = 'core.login.admin';

		$result = parent::login($credentials, $options);

		if (!($result instanceof \Exception))
		{
			$lang = $this->input->getCmd('lang');
			$lang = preg_replace('/[^A-Z-]/i', '', $lang);

			if ($lang)
			{
				$this->setUserState('application.lang', $lang);
			}

			static::purgeMessages();
		}

		return $result;
	}

	/**
	 * Purge the jos_messages table of old messages
	 *
	 * @return  void
	 *
	 * @since   3.2
	 */
	public static function purgeMessages()
	{
		$userId = Factory::getUser()->id;

		$db = Factory::getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName(['cfg_name', 'cfg_value']))
			->from($db->quoteName('#__messages_cfg'))
			->where(
				[
					$db->quoteName('user_id') . ' = :userId',
					$db->quoteName('cfg_name') . ' = ' . $db->quote('auto_purge'),
				]
			)
			->bind(':userId', $userId, ParameterType::INTEGER);

		$db->setQuery($query);
		$config = $db->loadObject();

		// Check if auto_purge value set
		if (\is_object($config) && $config->cfg_name === 'auto_purge')
		{
			$purge = $config->cfg_value;
		}
		else
		{
			// If no value set, default is 7 days
			$purge = 7;
		}

		// If purge value is not 0, then allow purging of old messages
		if ($purge > 0)
		{
			// Purge old messages at day set in message configuration
			$past = Factory::getDate(time() - $purge * 86400)->toSql();

			$query = $db->getQuery(true)
				->delete($db->quoteName('#__messages'))
				->where(
					[
						$db->quoteName('date_time') . ' < :past',
						$db->quoteName('user_id_to') . ' = :userId',
					]
				)
				->bind(':past', $past)
				->bind(':userId', $userId, ParameterType::INTEGER);

			$db->setQuery($query);
			$db->execute();
		}
	}

	/**
	 * Rendering is the process of pushing the document buffers into the template
	 * placeholders, retrieving data from the document and pushing it into
	 * the application response buffer.
	 *
	 * @return  void
	 *
	 * @since   3.2
	 */
	protected function render()
	{
		// Get the \JInput object
		$input = $this->input;

		$component = $input->getCmd('option', 'com_login');
		$file      = $input->getCmd('tmpl', 'index');

		if ($component === 'com_login')
		{
			$file = 'login';
		}

		$this->set('themeFile', $file . '.php');

		// Safety check for when configuration.php root_user is in use.
		$rootUser = $this->get('root_user');

		if (property_exists('\JConfig', 'root_user'))
		{
			if (Factory::getUser()->get('username') === $rootUser || Factory::getUser()->id === (string) $rootUser)
			{
				$this->enqueueMessage(
					Text::sprintf(
						'JWARNING_REMOVE_ROOT_USER',
						'index.php?option=com_config&task=application.removeroot&' . Session::getFormToken() . '=1'
					),
					'warning'
				);
			}
			// Show this message to superusers too
			elseif (Factory::getUser()->authorise('core.admin'))
			{
				$this->enqueueMessage(
					Text::sprintf(
						'JWARNING_REMOVE_ROOT_USER_ADMIN',
						$rootUser,
						'index.php?option=com_config&task=application.removeroot&' . Session::getFormToken() . '=1'
					),
					'warning'
				);
			}
		}

		parent::render();
	}

	/**
	 * Route the application.
	 *
	 * Routing is the process of examining the request environment to determine which
	 * component should receive the request. The component optional parameters
	 * are then set in the request object to be processed when the application is being
	 * dispatched.
	 *
	 * @return  void
	 *
	 * @since   3.2
	 */
	protected function route()
	{
		$uri = Uri::getInstance();

		if ($this->get('force_ssl') >= 1 && strtolower($uri->getScheme()) !== 'https')
		{
			// Forward to https
			$uri->setScheme('https');
			$this->redirect((string) $uri, 301);
		}

		if ($this->isTwoFactorAuthenticationRequired())
		{
			$this->redirectIfTwoFactorAuthenticationRequired();
		}

		// Trigger the onAfterRoute event.
		PluginHelper::importPlugin('system');
		$this->triggerEvent('onAfterRoute');
	}

	/**
	 * Return the application option string [main component].
	 *
	 * @return  string  The component to access.
	 *
	 * @since   4.0.0
	 */
	public function findOption(): string
	{
		/** @var self $app */
		$app    = Factory::getApplication();
		$option = strtolower($app->input->get('option'));
		$user   = $app->getIdentity();

		/**
		 * Special handling for guest users and authenticated users without the Backend Login privilege.
		 *
		 * If the component they are trying to access is in the $this->allowedUnprivilegedOptions array we allow the
		 * request to go through. Otherwise we force com_login to be loaded, letting the user (re)try authenticating
		 * with a user account that has the Backend Login privilege.
		 */
		if ($user->get('guest') || !$user->authorise('core.login.admin'))
		{
			$option = in_array($option, $this->allowedUnprivilegedOptions) ? $option : 'com_login';
		}

		/**
		 * If no component is defined in the request we will try to load com_cpanel, the administrator Control Panel
		 * component. This allows the /administrator URL to display something meaningful after logging in instead of an
		 * error.
		 */
		if (empty($option))
		{
			$option = 'com_cpanel';
		}

		/**
		 * Force the option to the input object. This is necessary because we might have force-changed the component in
		 * the two if-blocks above.
		 */
		$app->input->set('option', $option);

		return $option;
	}
}
Site is undergoing maintenance

PACJA Events

Maintenance mode is on

Site will be available soon. Thank you for your patience!