<?php
/*
 * @package 	RSFirewall!
 * @copyright 	(c) 2009 - 2024 RSJoomla!
 * @link 		https://www.rsjoomla.com/joomla-extensions/joomla-security.html
 * @license 	GNU General Public License https://www.gnu.org/licenses/gpl-3.0.en.html
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Session\Session;

class RSFirewallProtectionHelix3 extends RSFirewallProtection
{
	protected $reason = 'COM_RSFIREWALL_PHP_CODE_DETECTED';
	protected $code = 'HELIX3_INJECTION_ATTEMPT';

	public function isInjection()
	{
		if ($this->getOption() === 'com_ajax')
		{
			if (isset($_POST['action']) && in_array(strtolower($_POST['action']), array('upload_image', 'remove_image')))
			{
				if (!Session::checkToken('request'))
				{
					return true;
				}
				$user = Factory::getUser();
				if ($user->guest)
				{
					return true;
				}
				$action = strtolower($_POST['action']);
				if ($action === 'upload_image')
				{
					if (!$user->authorise('core.create', 'com_media'))
					{
						return true;
					}
					if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK)
					{
						if (!in_array($this->getExtension($_FILES['image']['name']), array('jpg', 'jpeg', 'png', 'gif', 'webp')))
						{
							$this->extra = 'action=upload_image, src=' . $_FILES['image']['name'];
							return true;
						}
					}
				}
				elseif ($action === 'remove_image')
				{
					if (!$user->authorise('core.delete', 'com_media'))
					{
						return true;
					}

					if (isset($_POST['src']))
					{
						$path = $this->getSafeMediaImagePath($_POST['src']);
						if ($path === null || !file_exists($path))
						{
							$this->extra = 'action=remove_image, src=' . $_POST['src'];
							return true;
						}
					}
				}
			}

			if (isset($_POST['data']) && is_array($_POST['data']))
			{
				$data = $_POST['data'];
				$adminActions = array(
					'remove',
					'save',
					'load',
					'resetLayout',
					'import',
					'updateFonts',
					'fontVariants',
				);
				if (isset($data['action']) && in_array($data['action'], $adminActions))
				{
					if (!Session::checkToken('request'))
					{
						return true;
					}
					$user = Factory::getUser();
					if ($user->guest || (!$user->authorise('core.admin') && !$user->authorise('core.manage', 'com_templates')))
					{
						return true;
					}

					$action = $data['action'];
					if ($action === 'remove')
					{
						if (isset($data['layoutName']))
						{
							$layoutName = $data['layoutName'];
							if (strpos($layoutName, '/') !== false || strpos($layoutName, '..') !== false || strtolower(substr($layoutName, -5)) !== '.json')
							{
								$this->extra = 'data[action]=remove, layoutName=' . $layoutName;
								return true;
							}
						}
					}
					elseif ($action === 'save')
					{
						if (isset($data['layoutName']))
						{
							$layoutName = $data['layoutName'];
							if (strpos($layoutName, '/') !== false || strpos($layoutName, '..') !== false)
							{
								$this->extra = 'data[action]=save, layoutName=' . $layoutName;
								return true;
							}
						}
					}
				}

				return false;
			}
		}

		return false;
	}

	protected function getExtension($filename)
	{
		return strtolower(pathinfo($filename, PATHINFO_EXTENSION));
	}

	private function getSafeMediaImagePath($src)
	{
		$src = str_replace('\\', '/', (string) $src);
		$src = ltrim($src, '/');

		if ($src === '' || strpos($src, "\0") !== false || strpos($src, '..') !== false) {
			return null;
		}

		if (strpos($src, 'images/') !== 0) {
			return null;
		}

		$extension = $this->getExtension($src);

		if (!$this->isAllowedImageExtension($extension)) {
			return null;
		}

		$basePath = realpath(JPATH_ROOT . '/images');
		$path = JPATH_ROOT . '/' . $src;
		$realPath = realpath($path);

		if ($basePath === false || $realPath === false) {
			return null;
		}

		if (strpos($realPath, $basePath . DIRECTORY_SEPARATOR) !== 0) {
			return null;
		}

		return $realPath;
	}

	private function isAllowedImageExtension($extension)
	{
		return in_array(strtolower((string) $extension), array('jpg', 'jpeg', 'png', 'gif', 'webp'), true);
	}
}