Done ! 403WebShell
403Webshell
Server IP : 46.105.57.169  /  Your IP : 216.73.217.35
Web Server : Apache
System : Linux webm002.cluster120.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
User : verseaumee ( 152031)
PHP Version : 8.5.7
Disable Function : _dyuweyrj4,_dyuweyrj4r,dl
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/verseaumee/123click/assets/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/verseaumee/123click/assets/com_akeeba.tar
dispatcher.php000060400000007611150752453440007415 0ustar00<?php
/**
 * @package   AkeebaBackup
 * @copyright Copyright (c)2009-2016 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 * @since     3.5
 */

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

class AkeebaDispatcher extends F0FDispatcher
{
	public $defaultView = 'backup';

	public function onBeforeDispatch()
	{
		$result = parent::onBeforeDispatch();

		$view = empty($this->view) ? $this->defaultView : $this->view;
		$view = strtolower($view);
		$view = F0FInflector::singularize($view);

		if (!in_array($view, array('backup', 'check', 'json')))
		{
			return false;
		}

		if ($result)
		{
			// Merge the language overrides
			$paths = array(JPATH_ADMINISTRATOR, JPATH_ROOT);
			$jlang = JFactory::getLanguage();
			$jlang->load($this->component, $paths[0], 'en-GB', true);
			$jlang->load($this->component, $paths[0], null, true);
			$jlang->load($this->component, $paths[1], 'en-GB', true);
			$jlang->load($this->component, $paths[1], null, true);

			$jlang->load($this->component . '.override', $paths[0], 'en-GB', true);
			$jlang->load($this->component . '.override', $paths[0], null, true);
			$jlang->load($this->component . '.override', $paths[1], 'en-GB', true);
			$jlang->load($this->component . '.override', $paths[1], null, true);

			// Timezone fix; avoids errors printed out by PHP 5.3.3+ (thanks Yannick!)
			if (function_exists('date_default_timezone_get') && function_exists('date_default_timezone_set'))
			{
				if (function_exists('error_reporting'))
				{
					$oldLevel = error_reporting(0);
				}
				$serverTimezone = @date_default_timezone_get();
				if (empty($serverTimezone) || !is_string($serverTimezone))
				{
					$serverTimezone = 'UTC';
				}
				if (function_exists('error_reporting'))
				{
					error_reporting($oldLevel);
				}
				@date_default_timezone_set($serverTimezone);
			}

			// Necessary defines for Akeeba Engine
			if (!defined('AKEEBAENGINE'))
			{
				define('AKEEBAENGINE', 1); // Required for accessing Akeeba Engine's factory class
				define('AKEEBAROOT', JPATH_ADMINISTRATOR . '/components/com_akeeba/akeeba');
			}

			// I think I still use that stuff somewhere
			if (!defined('JPATH_COMPONENT_ADMINISTRATOR'))
			{
				define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR . '/components/com_akeeba');
			}

			// Make sure we have a profile set throughout the component's lifetime
			$session    = JFactory::getSession();
			$profile_id = $session->get('profile', null, 'akeeba');
			if (is_null($profile_id))
			{
				// No profile is set in the session; use default profile
				$session->set('profile', 1, 'akeeba');
			}

			// Load Akeeba Engine
			require_once JPATH_COMPONENT_ADMINISTRATOR . '/engine/Factory.php';
			Platform::addPlatform('joomla25', JPATH_COMPONENT_ADMINISTRATOR . '/platform/joomla25');

			// Load the Akeeba Backup configuration and check user access permission
			$akeebaEngineConfig = Factory::getConfiguration();
			Platform::getInstance()->load_configuration();
			unset($akeebaEngineConfig);

			// Preload helpers
			require_once JPATH_ADMINISTRATOR . '/components/com_akeeba/helpers/escape.php';

			// Load Akeeba Strapper
			include_once JPATH_ROOT . '/media/akeeba_strapper/strapper.php';
			AkeebaStrapper::bootstrap();
		}

		return $result;
	}

	public function dispatch()
	{
		// Look for controllers in the plugins folder
		$option   = $this->input->get('option', 'com_foobar', 'cmd');
		$view     = $this->input->get('view', $this->defaultView, 'cmd');
		$c        = F0FInflector::singularize($view);
		$alt_path = JPATH_SITE . '/components/' . $option . '/plugins/controllers/' . $c . '.php';

		JLoader::import('joomla.filesystem.file');
		if (JFile::exists($alt_path))
		{
			// The requested controller exists and there you load it...
			require_once($alt_path);
		}

		$this->input->set('view', $this->view);

		parent::dispatch();
	}
}models/jsons.php000060400000056002150752453440007704 0ustar00<?php
/**
 * @package   AkeebaBackup
 * @copyright Copyright (c)2009-2016 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 3, or later
 *
 * @since     3.0
 */

// Protect from unauthorized access
defined('_JEXEC') or die();

// JSON API version number
define('AKEEBA_JSON_API_VERSION', '320');

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Encrypt;

/*
 * Short API version history:
 * 300	First draft. Basic backup working. Encryption semi-broken.
 * 316	Fixed download feature.
 */

if (!defined('AKEEBA_BACKUP_ORIGIN'))
{
	define('AKEEBA_BACKUP_ORIGIN', 'json');
}

class AkeebaModelJsons extends F0FModel
{
	const    COM_AKEEBA_CPANEL_LBL_STATUS_OK               = 200; // Normal reply

	const    STATUS_NOT_AUTH         = 401; // Invalid credentials

	const    STATUS_NOT_ALLOWED      = 403; // Not enough privileges

	const    STATUS_NOT_FOUND        = 404; // Requested resource not found

	const    STATUS_INVALID_METHOD   = 405; // Unknown JSON method

	const    COM_AKEEBA_CPANEL_LBL_STATUS_ERROR            = 500; // An error occurred

	const    STATUS_NOT_IMPLEMENTED  = 501; // Not implemented feature

	const    STATUS_NOT_AVAILABLE    = 503; // Remote service not activated

	const    ENCAPSULATION_RAW       = 1; // Data in plain-text JSON

	const    ENCAPSULATION_AESCTR128 = 2; // Data in AES-128 stream (CTR) mode encrypted JSON

	const    ENCAPSULATION_AESCTR256 = 3; // Data in AES-256 stream (CTR) mode encrypted JSON

	const    ENCAPSULATION_AESCBC128 = 4; // Data in AES-128 standard (CBC) mode encrypted JSON

	const    ENCAPSULATION_AESCBC256 = 5; // Data in AES-256 standard (CBC) mode encrypted JSON

	/** @var int The status code */
	private $status = 200;

	/** @var int Data encapsulation format */
	private $encapsulation = 1;

	/** @var mixed Any data to be returned to the caller */
	private $data = '';

	/** @var string A password passed to us by the caller */
	private $password = null;

	/** @var string The method called by the client */
	private $method_name = null;

	public function execute($json)
	{
		// Check if we're activated
		$enabled = Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0);

		// Is the Secret Key strong enough?
		$validKey = $this->serverKey();

		if (!\Akeeba\Engine\Util\Complexify::isStrongEnough($validKey, false))
		{
			$enabled = false;
		}

		if (!$enabled)
		{
			$this->data          = 'Access denied';
			$this->status        = self::STATUS_NOT_AVAILABLE;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return $this->getResponse();
		}

		// Try to JSON-decode the request's input first
		$request = @json_decode($json, false);

		if (is_null($request))
		{
			// Could not decode JSON
			$this->data          = 'JSON decoding error';
			$this->status        = self::COM_AKEEBA_CPANEL_LBL_STATUS_ERROR;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return $this->getResponse();
		}

		// Decode the request body
		// Request format: {encapsulation, body{ [key], [challenge], method, [data] }} or {[challenge], method, [data]}
		if (isset($request->encapsulation) && isset($request->body))
		{
			if (!class_exists('\\Akeeba\\Engine\\Util\\Encrypt') && !($request->encapsulation == self::ENCAPSULATION_RAW))
			{
				// Encrypted request found, but there is no encryption class available!
				$this->data          = 'This server does not support encrypted requests';
				$this->status        = self::STATUS_NOT_AVAILABLE;
				$this->encapsulation = self::ENCAPSULATION_RAW;

				return $this->getResponse();
			}

			// Fully specified request
			$body = '';

			switch ($request->encapsulation)
			{
				case self::ENCAPSULATION_AESCBC128:
					if (!isset($body))
					{
						$request->body = base64_decode($request->body);
						$body          = Factory::getEncryption()
						                        ->AESDecryptCBC($request->body, $this->serverKey(), 128);
					}
					break;

				case self::ENCAPSULATION_AESCBC256:
					if (!isset($body))
					{
						$request->body = base64_decode($request->body);
						$body          = Factory::getEncryption()
						                        ->AESDecryptCBC($request->body, $this->serverKey(), 256);
					}
					break;

				case self::ENCAPSULATION_AESCTR128:
					if (!isset($body))
					{
						$body = Factory::getEncryption()->AESDecryptCtr($request->body, $this->serverKey(), 128);
					}
					break;

				case self::ENCAPSULATION_AESCTR256:
					if (!isset($body))
					{
						$body = Factory::getEncryption()->AESDecryptCtr($request->body, $this->serverKey(), 256);
					}
					break;

				case self::ENCAPSULATION_RAW:
					$body = $request->body;
					break;
			}

			if (!empty($request->body))
			{
				$authorised = true;
				$body       = rtrim($body, chr(0));

				// Make sure it looks like a valid JSON string and is at least 12 characters (minimum valid message length)
				if ((strlen($body) < 12) || (substr($body, 0, 1) != '{') || (substr($body, - 1) != '}'))
				{
					$authorised = false;
				}

				// Try to JSON decode the body
				if ($authorised)
				{
					$request->body = json_decode($body);

					if (is_null($request->body))
					{
						$authorised = false;
					}
					elseif (!is_object($request->body))
					{
						$authorised = false;
					}
				}

				// Make sure there is a requested method
				if ($authorised)
				{
					if (!isset($request->body->method) || empty($request->body->method))
					{
						$authorised = false;
					}
				}

				if (!$authorised)
				{
					// Decryption failed. The user is an impostor! Go away, hacker!
					$this->data          = 'Authentication failed';
					$this->status        = self::STATUS_NOT_AUTH;
					$this->encapsulation = self::ENCAPSULATION_RAW;

					return $this->getResponse();
				}
			}
		}
		elseif (isset($request->body))
		{
			// Partially specified request, assume RAW encapsulation
			$request->encapsulation = self::ENCAPSULATION_RAW;
			$request->body          = json_decode($request->body);
		}
		else
		{
			// Legacy request
			$legacyRequest = clone $request;
			$request       = (object) array('encapsulation' => self::ENCAPSULATION_RAW, 'body' => null);
			$request->body = json_decode($legacyRequest);
			unset($legacyRequest);
		}

		// Authenticate the user. Do note that if an encrypted request was made, we can safely assume that
		// the user is authenticated (he already knows the server key!)
		if ($request->encapsulation == self::ENCAPSULATION_RAW)
		{
			$authenticated = false;
			if (isset($request->body->challenge))
			{
				list($challenge, $check) = explode(':', $request->body->challenge);
				$crosscheck    = strtolower(md5($challenge . $this->serverKey()));
				$authenticated = ($crosscheck == $check);
			}
			if (!$authenticated)
			{
				// If the challenge was missing or it was wrong, don't let him go any further
				$this->data          = 'Invalid login credentials';
				$this->status        = self::STATUS_NOT_AUTH;
				$this->encapsulation = self::ENCAPSULATION_RAW;

				return $this->getResponse();
			}
		}

		// Replicate the encapsulation preferences of the client for our own output
		$this->encapsulation = $request->encapsulation;

		// Store the client-specified key, or use the server key if none specified and the request
		// came encrypted.
		$this->password = isset($request->body->key) ? $request->body->key : null;
		$hasKey         = (isset($request->body->key) || property_exists($request->body, 'key')) ? !is_null($request->body->key) : false;
		if (!$hasKey && ($request->encapsulation != self::ENCAPSULATION_RAW))
		{
			$this->password = $this->serverKey();
		}

		// Does the specified method exist?
		$method_exists = false;
		$method_name   = '';
		if (isset($request->body->method))
		{
			$method_name       = ucfirst($request->body->method);
			$this->method_name = $method_name;
			$method_exists     = method_exists($this, '_api' . $method_name);
		}
		if (!$method_exists)
		{
			// The requested method doesn't exist. Oops!
			$this->data          = "Invalid method $method_name";
			$this->status        = self::STATUS_INVALID_METHOD;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return $this->getResponse();
		}

		// Run the method
		$params = array();
		if (isset($request->body->data))
		{
			$params = (array) $request->body->data;
		}
		$this->data = call_user_func(array($this, '_api' . $method_name), $params);

		return $this->getResponse();
	}

	/**
	 * Packages the response to a JSON-encoded object, optionally encrypting the
	 * data part with a caller-supplied password.
	 *
	 * @return string The JSON-encoded response
	 */
	private function getResponse()
	{
		// Initialize the response
		$response = array(
			'encapsulation' => $this->encapsulation,
			'body'          => array(
				'status' => $this->status,
				'data'   => null
			)
		);

		$data = json_encode($this->data);

		if (empty($this->password))
		{
			$this->encapsulation = self::ENCAPSULATION_RAW;
		}

		switch ($this->encapsulation)
		{
			case self::ENCAPSULATION_RAW:
				break;

			case self::ENCAPSULATION_AESCTR128:
				$data = Factory::getEncryption()->AESEncryptCtr($data, $this->password, 128);
				break;

			case self::ENCAPSULATION_AESCTR256:
				$data = Factory::getEncryption()->AESEncryptCtr($data, $this->password, 256);
				break;

			case self::ENCAPSULATION_AESCBC128:
				$data = base64_encode(Factory::getEncryption()->AESEncryptCBC($data, $this->password, 128));
				break;

			case self::ENCAPSULATION_AESCBC256:
				$data = base64_encode(Factory::getEncryption()->AESEncryptCBC($data, $this->password, 256));
				break;
		}

		$response['body']['data'] = $data;

		return '###' . json_encode($response) . '###';
	}

	private function serverKey()
	{
		static $key = null;

		if (is_null($key))
		{
			$key = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');
		}

		return $key;
	}

	private function _apiGetVersion()
	{
		$edition = AKEEBA_PRO ? 'pro' : 'core';

		return (object) array(
			'api'       => AKEEBA_JSON_API_VERSION,
			'component' => AKEEBA_VERSION,
			'date'      => AKEEBA_DATE,
			'edition'   => $edition,
		);
	}

	private function _apiGetProfiles()
	{
		require_once JPATH_SITE . '/administrator/components/com_akeeba/models/profiles.php';
		$model    = new AkeebaModelProfiles();
		$profiles = $model->getProfilesList(true);
		$ret      = array();

		if (count($profiles))
		{
			foreach ($profiles as $profile)
			{
				$temp       = new stdClass();
				$temp->id   = $profile->id;
				$temp->name = $profile->description;
				$ret[]      = $temp;
			}
		}

		return $ret;
	}

	private function _apiStartBackup($config)
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile'     => 1,
			'description' => '',
			'comment'     => '',
			'backupid'    => null,
			'overrides'   => array(),
		);

		$defConfig = array_merge($defConfig, $config);

		$profile     = (int) $defConfig['profile'];
		$profile     = max(1, $profile); // Make sure $profile is a positive integer >= 1
		$description = $filter->clean($defConfig['description'], 'string');
		$comment     = $filter->clean($defConfig['comment'], 'string');
		$backupid    = $filter->clean($defConfig['backupid'], 'cmd');
		$backupid    = empty($backupid) ? null : $backupid; // Otherwise the Engine doesn't set a backup ID
		$overrides   = $filter->clean($defConfig['overrides'], 'array');

		$session = JFactory::getSession();
		$session->set('profile', $profile, 'akeeba');
		define('AKEEBA_PROFILE', $profile);

		/**
		 * DO NOT REMOVE!
		 *
		 * The Model will only try to load the configuration after nuking the factory. This causes Profile 1 to be
		 * loaded first. Then it figures out it needs to load a different profile and it does – but the protected keys
		 * are NOT replaced, meaning that certain configuration parameters are not replaced. Most notably, the chain.
		 * This causes backups to behave weirdly. So, DON'T REMOVE THIS UNLESS WE REFACTOR THE MODEL.
		 */
		Platform::getInstance()->load_configuration($profile);

		/** @var AkeebaModelBackups $model */
		$model = F0FModel::getTmpInstance('Backups', 'AkeebaModel');
		$model->setState('tag', AKEEBA_BACKUP_ORIGIN);
		$model->setState('backupid', $backupid);
		$model->setState('description', $description);
		$model->setState('comment', $comment);

		$array = $model->startBackup($overrides);

		if ($array['Error'] != '')
		{
			// A backup error had occurred. Why are we here?!
			$this->status        = self::COM_AKEEBA_CPANEL_LBL_STATUS_ERROR;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return 'A backup error has occurred: ' . $array['Error'];
		}

		$statistics        = Factory::getStatistics();
		$array['BackupID'] = $statistics->getId();

		// Remote clients expect a boolean, not an integer.
		$array['HasRun'] = ($array['HasRun'] === 0);

		return $array;
	}

	private function _apiStepBackup($config)
	{
		$filter = \JFilterInput::getInstance();

		$defConfig = array(
			'profile'  => null,
			'tag'      => AKEEBA_BACKUP_ORIGIN,
			'backupid' => null,
		);

		$defConfig = array_merge($defConfig, $config);

		$profile  = $filter->clean($defConfig['profile'], 'int');
		$tag      = $filter->clean($defConfig['tag'], 'cmd');
		$backupid = $filter->clean($defConfig['backupid'], 'cmd');

		$session = JFactory::getSession();

		// Try to set the profile from the setup parameters
		if (!empty($profile))
		{
			$session->set('profile', $profile);
			define('AKEEBA_PROFILE', $profile);
		}

		/** @var AkeebaModelBackups $model */
		$model = F0FModel::getTmpInstance('Backups', 'AkeebaModel');

		$model->setState('tag', $tag);
		$model->setState('backupid', $backupid);
		$array = $model->stepBackup(false);

		if ($array['Error'] != '')
		{
			// A backup error had occurred. Why are we here?!
			$this->status        = self::COM_AKEEBA_CPANEL_LBL_STATUS_ERROR;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return 'A backup error has occurred: ' . $array['Error'];
		}

		$statistics        = Factory::getStatistics();
		$array['BackupID'] = $statistics->getId();

		// Remote clients expect a boolean, not an integer.
		$array['HasRun'] = ($array['HasRun'] === 0);

		return $array;
	}

	private function _apiListBackups($config)
	{
		$defConfig = array(
			'from'  => 0,
			'limit' => 50
		);
		$config    = array_merge($defConfig, $config);

		$from  = $config['from'];
		$limit = $config['limit'];

		require_once JPATH_COMPONENT_ADMINISTRATOR . '/models/statistics.php';

		$model = new AkeebaModelStatistics();
		$model->setState('limitstart', $from);
		$model->setState('limit', $limit);

		return $model->getStatisticsListWithMeta(false);
	}

	private function _apiGetBackupInfo($config)
	{
		$defConfig = array(
			'backup_id' => '0'
		);

		$config = array_merge($defConfig, $config);

		$backup_id = $config['backup_id'];

		// Get the basic statistics
		$record = Platform::getInstance()->get_statistics($backup_id);

		// Get a list of filenames
		$backup_stats = Platform::getInstance()->get_statistics($backup_id);

		// Backup record doesn't exist
		if (empty($backup_stats))
		{
			$this->status        = self::STATUS_NOT_FOUND;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return 'Invalid backup record identifier';
		}

		$filenames = Factory::getStatistics()->get_all_filenames($record);

		if (empty($filenames))
		{
			// Archives are not stored on the server or no files produced
			$record['filenames'] = array();
		}
		else
		{
			$filedata = array();
			$i        = 0;

			// Get file sizes per part
			foreach ($filenames as $file)
			{
				$i ++;
				$size       = @filesize($file);
				$size       = is_numeric($size) ? $size : 0;
				$filedata[] = array(
					'part' => $i,
					'name' => basename($file),
					'size' => $size
				);
			}

			// Add the file info to $record['filenames']
			$record['filenames'] = $filedata;
		}

		return $record;
	}

	private function _apiDownload($config)
	{
		$defConfig = array(
			'backup_id'  => 0,
			'part_id'    => 1,
			'segment'    => 1,
			'chunk_size' => 1
		);
		$config    = array_merge($defConfig, $config);

		$backup_id  = $config['backup_id'];
		$part_id    = $config['part_id'];
		$segment    = $config['segment'];
		$chunk_size = $config['chunk_size'];

		$backup_stats = Platform::getInstance()->get_statistics($backup_id);
		if (empty($backup_stats))
		{
			// Backup record doesn't exist
			$this->status        = self::STATUS_NOT_FOUND;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return 'Invalid backup record identifier';
		}
		$files = Factory::getStatistics()->get_all_filenames($backup_stats);

		if ((count($files) < $part_id) || ($part_id <= 0))
		{
			// Invalid part
			$this->status        = self::STATUS_NOT_FOUND;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return 'Invalid backup part';
		}

		$file = $files[ $part_id - 1 ];

		$filesize = @filesize($file);
		$seekPos  = $chunk_size * 1048756 * ($segment - 1);

		if ($seekPos > $filesize)
		{
			// Trying to seek past end of file
			$this->status        = self::STATUS_NOT_FOUND;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return 'Invalid segment';
		}

		$fp = fopen($file, 'rb');

		if ($fp === false)
		{
			// Could not read file
			$this->status        = self::COM_AKEEBA_CPANEL_LBL_STATUS_ERROR;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return 'Error reading backup archive';
		}

		rewind($fp);
		if (fseek($fp, $seekPos, SEEK_SET) === - 1)
		{
			// Could not seek to position
			$this->status        = self::COM_AKEEBA_CPANEL_LBL_STATUS_ERROR;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return 'Error reading specified segment';
		}

		$buffer = fread($fp, 1048756);

		if ($buffer === false)
		{
			// Could not read
			$this->status        = self::COM_AKEEBA_CPANEL_LBL_STATUS_ERROR;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return 'Error reading specified segment';
		}

		fclose($fp);

		switch ($this->encapsulation)
		{
			case self::ENCAPSULATION_RAW:
				return base64_encode($buffer);
				break;

			case self::ENCAPSULATION_AESCTR128:
				$this->encapsulation = self::ENCAPSULATION_AESCBC128;

				return $buffer;
				break;

			case self::ENCAPSULATION_AESCTR256:
				$this->encapsulation = self::ENCAPSULATION_AESCBC256;

				return $buffer;
				break;

			default:
				// On encrypted comms the encryption will take care of transport encoding
				return $buffer;
				break;
		}
	}

	private function _apiDelete($config)
	{
		$defConfig = array(
			'backup_id' => 0
		);

		$config = array_merge($defConfig, $config);

		$backup_id = $config['backup_id'];

		require_once JPATH_COMPONENT_ADMINISTRATOR . '/models/statistics.php';

		$model = new AkeebaModelStatistics();
		$model->setState('id', (int) $backup_id);
		$result = $model->delete();
		if (!$result)
		{
			$this->status        = self::COM_AKEEBA_CPANEL_LBL_STATUS_ERROR;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return $model->getError();
		}
		else
		{
			return true;
		}
	}

	private function _apiDeleteFiles($config)
	{
		$defConfig = array(
			'backup_id' => 0
		);

		$config = array_merge($defConfig, $config);

		$backup_id = $config['backup_id'];

		require_once JPATH_COMPONENT_ADMINISTRATOR . '/models/statistics.php';

		$model = new AkeebaModelStatistics();
		$model->setState('id', (int) $backup_id);
		$result = $model->deleteFile();
		if (!$result)
		{
			$this->status        = self::COM_AKEEBA_CPANEL_LBL_STATUS_ERROR;
			$this->encapsulation = self::ENCAPSULATION_RAW;

			return $model->getError();
		}
		else
		{
			return true;
		}
	}

	private function _apiGetLog($config)
	{
		$defConfig = array(
			'tag' => 'remote'
		);

		$config = array_merge($defConfig, $config);

		$tag = $config['tag'];

		$filename = Factory::getLog()->getLogFilename($tag);
		$buffer   = file_get_contents($filename);

		switch ($this->encapsulation)
		{
			case self::ENCAPSULATION_RAW:
				return base64_encode($buffer);
				break;

			case self::ENCAPSULATION_AESCTR128:
				$this->encapsulation = self::ENCAPSULATION_AESCBC128;

				return $buffer;
				break;

			case self::ENCAPSULATION_AESCTR256:
				$this->encapsulation = self::ENCAPSULATION_AESCBC256;

				return $buffer;
				break;

			default:
				// On encrypted comms the encryption will take care of transport encoding
				return $buffer;
				break;
		}
	}

	private function _apiDownloadDirect($config)
	{
		$defConfig = array(
			'backup_id' => 0,
			'part_id'   => 1
		);

		$config = array_merge($defConfig, $config);

		$backup_id = $config['backup_id'];
		$part_id   = $config['part_id'];

		$backup_stats = Platform::getInstance()->get_statistics($backup_id);
		if (empty($backup_stats))
		{
			// Backup record doesn't exist
			$this->status        = self::STATUS_NOT_FOUND;
			$this->encapsulation = self::ENCAPSULATION_RAW;
			@ob_end_clean();
			header('HTTP/1.1 500 Invalid backup record identifier');
			flush();
			JFactory::getApplication()->close();
		}
		$files = Factory::getStatistics()->get_all_filenames($backup_stats);

		if ((count($files) < $part_id) || ($part_id <= 0))
		{
			// Invalid part
			$this->status        = self::STATUS_NOT_FOUND;
			$this->encapsulation = self::ENCAPSULATION_RAW;
			@ob_end_clean();
			header('HTTP/1.1 500 Invalid backup part');
			flush();
			JFactory::getApplication()->close();
		}

		$filename = $files[ $part_id - 1 ];
		@clearstatcache();

		// For a certain unmentionable browser -- Thank you, Nooku, for the tip
		if (function_exists('ini_get') && function_exists('ini_set'))
		{
			if (ini_get('zlib.output_compression'))
			{
				ini_set('zlib.output_compression', 'Off');
			}
		}

		// Remove php's time limit -- Thank you, Nooku, for the tip
		if (function_exists('ini_get') && function_exists('set_time_limit'))
		{
			if (!ini_get('safe_mode'))
			{
				@set_time_limit(0);
			}
		}

		$basename  = @basename($filename);
		$filesize  = @filesize($filename);
		$extension = strtolower(str_replace(".", "", strrchr($filename, ".")));

		while (@ob_end_clean())
		{
			;
		}
		@clearstatcache();
		// Send MIME headers
		header('MIME-Version: 1.0');
		header('Content-Disposition: attachment; filename="' . $basename . '"');
		header('Content-Transfer-Encoding: binary');
		header('Accept-Ranges: bytes');

		switch ($extension)
		{
			case 'zip':
				// ZIP MIME type
				header('Content-Type: application/zip');
				break;

			default:
				// Generic binary data MIME type
				header('Content-Type: application/octet-stream');
				break;
		}
		// Notify of filesize, if this info is available
		if ($filesize > 0)
		{
			header('Content-Length: ' . @filesize($filename));
		}
		// Disable caching
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Expires: 0");
		header('Pragma: no-cache');
		flush();
		if ($filesize > 0)
		{
			// If the filesize is reported, use 1M chunks for echoing the data to the browser
			$blocksize = 1048756; //1M chunks
			$handle    = @fopen($filename, "r");
			// Now we need to loop through the file and echo out chunks of file data
			if ($handle !== false)
			{
				while (!@feof($handle))
				{
					echo @fread($handle, $blocksize);
					@ob_flush();
					flush();
				}
			}
			if ($handle !== false)
			{
				@fclose($handle);
			}
		}
		else
		{
			// If the filesize is not reported, hope that readfile works
			@readfile($filename);
		}
		flush();
		JFactory::getApplication()->close();
	}
}index.html000060400000000066150752453440006550 0ustar00<html><head><title></title></head><body></body></html>akeeba.php000060400000001012150752453440006464 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

// Protect from unauthorized access
defined('_JEXEC') or die();

JDEBUG ? define('AKEEBADEBUG', 1) : null;

if (!defined('FOF30_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof30/include.php'))
{
	throw new RuntimeException('FOF 3.0 is not installed', 500);
}

FOF30\Container\Container::getInstance('com_akeeba')->dispatcher->dispatch();
controllers/backup.php000060400000013302150752453440011074 0ustar00<?php
/**
 * @package   AkeebaBackup
 * @copyright Copyright (c)2009-2016 Nicholas K. Dionysopoulos
 * @license   GNU General Public License version 2, or later
 *
 * @since     1.3
 */

// Protect from unauthorized access
defined('_JEXEC') or die();

defined('AKEEBA_BACKUP_ORIGIN') or define('AKEEBA_BACKUP_ORIGIN', 'frontend');

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

class AkeebaControllerBackup extends F0FController
{
	public function __construct($config = array())
	{
		$config['csrf_protection'] = false;

		parent::__construct($config);
	}

	public function execute($task)
	{
		if ($task != 'step')
		{
			$task = 'browse';
		}

		parent::execute($task);
	}

	public function browse()
	{
		// Check permissions
		$this->checkPermissions();
		// Set the profile
		$this->setProfile();

		// Get the backup ID
		$backupId = $this->input->get('backupid', null, 'cmd');

		if (empty($backupId))
		{
			$backupId = null;
		}

		/** @var AkeebaModelBackups $model */
		$model = F0FModel::getTmpInstance('Backups', 'AkeebaModel');

		JLoader::import('joomla.utilities.date');
		$dateNow = new JDate();

		$model->setState('tag', AKEEBA_BACKUP_ORIGIN);
		$model->setState('backupid', $backupId);
		$model->setState('description', JText::_('COM_AKEEBA_BACKUP_DEFAULT_DESCRIPTION') . ' ' . $dateNow->format(JText::_('DATE_FORMAT_LC2'), true));
		$model->setState('comment', '');

		$array = $model->startBackup();

		$backupId = $model->getState('backupid', null, 'cmd');

		$this->processEngineReturnArray($array, $backupId);
	}

	/**
	 * Step through a front-end legacy backup
	 *
	 * @return  void
	 */
	public function step()
	{
		// Setup
		$this->checkPermissions();
		$this->setProfile();

		// Get the backup ID
		$backupId = $this->input->get('backupid', null, 'cmd');

		if (empty($backupId))
		{
			$backupId = null;
		}

		/** @var AkeebaModelBackups $model */
		$model = F0FModel::getTmpInstance('Backups', 'AkeebaModel');

		$model->setState('tag', AKEEBA_BACKUP_ORIGIN);
		$model->setState('backupid', $backupId);

		$array = $model->stepBackup();

		$backupId = $model->getState('backupid', null, 'cmd');

		$this->processEngineReturnArray($array, $backupId);
	}

	/**
	 * Used by the tasks to process Akeeba Engine's return array. Depending on the result and the component options we
	 * may throw text output or send an HTTP redirection header.
	 *
	 * @param   array   $array     The return array to process
	 * @param   string  $backupId  The backup ID (used to step the backup process)
	 */
	private function processEngineReturnArray($array, $backupId)
	{
		if ($array['Error'] != '')
		{
			@ob_end_clean();
			echo '500 ERROR -- ' . $array['Error'];
			flush();

			JFactory::getApplication()->close();
		}

		if ($array['HasRun'] == 1)
		{
			// All done
			Factory::nuke();
			Factory::getFactoryStorage()->reset();
			@ob_end_clean();
			header('Content-type: text/plain');
			header('Connection: close');
			echo '200 OK';
			flush();

			JFactory::getApplication()->close();
		}

		$noredirect = $this->input->get('noredirect', 0, 'int');

		if ($noredirect != 0)
		{
			@ob_end_clean();
			header('Content-type: text/plain');
			header('Connection: close');
			echo "301 More work required -- BACKUPID ###$backupId###";
			flush();

			JFactory::getApplication()->close();
		}

		$curUri  = JUri::getInstance();
		$ssl     = $curUri->isSSL() ? 1 : 0;
		$tempURL = JRoute::_('index.php?option=com_akeeba', false, $ssl);
		$uri     = new JUri($tempURL);

		$uri->setVar('view', 'backup');
		$uri->setVar('task', 'step');
		$uri->setVar('key', $this->input->get('key', '', 'none', 2));
		$uri->setVar('profile', $this->input->get('profile', 1, 'int'));

		if (!empty($backupId))
		{
			$uri->setVar('backupid', $backupId);
		}

		// Maybe we have a multilingual site?
		/** @var JLanguage $language */
		$language    = F0FPlatform::getInstance()->getLanguage();
		$languageTag = $language->getTag();

		$uri->setVar('lang', $languageTag);

		$redirectionUrl = $uri->toString();

		$this->customRedirect($redirectionUrl);
	}

	/**
	 * Check that the user has sufficient permissions, or die in error
	 *
	 */
	private function checkPermissions()
	{
		// Is frontend backup enabled?
		$febEnabled = Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0) != 0;

		// Is the Secret Key strong enough?
		$validKey = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');

		if (!\Akeeba\Engine\Util\Complexify::isStrongEnough($validKey, false))
		{
			$febEnabled = false;
		}

		if (!$febEnabled)
		{
			@ob_end_clean();
			echo '403 ' . JText::_('COM_AKEEBA_COMMON_ERR_NOT_ENABLED');
			flush();
			JFactory::getApplication()->close();
		}

		// Is the key good?
		$key          = $this->input->get('key', '', 'none', 2);
		$validKeyTrim = trim($validKey);

		if (($key != $validKey) || (empty($validKeyTrim)))
		{
			@ob_end_clean();
			echo '403 ' . JText::_('ERROR_INVALID_KEY');
			flush();
			JFactory::getApplication()->close();
		}
	}

	private function setProfile()
	{
		// Set profile
		$profile = $this->input->get('profile', 1, 'int');

		if (!is_numeric($profile))
		{
			$profile = 1;
		}

		$session = JFactory::getSession();
		$session->set('profile', $profile, 'akeeba');

		Platform::getInstance()->load_configuration($profile);
	}

	private function customRedirect($url, $header = '302 Found')
	{
		header('HTTP/1.1 ' . $header);
		header('Location: ' . $url);
		header('Content-Type: text/plain');
		header('Connection: close');

		JFactory::getApplication()->close(0);
	}
}controllers/json.php000060400000002671150752453440010607 0ustar00<?php
/**
 * @package AkeebaBackup
 * @copyright Copyright (c)2009-2016 Nicholas K. Dionysopoulos
 * @license GNU General Public License version 2, or later
 *
 * @since 1.3
 */

// Protect from unauthorized access
defined('_JEXEC') or die();

defined('AKEEBA_BACKUP_ORIGIN') or define('AKEEBA_BACKUP_ORIGIN','json');

class AkeebaControllerJson extends F0FController
{
	public function __construct($config = array()) {
		$config['csrf_protection'] = false;
		parent::__construct($config);
	}
	public function execute($task)
	{
		$task = 'json';

		parent::execute($task);
	}

	/**
	 * Handles API calls
	 */
	public function json()
	{
		// Use the model to parse the JSON message
		if(function_exists('ob_start')) @ob_start();
		$sourceJSON = $this->input->get('json', null, 'raw', 2);

		// On some !@#$%^& servers where magic_quotes_gpc is On we might get extra slashes added
		if(function_exists('get_magic_quotes_gpc')) {
			if(get_magic_quotes_gpc()) {
				$sourceJSON = stripslashes($sourceJSON);
			}
		}

		/** @var AkeebaModelJsons $model */
		$model = $this->getThisModel();
		$json = $model->execute($sourceJSON);
		if(function_exists('ob_end_clean')) @ob_end_clean();

		// Just dump the JSON and tear down the application, without plugins executing
		header('Content-type: text/plain');
		header('Connection: close');
		echo $json;
		$app = JFactory::getApplication();
		$app->close();
	}

}

controllers/check.php000060400000004405150752453440010710 0ustar00<?php
/**
 * @package AkeebaBackup
 * @copyright Copyright (c)2009-2016 Nicholas K. Dionysopoulos
 * @license GNU General Public License version 2, or later
 *
 */

// Protect from unauthorized access
defined('_JEXEC') or die();

defined('AKEEBA_BACKUP_ORIGIN') or define('AKEEBA_BACKUP_ORIGIN','frontend');

use Akeeba\Engine\Platform;

class AkeebaControllerCheck extends F0FController
{
	public function __construct($config = array())
    {
		$config['csrf_protection'] = false;

		parent::__construct($config);
	}

	public function execute($task)
    {
        // The only allowed task is the browse one
		$task = 'browse';
		parent::execute($task);
	}

	public function browse()
	{
		// Check permissions
		$this->_checkPermissions();

        /** @var AkeebaModelStatistics $model */
        $model = F0FModel::getTmpInstance('Statistics', 'AkeebaModel');
        $model->setInput($this->input);

        $result = $model->notifyFailed();

        $message  = $result['result'] ? '200 ' : '500 ';
        $message .= implode(', ', $result['message']);

        @ob_end_clean();
		header('Content-type: text/plain');
		header('Connection: close');
        echo $message;
        flush();
        JFactory::getApplication()->close();
	}


	/**
	 * Check that the user has sufficient permissions, or die in error
	 *
	 */
	private function _checkPermissions()
	{
		// Is frontend backup enabled?
		$febEnabled = Platform::getInstance()->get_platform_configuration_option('failure_frontend_enable', 0) != 0;

		// Is the Secret Key strong enough?
		$validKey = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');

		if (!\Akeeba\Engine\Util\Complexify::isStrongEnough($validKey, false))
		{
			$febEnabled = false;
		}

		if (!$febEnabled)
		{
			@ob_end_clean();
			echo '403 ' . JText::_('COM_AKEEBA_COMMON_ERR_NOT_ENABLED');
			flush();
			JFactory::getApplication()->close();
		}

		// Is the key good?
		$key = $this->input->get('key', '', 'none', 2);

		$validKeyTrim = trim($validKey);

		if (($key != $validKey) || (empty($validKeyTrim)))
		{
			@ob_end_clean();
			echo '403 ' . JText::_('ERROR_INVALID_KEY');
			flush();
			JFactory::getApplication()->close();
		}
	}
}Controller/Mixin/FrontEndPermissions.php000060400000002536150752453440014452 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller\Mixin;

// Protect from unauthorized access
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Complexify;
use JText;

defined('_JEXEC') or die();

/**
 * Provides the method to check whether front-end backup is enabled and weather the key is correct
 */
trait FrontEndPermissions
{
	/**
	 * Check that the user has sufficient permissions to access the front-end backup feature.
	 *
	 * @return  void
	 */
	protected function checkPermissions()
	{
		// Is frontend backup enabled?
		$febEnabled = Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0) != 0;

		// Is the Secret Key strong enough?
		$validKey     = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');
		$validKeyTrim = trim($validKey);

		if (!Complexify::isStrongEnough($validKey, false))
		{
			$febEnabled = false;
		}

		// Is the key good?
		$key = $this->input->get('key', '', 'none', 2);

		if (!$febEnabled || ($key != $validKey) || (empty($validKeyTrim)))
		{
			@ob_end_clean();
			echo '403 ' . JText::_('COM_AKEEBA_COMMON_ERR_NOT_ENABLED');
			flush();

			$this->container->platform->closeApplication();
		}
	}

}
Controller/Mixin/CustomRedirection.php000060400000001531150752453440014133 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller\Mixin;

// Protect from unauthorized access
use Akeeba\Engine\Platform;

defined('_JEXEC') or die();

/**
 * Provides the method to send custom HTTP redirection headers
 */
trait CustomRedirection
{
	/**
	 * Sends custom HTTP redirection headers
	 *
	 * @param   string  $url     The URL to redirect to
	 * @param   string  $header  The HTTP header to send, default 302 Found
	 */
	protected function customRedirect($url, $header = '302 Found')
	{
		header('HTTP/1.1 ' . $header);
		header('Location: ' . $url);
		header('Content-Type: text/plain');
		header('Connection: close');

		$this->container->platform->closeApplication();
	}

}
Controller/Mixin/ActivateProfile.php000060400000002316150752453440013554 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller\Mixin;

// Protect from unauthorized access
use Akeeba\Engine\Platform;

defined('_JEXEC') or die();

/**
 * Provides the method to set the current backup profile from the request variables
 */
trait ActivateProfile
{
	/**
	 * Set the active profile from the input parameters
	 */
	protected function setProfile()
	{
		$profile = $this->input->get('profile', 1, 'int');
		$profile = max(1, $profile);

		$this->container->platform->setSessionVar('profile', $profile, 'akeeba');

		/**
		 * DO NOT REMOVE!
		 *
		 * The Model will only try to load the configuration after nuking the factory. This causes Profile 1 to be
		 * loaded first. Then it figures out it needs to load a different profile and it does – but the protected keys
		 * are NOT replaced, meaning that certain configuration parameters are not replaced. Most notably, the chain.
		 * This causes backups to behave weirdly. So, DON'T REMOVE THIS UNLESS WE REFACTOR THE MODEL.
		 */
		Platform::getInstance()->load_configuration($profile);
	}

}
Controller/Check.php000060400000003022150752453440010417 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Controller\Mixin\PredefinedTaskList;
use Akeeba\Backup\Site\Controller\Mixin\FrontEndPermissions;
use Akeeba\Backup\Site\Model\Statistics;
use FOF30\Container\Container;
use FOF30\Controller\Controller;

/**
 * Controller for the front-end Check Backups features
 */
class Check extends Controller
{
	use PredefinedTaskList, FrontEndPermissions;

	/**
	 * Overridden constructor
	 *
	 * @param   Container  $container  The application container
	 * @param   array      $config     The configuration array
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->setPredefinedTaskList(['main']);
	}

	/**
	 * Checks for failed backups and sends out any notification emails
	 */
	public function main()
	{
		// Check permissions
		$this->checkPermissions();

		/** @var Statistics $model */
		$model  = $this->container->factory->model('Statistics')->tmpInstance();
		$result = $model->notifyFailed();

		$message = $result['result'] ? '200 ' : '500 ';
		$message .= implode(', ', $result['message']);

		@ob_end_clean();
		header('Content-type: text/plain');
		header('Connection: close');
		echo $message;
		flush();

		$this->container->platform->closeApplication();
	}
}
Controller/Json.php000060400000002675150752453440010330 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Controller\Mixin\PredefinedTaskList;
use FOF30\Container\Container;
use FOF30\Controller\Controller;

/**
 * Controller for the JSON API
 */
class Json extends Controller
{
	use PredefinedTaskList;

	/**
	 * Overridden constructor
	 *
	 * @param   Container  $container  The application container
	 * @param   array      $config     The configuration array
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->setPredefinedTaskList(['json']);
	}

	/**
	 * Handles API calls
	 */
	public function json()
	{
		// Use the model to parse the JSON message
		if (function_exists('ob_start'))
		{
			@ob_start();
		}

		$sourceJSON = $this->input->get('json', null, 'raw', 2);

		/** @var \Akeeba\Backup\Site\Model\Json $model */
		$model = $this->getModel();
		$json  = $model->execute($sourceJSON);

		if (function_exists('ob_end_clean'))
		{
			@ob_end_clean();
		}

		// Just dump the JSON and tear down the application, without plugins executing
		header('Content-type: text/plain');
		header('Connection: close');
		echo $json;

		$this->container->platform->closeApplication();
	}

}
Controller/index.html000060400000000066150752453440010673 0ustar00<html><head><title></title></head><body></body></html>Controller/web.config000060400000001025150752453440010636 0ustar00<?xml version="1.0"?>
<!--
    This only works on IIS 7 or later. See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions
-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>Controller/Backup.php000060400000012126150752453440010614 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Controller;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Controller\Mixin\PredefinedTaskList;
use Akeeba\Backup\Site\Controller\Mixin\ActivateProfile;
use Akeeba\Backup\Site\Controller\Mixin\CustomRedirection;
use Akeeba\Backup\Site\Controller\Mixin\FrontEndPermissions;
use Akeeba\Engine\Factory;
use FOF30\Container\Container;
use FOF30\Controller\Controller;
use FOF30\Date\Date;
use JLoader;
use JRoute;
use JText;
use JUri;

if (!defined('AKEEBA_BACKUP_ORIGIN'))
{
	define('AKEEBA_BACKUP_ORIGIN', 'frontend');
}

/**
 * Controller for the front-end backup feature.
 *
 * The Traits used by this class offer most of the features you don't see, especially those pertaining to security:
 * PredefinedTaskList   Only allows certain tasks to be called.
 * FrontEndPermissions  Validates the secret word before running a task through checkPermissions.
 * ActivateProfile      Finds the profile specified in the URL and loads it through setProfile.
 * CustomRedirection    Provides customRedirect for HTTP redirects without dealing with CMS inconsistencies.
 */
class Backup extends Controller
{
	use PredefinedTaskList, FrontEndPermissions, ActivateProfile, CustomRedirection;

	/**
	 * Overridden constructor
	 *
	 * @param   Container  $container  The application container
	 * @param   array      $config     The configuration array
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->setPredefinedTaskList(['main', 'step']);
	}

	/**
	 * Start a front-end legacy backup
	 *
	 * @return  void
	 */
	public function main()
	{
		$this->checkPermissions();
		$this->setProfile();

		// Get the backup ID
		$backupId = $this->input->get('backupid', null, 'cmd');

		if (empty($backupId))
		{
			$backupId = null;
		}

		/** @var \Akeeba\Backup\Site\Model\Backup $model */
		$model = $this->container->factory->model('Backup')->tmpInstance();

		JLoader::import('joomla.utilities.date');
		$dateNow = new Date();

		$model->setState('tag', AKEEBA_BACKUP_ORIGIN);
		$model->setState('backupid', $backupId);
		$model->setState('description', JText::_('COM_AKEEBA_BACKUP_DEFAULT_DESCRIPTION') . ' ' . $dateNow->format(JText::_('DATE_FORMAT_LC2'), true));
		$model->setState('comment', '');

		$array = $model->startBackup();

		$backupId = $model->getState('backupid', null, 'cmd');

		$this->processEngineReturnArray($array, $backupId);
	}

	/**
	 * Step through a front-end legacy backup
	 *
	 * @return  void
	 */
	public function step()
	{
		// Setup
		$this->checkPermissions();
		$this->setProfile();

		// Get the backup ID
		$backupId = $this->input->get('backupid', null, 'cmd');

		if (empty($backupId))
		{
			$backupId = null;
		}

		/** @var \Akeeba\Backup\Site\Model\Backup $model */
		$model = $this->container->factory->model('Backup')->tmpInstance();

		$model->setState('tag', AKEEBA_BACKUP_ORIGIN);
		$model->setState('backupid', $backupId);

		$array = $model->stepBackup();

		$backupId = $model->getState('backupid', null, 'cmd');

		$this->processEngineReturnArray($array, $backupId);
	}

	/**
	 * Used by the tasks to process Akeeba Engine's return array. Depending on the result and the component options we
	 * may throw text output or send an HTTP redirection header.
	 *
	 * @param   array   $array     The return array to process
	 * @param   string  $backupId  The backup ID (used to step the backup process)
	 */
	private function processEngineReturnArray($array, $backupId)
	{
		if ($array['Error'] != '')
		{
			@ob_end_clean();
			echo '500 ERROR -- ' . $array['Error'];
			flush();

			$this->container->platform->closeApplication();
		}

		if ($array['HasRun'] == 1)
		{
			// All done
			Factory::nuke();
			Factory::getFactoryStorage()->reset();
			@ob_end_clean();
			header('Content-type: text/plain');
			header('Connection: close');
			echo '200 OK';
			flush();

			$this->container->platform->closeApplication();
		}

		$noredirect = $this->input->get('noredirect', 0, 'int');

		if ($noredirect != 0)
		{
			@ob_end_clean();
			header('Content-type: text/plain');
			header('Connection: close');
			echo "301 More work required -- BACKUPID ###$backupId###";
			flush();

			$this->container->platform->closeApplication();
		}

		$curUri  = JUri::getInstance();
		$ssl     = $curUri->isSSL() ? 1 : 0;
		$tempURL = JRoute::_('index.php?option=com_akeeba', false, $ssl);
		$uri     = new JUri($tempURL);

		$uri->setVar('view', 'Backup');
		$uri->setVar('task', 'step');
		$uri->setVar('key', $this->input->get('key', '', 'none', 2));
		$uri->setVar('profile', $this->input->get('profile', 1, 'int'));

		if (!empty($backupId))
		{
			$uri->setVar('backupid', $backupId);
		}

		// Maybe we have a multilingual site?
		$language    = $this->container->platform->getLanguage();
		$languageTag = $language->getTag();

		$uri->setVar('lang', $languageTag);

		$redirectionUrl = $uri->toString();

		$this->customRedirect($redirectionUrl);
	}
}
Controller/.htaccess000060400000000246150752453440010474 0ustar00<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
<IfModule mod_authz_core.c>
  <RequireAll>
    Require all denied
  </RequireAll>
</IfModule>
Dispatcher/Dispatcher.php000060400000007202150752453440011437 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Dispatcher;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Dispatcher\Dispatcher as AdminDispatcher;
use Akeeba\Backup\Admin\Helper\SecretWord;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
use FOF30\Container\Container;
use FOF30\Dispatcher\Mixin\ViewAliases;
use JFactory;

class Dispatcher extends AdminDispatcher
{
	/** @var   string  The name of the default view, in case none is specified */
	public $defaultView = 'Backup';

	/**
	 * Dispatcher constructor. Overridden to set up a different default view and migrated views map than the back-end.
	 *
	 * @param   Container  $container  The component's container
	 * @param   array      $config     Optional configuration overrides
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->defaultView = 'Backup';

		$this->viewNameAliases = [
			'backup'  => 'Backup',
			'backups' => 'Backup',
			'check'   => 'Check',
			'checks'  => 'Check',
			'json'    => 'Json',
			'jsons'   => 'Json',
		];
	}


	/**
	 * Executes before dispatching the request to the appropriate controller
	 */
	public function onBeforeDispatch()
	{
		$this->onBeforeDispatchViewAliases();

		// Load the FOF language
		$lang = $this->container->platform->getLanguage();
		$lang->load('lib_fof30', JPATH_SITE, 'en-GB', true, true);
		$lang->load('lib_fof30', JPATH_SITE, null, true, false);

		// Necessary defines for Akeeba Engine
		if ( !defined('AKEEBAENGINE'))
		{
			define('AKEEBAENGINE', 1);
			define('AKEEBAROOT', $this->container->backEndPath . '/BackupEngine');
			define('ALICEROOT', $this->container->backEndPath . '/AliceEngine');
		}

		// Make sure we have a profile set throughout the component's lifetime
		$profile_id = $this->container->platform->getSessionVar('profile', null, 'akeeba');

		if (is_null($profile_id))
		{
			$this->container->platform->setSessionVar('profile', 1, 'akeeba');
		}

		// Load Akeeba Engine
		$basePath = $this->container->backEndPath;
		require_once $basePath . '/BackupEngine/Factory.php';

		// Load the Akeeba Engine configuration
		Platform::addPlatform('joomla3x', JPATH_COMPONENT_ADMINISTRATOR . '/BackupPlatform/Joomla3x');
		$akeebaEngineConfig = Factory::getConfiguration();
		Platform::getInstance()->load_configuration();
		unset($akeebaEngineConfig);

		// Prevents the "SQLSTATE[HY000]: General error: 2014" due to resource sharing with Akeeba Engine
		// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// !!!!! WARNING: ALWAYS GO THROUGH JFactory; DO NOT GO THROUGH $this->container->db !!!!!
		// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		$jDbo = JFactory::getDbo();

		if ($jDbo->name == 'pdomysql')
		{
			@JFactory::getDbo()->disconnect();
		}

		// Load the utils helper library
		Platform::getInstance()->load_version_defines();

		// Make sure the front-end backup Secret Word is stored encrypted
		$params = $this->container->params;
		SecretWord::enforceEncryption($params, 'frontend_secret_word');

		// Make sure we have a version loaded
		@include_once($this->container->backEndPath . '/version.php');

		if (!defined('AKEEBA_VERSION'))
		{
			define('AKEEBA_VERSION', 'dev');
			define('AKEEBA_DATE', date('Y-m-d'));
		}

		// Create a media file versioning tag
		$this->container->mediaVersion = md5(AKEEBA_VERSION . AKEEBA_DATE);
	}
}
Dispatcher/web.config000060400000001025150752453440010601 0ustar00<?xml version="1.0"?>
<!--
    This only works on IIS 7 or later. See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions
-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>Dispatcher/.htaccess000060400000000246150752453440010437 0ustar00<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
<IfModule mod_authz_core.c>
  <RequireAll>
    Require all denied
  </RequireAll>
</IfModule>
Model/RegExDatabaseFilters.php000060400000000616150752453440012315 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\RegExDatabaseFilters as AdminModel;

class RegExDatabaseFilters extends AdminModel
{
}
Model/Updates.php000060400000000564150752453440007734 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\Updates as AdminModel;

class Updates extends AdminModel
{
}
Model/FileFilters.php000060400000000574150752453440010540 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\FileFilters as AdminModel;

class FileFilters extends AdminModel
{
}
Model/.htaccess000060400000000246150752453440007411 0ustar00<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
<IfModule mod_authz_core.c>
  <RequireAll>
    Require all denied
  </RequireAll>
</IfModule>
Model/MultipleDatabases.php000060400000000610150752453440011722 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\MultipleDatabases as AdminModel;

class MultipleDatabases extends AdminModel
{
}
Model/Json/EncapsulationInterface.php000060400000006212150752453440013662 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json;

// Protect from unauthorized access
defined('_JEXEC') or die();

/**
 * Interface for Encapsulation data handlers
 */
interface EncapsulationInterface
{
	/**
	 * Is the provided encapsulation type supported by this class?
	 *
	 * @param   int  $encapsulation  Encapsulation type
	 *
	 * @return  bool  True if supported
	 */
	public function isSupported($encapsulation);

	/**
	 * Returns information about the encapsulation supported by this class. The return array has the following keys:
	 * id: The numeric ID of the encapsulation, e.g. 3
	 * code: The short code of the encapsulation, e.g. ENCAPSULATION_AESCTR256
	 * description: A human readable descriptions, e.g. "Data in AES-256 stream (CTR) mode encrypted JSON"
	 *
	 * @return  array  See above
	 */
	public function getInformation();

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it but *NOT* JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to decode data
	 * @param   string  $data       Encoded data
	 *
	 * @return  string  The decoded data.
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02.html
	 */
	public function decode($serverKey, $data);

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to encode data
	 * @param   mixed   $data       The data to encode, typically a string, array or object
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($serverKey, $data);

	/**
	 * Checks if the request body authorises the user to use the API. Each encapsulation can implement its own
	 * authorisation method. This method is only called after the request body has been successfully decoded, therefore
	 * encrypted encapsulations can simply return true.
	 *
	 * @param   string  $serverKey  The server key we need to check the authorisation
	 * @param   array   $body       The decoded body (as returned by the decode() method)
	 *
	 * @return  bool  True if authorised
	 */
	public function isAuthorised($serverKey, $body);
}
Model/Json/TaskInterface.php000060400000001674150752453440011766 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json;

// Protect from unauthorized access
defined('_JEXEC') or die();

use FOF30\Container\Container;

/**
 * Interface for JSON API tasks
 */
interface TaskInterface
{
	/**
	 * Public constructor
	 *
	 * @param   Container  $container  The container of the component we belong to
	 */
	public function __construct(Container $container);

	/**
	 * Return the JSON API task's name ("method" name). Remote clients will use it to call us.
	 *
	 * @return  string
	 */
	public function getMethodName();

	/**
	 * Execute the JSON API task
	 *
	 * @param   array  $parameters  The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array());
}
Model/Json/Task.php000060400000004760150752453440010144 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json;

// Protect from unauthorized access
defined('_JEXEC') or die();

use FOF30\Container\Container;

/**
 * Handles task execution
 */
class Task
{
	/**
	 * The component's container
	 *
	 * @var Container
	 */
	protected $container = null;

	/** @var  TaskInterface[]  The task handlers known to us */
	protected $handlers = array();

	/**
	 * Public constructor. Populates the list of task handlers.
	 */
	public function __construct(Container $container)
	{
		$this->container = $container;

		// Populate the list of task handlers
		$this->initialiseHandlers();
	}

	/**
	 * Do I have a specific task handling method?
	 *
	 * @param   string  $method  The method to check for
	 *
	 * @return  bool
	 */
	public function hasMethod($method)
	{
		$method = strtolower($method);

		return isset($this->handlers[$method]);
	}

	/**
	 * Execute a JSON API method
	 *
	 * @param   string  $method      The method's name
	 * @param   array   $parameters  The parameters to the method (optional)
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  When the method requested is not known to us
	 */
	public function execute($method, $parameters = array())
	{
		if (!$this->hasMethod($method))
		{
			throw new \RuntimeException("Invalid method $method", 405);
		}

		$method = strtolower($method);

		return $this->handlers[$method]->execute($parameters);
	}

	/**
	 * Initialises the encapsulation handlers
	 *
	 * @return  void
	 */
	protected function initialiseHandlers()
	{
		// Reset the array
		$this->handlers = array();

		// Look all files in the Task handlers' directory
		$dh = new \DirectoryIterator(__DIR__ . '/Task');

		/** @var \DirectoryIterator $entry */
		foreach ($dh as $entry)
		{
			$fileName = $entry->getFilename();

			// Ignore non-PHP files
			if (substr($fileName, -4) != '.php')
			{
				continue;
			}

			// Ignore the Base class
			if ($fileName == 'AbstractTask.php')
			{
				continue;
			}

			// Get the class name
			$className = '\\Akeeba\\Backup\\Site\\Model\\Json\\Task\\' . substr($fileName, 0, -4);

			// Check if the class really exists
			if (!class_exists($className, true))
			{
				continue;
			}

			/** @var TaskInterface $o */
			$o = new $className($this->container);
			$name = $o->getMethodName();
			$name = strtolower($name);
			$this->handlers[$name] = $o;
		}
	}

}
Model/Json/Task/DeleteFiles.php000060400000002234150752453440012323 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Statistics;
use Akeeba\Engine\Platform;

/**
 * Delete the backup archives of a backup record
 */
class DeleteFiles extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id = (int)$defConfig['backup_id'];

		/** @var Statistics $model */
		$model = $this->container->factory->model('Statistics')->tmpInstance();
		$model->setState('id', $backup_id);

		try
		{
			$model->deleteFile();
		}
		catch (\Exception $e)
		{
			throw new \RuntimeException($e->getMessage(), 500);
		}

		return true;
	}
}
Model/Json/Task/SaveProfile.php000060400000003606150752453440012361 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Profiles;
use Akeeba\Engine\Platform;

/**
 * Saves a backup profile
 */
class SaveProfile extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile'     => 0,
			'description' => null,
			'quickicon'   => null,
			'source'      => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile     = (int)$defConfig['profile'];
		$description = $defConfig['description'];
		$quickicon   = $defConfig['quickicon'];
		$source      = (int)$defConfig['source'];

		if ($profile <= 0)
		{
			$profile = null;
		}

		// At least one of these parameters is required
		if (empty($profile) && empty($source) && empty($description))
		{
			throw new \RuntimeException('Invalid profile ID', 404);
		}

		// Get a profile model
		/** @var Profiles $profileModel */
		$profileModel = $this->container->factory->model('Profiles')->tmpInstance();

		// Load the profile
		$sourceId = empty($profile) ? $source : $profile;

		if (!empty($sourceId))
		{
			$profileModel->findOrFail($sourceId);
		}
		else
		{
			$profileModel->reset(true);
		}

		$profileModel->setFieldValue('id', $profile);

		if ($description)
		{
			$profileModel->setFieldValue('description', $description);
		}

		if (!is_null($quickicon))
		{
			$profileModel->setFieldValue('quickicon', (int)$quickicon);
		}

		$profileModel->save();

		return true;
	}
}
Model/Json/Task/GetIncludedDBs.php000060400000002363150752453440012721 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\MultipleDatabases;
use Akeeba\Engine\Platform;

/**
 * Get the extra included databases
 */
class GetIncludedDBs extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = (int)$defConfig['profile'];

		if ($profile <= 0)
		{
			$profile = 1;
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var MultipleDatabases $model */
		$model = $this->container->factory->model('MultipleDatabases')->tmpInstance();

		return $model->get_databases();
	}
}
Model/Json/Task/TestDBConnection.php000060400000002614150752453440013305 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\MultipleDatabases;
use Akeeba\Engine\Platform;

/**
 * Test an extra database definition
 */
class TestDBConnection extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'connection' => array(),
		);

		$defConfig = array_merge($defConfig, $parameters);

		$connection = $filter->clean($defConfig['connection'], 'array');

		if (
			empty($connection) || !isset($connection['host']) || !isset($connection['driver'])
			|| !isset($connection['database']) || !isset($connection['user'])
			|| !isset($connection['password'])
		)
		{
			throw new \RuntimeException('Connection information missing or incomplete', 500);
		}

		/** @var MultipleDatabases $model */
		$model = $this->container->factory->model('MultipleDatabases')->tmpInstance();

		return $model->test($connection);
	}
}
Model/Json/Task/GetVersion.php000060400000002300150752453440012215 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Updates;

/**
 * Get the version information of Akeeba Backup
 */
class GetVersion extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		/** @var Updates $model */
		$model = $this->container->factory->model('Updates')->tmpInstance();

		$updateInformation = $model->getUpdates();

		if (is_array($updateInformation) && array_key_exists('releasenotes', $updateInformation))
		{
			unset ($updateInformation['releasenotes']);
		}

		$edition = AKEEBA_PRO ? 'pro' : 'core';

		return (object)array(
			'api'        => AKEEBA_JSON_API_VERSION,
			'component'  => AKEEBA_VERSION,
			'date'       => AKEEBA_DATE,
			'edition'    => $edition,
			'updateinfo' => $updateInformation,
		);
	}
}
Model/Json/Task/SetRegexFSFilter.php000060400000004161150752453440013264 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\RegExFileFilters;
use Akeeba\Engine\Platform;

/**
 * Set or unset a Regex filesystem filter
 */
class SetRegexFSFilter extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'root'    => '[SITEDB]',
			'regex'   => '',
			'type'    => 'directories',
			'status'  => 1
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = $filter->clean($defConfig['profile'], 'int');
		$root    = $filter->clean($defConfig['root'], 'string');
		$regex   = $filter->clean($defConfig['regex'], 'string');
		$type    = $filter->clean($defConfig['type'], 'cmd');
		$status  = $filter->clean($defConfig['status'], 'bool');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown database root', 500);
		}

		// We need a regex name
		if (empty($regex))
		{
			throw new \RuntimeException('Regex is mandatory', 500);
		}

		// We need a regex name
		if (empty($type))
		{
			throw new \RuntimeException('Filter type is mandatory', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var RegExFileFilters $model */
		$model = $this->container->factory->model('RegExFileFilters')->tmpInstance();

		if ($status)
		{
			$ret = $model->setFilter($type, $root, $regex);
		}
		else
		{
			$ret = $model->remove($type, $root, $regex);
		}

		return $ret;
	}
}
Model/Json/Task/UpdateGetInformation.php000060400000002137150752453440014230 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Updates;
use Akeeba\Engine\Platform;

/**
 * Get the update information
 */
class UpdateGetInformation extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'force' => 0
		);

		$defConfig = array_merge($defConfig, $parameters);

		$force = $filter->clean($defConfig['force'], 'bool');

		/** @var Updates $model */
		$model = $this->container->factory->model('Updates')->tmpInstance();

		$updateInformation = $model->getUpdates($force);

		return (object)$updateInformation;
	}
}
Model/Json/Task/RemoveIncludedDB.php000060400000003061150752453440013250 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\MultipleDatabases;
use Akeeba\Engine\Platform;

/**
 * Remove an extra database definition
 */
class RemoveIncludedDB extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile'       => 0,
			'name'          => '',
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile       = $filter->clean($defConfig['profile'], 'int');
		$name          = $filter->clean($defConfig['name'], 'string');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a uuid
		if (empty($name))
		{
			throw new \RuntimeException('The database name is required', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var MultipleDatabases $model */
		$model = $this->container->factory->model('MultipleDatabases')->tmpInstance();

		return $model->remove($name);
	}
}
Model/Json/Task/StartBackup.php000060400000005513150752453440012364 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Start a backup job
 */
class StartBackup extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile'     => 1,
			'description' => '',
			'comment'     => '',
			'backupid'    => null,
			'overrides'   => array(),
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile     = (int) $defConfig['profile'];
		$profile     = max(1, $profile); // Make sure $profile is a positive integer >= 1
		$description = $filter->clean($defConfig['description'], 'string');
		$comment     = $filter->clean($defConfig['comment'], 'string');
		$backupid    = $filter->clean($defConfig['backupid'], 'cmd');
		$backupid    = empty($backupid) ? null : $backupid; // Otherwise the Engine doesn't set a backup ID
		$overrides   = $filter->clean($defConfig['overrides'], 'array');

		$this->container->platform->setSessionVar('profile', $profile);
		define('AKEEBA_PROFILE', $profile);

		/**
		 * DO NOT REMOVE!
		 *
		 * The Model will only try to load the configuration after nuking the factory. This causes Profile 1 to be
		 * loaded first. Then it figures out it needs to load a different profile and it does – but the protected keys
		 * are NOT replaced, meaning that certain configuration parameters are not replaced. Most notably, the chain.
		 * This causes backups to behave weirdly. So, DON'T REMOVE THIS UNLESS WE REFACTOR THE MODEL.
		 */
		Platform::getInstance()->load_configuration($profile);

		/** @var \Akeeba\Backup\Site\Model\Backup $model */
		$model = $this->container->factory->model('Backup')->tmpInstance();
		$model->setState('tag', AKEEBA_BACKUP_ORIGIN);
		$model->setState('backupid', $backupid);
		$model->setState('description', $description);
		$model->setState('comment', $comment);

		$array = $model->startBackup($overrides);

		if ($array['Error'] != '')
		{
			throw new \RuntimeException('A backup error has occurred: ' . $array['Error'], 500);
		}

		// BackupID contains the numeric backup record ID. backupid contains the backup id (usually in the form id123)
		$statistics        = Factory::getStatistics();
		$array['BackupID'] = $statistics->getId();

		// Remote clients expect a boolean, not an integer.
		$array['HasRun'] = ($array['HasRun'] === 0);

		return $array;
	}
}
Model/Json/Task/GetBackupInfo.php000060400000003477150752453440012631 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Get information for a given backup record
 */
class GetBackupInfo extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id = (int)$defConfig['backup_id'];

		// Get the basic statistics
		$record = Platform::getInstance()->get_statistics($backup_id);

		// Get a list of filenames
		$backup_stats = Platform::getInstance()->get_statistics($backup_id);

		// Backup record doesn't exist
		if (empty($backup_stats))
		{
			throw new \RuntimeException('Invalid backup record identifier', 404);
		}

		$filenames = Factory::getStatistics()->get_all_filenames($record);

		if (empty($filenames))
		{
			// Archives are not stored on the server or no files produced
			$record['filenames'] = array();
		}
		else
		{
			$filedata = array();
			$i        = 0;

			// Get file sizes per part
			foreach ($filenames as $file)
			{
				$i++;
				$size       = @filesize($file);
				$size       = is_numeric($size) ? $size : 0;
				$filedata[] = array(
					'part' => $i,
					'name' => basename($file),
					'size' => $size
				);
			}

			// Add the file info to $record['filenames']
			$record['filenames'] = $filedata;
		}

		return $record;
	}
}
Model/Json/Task/DownloadDirect.php000060400000006755150752453440013054 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Download an entire backup archive directly over HTTP
 */
class DownloadDirect extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id' => 0,
			'part_id'   => 1,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id = (int)$defConfig['backup_id'];
		$part_id   = (int)$defConfig['part_id'];

		$backup_stats = Platform::getInstance()->get_statistics($backup_id);

		if (empty($backup_stats))
		{
			// Backup record doesn't exist
			@ob_end_clean();
			header('HTTP/1.1 500 Invalid backup record identifier');
			flush();

			$this->container->platform->closeApplication();
		}

		$files = Factory::getStatistics()->get_all_filenames($backup_stats);

		if ((count($files) < $part_id) || ($part_id <= 0))
		{
			// Invalid part
			@ob_end_clean();
			header('HTTP/1.1 500 Invalid backup part');
			flush();

			$this->container->platform->closeApplication();
		}

		$filename = $files[ $part_id - 1 ];
		@clearstatcache();

		// For a certain unmentionable browser
		if (function_exists('ini_get') && function_exists('ini_set'))
		{
			if (ini_get('zlib.output_compression'))
			{
				ini_set('zlib.output_compression', 'Off');
			}
		}

		// Remove php's time limit
		if (function_exists('ini_get') && function_exists('set_time_limit'))
		{
			if (!ini_get('safe_mode'))
			{
				@set_time_limit(0);
			}
		}

		$basename  = @basename($filename);
		$fileSize  = @filesize($filename);
		$extension = strtolower(str_replace(".", "", strrchr($filename, ".")));

		while (@ob_end_clean())
		{
			;
		}
		@clearstatcache();
		// Send MIME headers
		header('MIME-Version: 1.0');
		header('Content-Disposition: attachment; filename="' . $basename . '"');
		header('Content-Transfer-Encoding: binary');
		header('Accept-Ranges: bytes');

		switch ($extension)
		{
			case 'zip':
				// ZIP MIME type
				header('Content-Type: application/zip');
				break;

			default:
				// Generic binary data MIME type
				header('Content-Type: application/octet-stream');
				break;
		}

		// Notify of file size, if this info is available
		if ($fileSize > 0)
		{
			header('Content-Length: ' . @filesize($filename));
		}

		// Disable caching
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header("Expires: 0");
		header('Pragma: no-cache');
		flush();

		if ($fileSize > 0)
		{
			// If the filesize is reported, use 1M chunks for echoing the data to the browser
			$blockSize = 1048576; //1M chunks
			$handle    = @fopen($filename, "r");

			// Now we need to loop through the file and echo out chunks of file data
			if ($handle !== false)
			{
				while (!@feof($handle))
				{
					echo @fread($handle, $blockSize);
					@ob_flush();
					flush();
				}
			}

			if ($handle !== false)
			{
				@fclose($handle);
			}
		}
		else
		{
			// If the filesize is not reported, hope that readfile works
			@readfile($filename);
		}

		flush();

		$this->container->platform->closeApplication();

	}
}
Model/Json/Task/GetDBRoots.php000060400000002326150752453440012114 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\DatabaseFilters;
use Akeeba\Engine\Platform;

/**
 * Get the database roots (database definitions)
 */
class GetDBRoots extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = (int)$defConfig['profile'];

		if ($profile <= 0)
		{
			$profile = 1;
		}

		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var DatabaseFilters $model */
		$model = $this->container->factory->model('DatabaseFilters')->tmpInstance();

		return $model->get_roots();
	}
}
Model/Json/Task/SetIncludedDB.php000060400000004134150752453440012550 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\MultipleDatabases;
use Akeeba\Engine\Platform;

/**
 * Set up or edit an extra database definition
 */
class SetIncludedDB extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile'    => 0,
			'name'       => '',
			'connection' => array(),
			'test'       => true,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile    = $filter->clean($defConfig['profile'], 'int');
		$name       = $filter->clean($defConfig['name'], 'string');
		$connection = $filter->clean($defConfig['connection'], 'array');
		$test       = $filter->clean($defConfig['test'], 'bool');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		if (
			empty($connection) || !isset($connection['host']) || !isset($connection['driver'])
			|| !isset($connection['database']) || !isset($connection['user'])
			|| !isset($connection['password'])
		)
		{
			throw new \RuntimeException('Connection information missing or incomplete', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var MultipleDatabases $model */
		$model = $this->container->factory->model('MultipleDatabases')->tmpInstance();

		if ($test)
		{
			$result = $model->test($connection);

			if (!$result['status'])
			{
				throw new \RuntimeException('Connection test failed: ' . $result['message'], 500);
			}
		}

		return $model->setFilter($name, $connection);
	}
}
Model/Json/Task/SetDBFilter.php000060400000004141150752453440012244 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\DatabaseFilters;
use Akeeba\Engine\Platform;

/**
 * Set or unset a database filter
 */
class SetDBFilter extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'root'    => '[SITEDB]',
			'table'   => '',
			'type'    => 'tables',
			'status'  => 1
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = $filter->clean($defConfig['profile'], 'int');
		$root    = $filter->clean($defConfig['root'], 'string');
		$table   = $filter->clean($defConfig['table'], 'string');
		$type    = $filter->clean($defConfig['type'], 'cmd');
		$status  = $filter->clean($defConfig['status'], 'bool');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown database root', 500);
		}

		// We need a table name
		if (empty($table))
		{
			throw new \RuntimeException('Table name is mandatory', 500);
		}

		// We need a table name
		if (empty($type))
		{
			throw new \RuntimeException('Filter type is mandatory', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var DatabaseFilters $model */
		$model = $this->container->factory->model('DatabaseFilters')->tmpInstance();

		if ($status)
		{
			$ret = $model->setFilter($root, $table, $type);
		}
		else
		{
			$ret = $model->remove($root, $table, $type);
		}

		return $ret;
	}
}
Model/Json/Task/Log.php000060400000001641150752453440010660 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Get the log contents
 */
class Log extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'tag' => 'remote'
		);

		$defConfig = array_merge($defConfig, $parameters);

		$tag = (int)$defConfig['tag'];

		$filename = Factory::getLog()->getLogFilename($tag);

		return file_get_contents($filename);
	}
}
Model/Json/Task/GetFSRoots.php000060400000002374150752453440012142 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\FileFilters;
use Akeeba\Engine\Platform;

/**
 * Get the filesystem roots (site root and extra included directories)
 */
class GetFSRoots extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = (int)$defConfig['profile'];

		if ($profile <= 0)
		{
			$profile = 1;
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var FileFilters $model */
		$model = $this->container->factory->model('FileFilters')->tmpInstance();

		return $model->get_roots();
	}
}
Model/Json/Task/ImportConfiguration.php000060400000002254150752453440014142 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Profiles;
use Akeeba\Engine\Factory;

/**
 * Import the profile's configuration
 */
class ImportConfiguration extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'data' => null,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile_id = (int)$defConfig['profile'];
		$data = $defConfig['data'];

		if ($profile_id <= 0)
		{
			$profile_id = 0;
		}

		/** @var Profiles $profile */
		$profile = $this->container->factory->model('Profiles')->tmpInstance();

		if ($profile_id)
		{
			$profile->find($profile_id);
		}

		$profile->import($data);

		return true;
	}
}
Model/Json/Task/ListBackups.php000060400000002174150752453440012365 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Statistics;
use Akeeba\Engine\Platform;

/**
 * List the backup records
 */
class ListBackups extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'from'  => 0,
			'limit' => 50
		);

		$defConfig = array_merge($defConfig, $parameters);

		$from  = (int)$defConfig['from'];
		$limit = (int)$defConfig['limit'];

		/** @var Statistics $model */
		$model = $this->container->factory->model('Statistics')->tmpInstance();
		$model->setState('limitstart', $from);
		$model->setState('limit', $limit);

		return $model->getStatisticsListWithMeta(false);
	}
}
Model/Json/Task/GetFSEntities.php000060400000003670150752453440012620 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\FileFilters;
use Akeeba\Engine\Platform;

/**
 * Get the filesystem entities along with their filtering status (typically for rendering a GUI)
 */
class GetFSEntities extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile'      => 0,
			'root'         => '[SITEROOT]',
			'subdirectory' => '',
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile      = $filter->clean($defConfig['profile'], 'int');
		$root         = $filter->clean($defConfig['root'], 'string');
		$subdirectory = $filter->clean($defConfig['subdirectory'], 'path');
		$crumbs       = array();

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown filesystem root', 500);
		}

		// Get the subdirectory and explode it to its parts
		if (!empty($subdirectory))
		{
			$subdirectory = trim($subdirectory, '/');
		}

		if (!empty($subdirectory))
		{
			$crumbs = explode('/', $subdirectory);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var FileFilters $model */
		$model = $this->container->factory->model('FileFilters')->tmpInstance();

		return $model->make_listing($root, $crumbs);
	}
}
Model/Json/Task/GetGUIConfiguration.php000060400000002237150752453440013755 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Get the GUI definitions for the configuration page
 */
class GetGUIConfiguration extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = (int)$defConfig['profile'];

		if ($profile <= 0)
		{
			$profile = 1;
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		return Factory::getEngineParamsProvider()->getJsonGuiDefinition();
	}
}
Model/Json/Task/GetDBEntities.php000060400000003062150752453440012570 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\DatabaseFilters;
use Akeeba\Engine\Platform;

/**
 * Get the database entities along with their filtering status (typically for rendering a GUI)
 */
class GetDBEntities extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'root'    => '[SITEDB]',
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = $filter->clean($defConfig['profile'], 'int');
		$root    = $filter->clean($defConfig['root'], 'string');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown database root', 500);
		}

		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var DatabaseFilters $model */
		$model = $this->container->factory->model('DatabaseFilters')->tmpInstance();

		return $model->make_listing($root);
	}
}
Model/Json/Task/GetRegexFSFilters.php000060400000003041150752453440013427 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\RegExFileFilters;
use Akeeba\Engine\Platform;

/**
 * Get the regex filesystem filters
 */
class GetRegexFSFilters extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'root'    => '[SITEROOT]',
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = $filter->clean($defConfig['profile'], 'int');
		$root    = $filter->clean($defConfig['root'], 'string');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown database root', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var RegExFileFilters $model */
		$model = $this->container->factory->model('RegExFileFilters')->tmpInstance();

		return $model->get_regex_filters($root);
	}
}
Model/Json/Task/AbstractTask.php000060400000003000150752453440012514 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

// Protect from unauthorized access
use Akeeba\Backup\Site\Model\Json\TaskInterface;
use FOF30\Container\Container;

defined('_JEXEC') or die();

class AbstractTask implements TaskInterface
{
	/**
	 * The container of the component we belong to
	 *
	 * @var  Container
	 */
	protected $container = null;

	/**
	 * The method name
	 *
	 * @var  string
	 */
	protected $methodName = '';

	/**
	 * Public constructor
	 *
	 * @param   Container  $container  The container of the component we belong to
	 */
	public function __construct(Container $container)
	{
		$this->container = $container;

		$path = explode('\\', get_class($this));
		$shortName = array_pop($path);
		$this->methodName = lcfirst($shortName);
	}

	/**
	 * Return the JSON API task's name ("method" name). Remote clients will use it to call us.
	 *
	 * @return  string
	 */
	public function getMethodName()
	{
		return $this->methodName;
	}

	/**
	 * Execute the JSON API task
	 *
	 * @param   array  $parameters  The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		throw new \LogicException(__CLASS__ . ' has not implemented its execute() method yet.');
	}
}
Model/Json/Task/GetProfiles.php000060400000002031150752453440012354 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Profiles;

/**
 * Get a list of known backup profiles
 */
class GetProfiles extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		/** @var Profiles $model */
		$model = $this->container->factory->model('Profiles')->tmpInstance();

		$profiles = $model->get(true);
		$ret      = array();

		if (count($profiles))
		{
			foreach ($profiles as $profile)
			{
				$temp       = new \stdClass();
				$temp->id   = $profile->id;
				$temp->name = $profile->description;
				$ret[]      = $temp;
			}
		}

		return $ret;
	}
}
Model/Json/Task/SaveConfiguration.php000060400000003473150752453440013572 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Save the configuration for a given profile
 */
class SaveConfiguration extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile'      => -1,
			'engineconfig' => array()
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = (int)$defConfig['profile'];
		$data    = $defConfig['engineconfig'];

		if (empty($profile))
		{
			throw new \RuntimeException('Invalid profile ID', 404);
		}

		// Forbid stupidly selecting the site's root as the output or temporary directory
		if (array_key_exists('akeeba.basic.output_directory', $data))
		{
			$folder = $data['akeeba.basic.output_directory'];
			$folder = Factory::getFilesystemTools()->translateStockDirs($folder, true, true);

			$check = Factory::getFilesystemTools()->translateStockDirs('[SITEROOT]', true, true);

			if ($check == $folder)
			{
				$data['akeeba.basic.output_directory'] = '[DEFAULT_OUTPUT]';
			}
		}

		// Merge it
		$config        = Factory::getConfiguration();
		$protectedKeys = $config->getProtectedKeys();
		$config->resetProtectedKeys();
		$config->mergeArray($data, false, false);
		$config->setProtectedKeys($protectedKeys);

		// Save configuration
		return Platform::getInstance()->save_configuration($profile);
	}
}
Model/Json/Task/GetFSFilters.php000060400000003003150752453440012432 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\FileFilters;
use Akeeba\Engine\Platform;

/**
 * Get the filesystem filters
 */
class GetFSFilters extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'root'    => '[SITEROOT]',
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = $filter->clean($defConfig['profile'], 'int');
		$root    = $filter->clean($defConfig['root'], 'string');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown filesystem root', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var FileFilters $model */
		$model = $this->container->factory->model('FileFilters')->tmpInstance();

		return $model->get_filters($root);
	}
}
Model/Json/Task/GetRegexDBFilters.php000060400000003051150752453440013405 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\RegExDatabaseFilters;
use Akeeba\Engine\Platform;

/**
 * Get the regex database filters
 */
class GetRegexDBFilters extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'root'    => '[SITEDB]',
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = $filter->clean($defConfig['profile'], 'int');
		$root    = $filter->clean($defConfig['root'], 'string');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown database root', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var RegExDatabaseFilters $model */
		$model = $this->container->factory->model('RegExDatabaseFilters')->tmpInstance();

		return $model->get_regex_filters($root);
	}
}
Model/Json/Task/RemoveIncludedDirectory.php000060400000003043150752453440014727 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\IncludeFolders;
use Akeeba\Engine\Platform;

/**
 * Remove an extra directory definition
 */
class RemoveIncludedDirectory extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile'       => 0,
			'uuid'          => '',
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile       = $filter->clean($defConfig['profile'], 'int');
		$uuid          = $filter->clean($defConfig['uuid'], 'string');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a uuid
		if (empty($uuid))
		{
			throw new \RuntimeException('UUID is required', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var IncludeFolders $model */
		$model = $this->container->factory->model('IncludeFolders')->tmpInstance();

		return $model->remove($uuid);
	}
}
Model/Json/Task/GetIncludedDirectories.php000060400000002366150752453440014530 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\IncludeFolders;
use Akeeba\Engine\Platform;

/**
 * Get the extra included directories
 */
class GetIncludedDirectories extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = (int)$defConfig['profile'];

		if ($profile <= 0)
		{
			$profile = 1;
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var IncludeFolders $model */
		$model = $this->container->factory->model('IncludeFolders')->tmpInstance();

		return $model->get_directories();
	}
}
Model/Json/Task/Delete.php000060400000002174150752453440011343 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Statistics;
use Akeeba\Engine\Platform;

/**
 * Delete a backup record
 */
class Delete extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id = (int)$defConfig['backup_id'];

		/** @var Statistics $model */
		$model = $this->container->factory->model('Statistics')->tmpInstance();
		$model->setState('id', $backup_id);

		try
		{
			$model->delete();
		}
		catch (\Exception $e)
		{
			throw new \RuntimeException($e->getMessage(), 500);
		}

		return true;
	}
}
Model/Json/Task/GetDBFilters.php000060400000002755150752453440012424 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\DatabaseFilters;
use Akeeba\Engine\Platform;

/**
 * Get the database filters
 */
class GetDBFilters extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'root'    => '[SITEDB]',
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = $filter->clean($defConfig['profile'], 'int');
		$root    = $filter->clean($defConfig['root'], 'string');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown database root', 500);
		}

		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var DatabaseFilters $model */
		$model = $this->container->factory->model('DatabaseFilters')->tmpInstance();

		return $model->get_filters($root);
	}
}
Model/Json/Task/SetIncludedDirectory.php000060400000004536150752453440014235 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\IncludeFolders;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\RandomValue;

/**
 * Set up or edit an extra directory definition
 */
class SetIncludedDirectory extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile'       => 0,
			'uuid'          => '',
			'path'          => '',
			'virtualFolder' => '',
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile       = $filter->clean($defConfig['profile'], 'int');
		$path          = $filter->clean($defConfig['path'], 'path');
		$uuid          = $filter->clean($defConfig['uuid'], 'string');
		$virtualFolder = $filter->clean($defConfig['virtualFolder'], 'string');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a path
		if (empty($path))
		{
			throw new \RuntimeException('Path is required', 500);
		}

		// We need a uuid
		if (empty($uuid))
		{
			$uuid = $this->uuid_v4();
		}

		// We need a vf
		if (empty($virtualFolder))
		{
			$virtualFolder = basename($path);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var IncludeFolders $model */
		$model = $this->container->factory->model('IncludeFolders')->tmpInstance();

		$data = array($path, $virtualFolder);

		return $model->setFilter($uuid, $data);
	}

	/**
	 * Generate a UUID v4
	 *
	 * @return  string
	 */
	private function uuid_v4()
	{
		$randval = new RandomValue();
		$data    = $randval->generate(16);

		$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
		$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10

		return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
	}
}
Model/Json/Task/StepBackup.php000060400000004555150752453440012207 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Step through a backup job
 */
class StepBackup extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile'  => null,
			'tag'      => AKEEBA_BACKUP_ORIGIN,
			'backupid' => null,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile  = $filter->clean($defConfig['profile'], 'int');
		$tag      = $filter->clean($defConfig['tag'], 'cmd');
		$backupid = $filter->clean($defConfig['backupid'], 'cmd');

		if (is_null($backupid) && defined('AKEEBA_BACKUP_ID'))
		{
			$tag = AKEEBA_BACKUP_ID;
		}

		if (empty($backupid))
		{
			throw new \RuntimeException("JSON API :: stepBackup -- You have not provided the required backupid parameter. This parameter is MANDATORY since May 2016. Please update your client software to include this parameter.");
		}

		// Try to set the profile from the setup parameters
		if (!empty($profile))
		{
			$profile  = max(1, $profile); // Make sure $profile is a positive integer >= 1
			$this->container->platform->setSessionVar('profile', $profile);
			define('AKEEBA_PROFILE', $profile);
		}

		/** @var \Akeeba\Backup\Site\Model\Backup $model */
		$model = $this->container->factory->model('Backup')->tmpInstance();
		$model->setState('tag', $tag);
		$model->setState('backupid', $backupid);
		$array = $model->stepBackup(false);

		if ($array['Error'] != '')
		{
			throw new \RuntimeException('A backup error has occurred: ' . $array['Error'], 500);
		}

		// BackupID contains the numeric backup record ID. backupid contains the backup id (usually in the form id123)
		$statistics        = Factory::getStatistics();
		$array['BackupID'] = $statistics->getId();

		// Remote clients expect a boolean, not an integer.
		$array['HasRun'] = ($array['HasRun'] === 0);

		return $array;
	}
}
Model/Json/Task/SetRegexDBFilter.php000060400000004166150752453440013246 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\RegExDatabaseFilters;
use Akeeba\Engine\Platform;

/**
 * Set or unset a Regex database filter
 */
class SetRegexDBFilter extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'root'    => '[SITEDB]',
			'regex'   => '',
			'type'    => 'tables',
			'status'  => 1
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = $filter->clean($defConfig['profile'], 'int');
		$root    = $filter->clean($defConfig['root'], 'string');
		$regex   = $filter->clean($defConfig['regex'], 'string');
		$type    = $filter->clean($defConfig['type'], 'cmd');
		$status  = $filter->clean($defConfig['status'], 'bool');

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown database root', 500);
		}

		// We need a regex name
		if (empty($regex))
		{
			throw new \RuntimeException('Regex is mandatory', 500);
		}

		// We need a regex name
		if (empty($type))
		{
			throw new \RuntimeException('Filter type is mandatory', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var RegExDatabaseFilters $model */
		$model = $this->container->factory->model('RegExDatabaseFilters')->tmpInstance();

		if ($status)
		{
			$ret = $model->setFilter($type, $root, $regex);
		}
		else
		{
			$ret = $model->remove($type, $root, $regex);
		}

		return $ret;
	}
}
Model/Json/Task/DeleteProfile.php000060400000002463150752453440012665 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Profiles;
use Akeeba\Engine\Platform;

/**
 * Delete a backup profile
 */
class DeleteProfile extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = (int)$defConfig['profile'];

		// You need to specify the profile
		if (empty($profile))
		{
			throw new \RuntimeException('Invalid profile ID', 404);
		}

		if ($profile == 1)
		{
			throw new \RuntimeException('You cannot delete the default backup profile', 404);
		}

		// Get a profile model
		/** @var Profiles $profileModel */
		$profileModel = $this->container->factory->model('Profiles')->tmpInstance();
		$profileModel->findOrFail($profile);
		$profileModel->delete();

		return true;
	}
}
Model/Json/Task/Browse.php000060400000003462150752453440011403 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Browser;
use Akeeba\Engine\Platform;

/**
 * Return folder browser results
 */
class Browse extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'folder'        => '',
			'processfolder' => 0
		);

		$defConfig = array_merge($defConfig, $parameters);

		$folder        = $filter->clean($defConfig['folder'], 'string');
		$processFolder = $filter->clean($defConfig['processfolder'], 'bool');

		/** @var Browser $model */
		$model = $this->container->factory->model('Browser')->tmpInstance();
		$model->setState('folder', $folder);
		$model->setState('processfolder', $processFolder);
		$model->makeListing();

		$ret = array(
			'folder'                => $model->getState('folder'),
			'folder_raw'            => $model->getState('folder_raw'),
			'parent'                => $model->getState('parent'),
			'exists'                => $model->getState('exists'),
			'inRoot'                => $model->getState('inRoot'),
			'openbasedirRestricted' => $model->getState('openbasedirRestricted'),
			'writable'              => $model->getState('writable'),
			'subfolders'            => $model->getState('subfolders'),
			'breadcrumbs'           => $model->getState('breadcrumbs'),
		);

		return $ret;
	}
}
Model/Json/Task/ExportConfiguration.php000060400000003220150752453440014143 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Profiles;
use Akeeba\Engine\Factory;

/**
 * Export the profile's configuration
 */
class ExportConfiguration extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile_id = (int)$defConfig['profile'];

		if ($profile_id <= 0)
		{
			$profile_id = 1;
		}

		/** @var Profiles $profile */
		$profile = $this->container->factory->model('Profiles')->tmpInstance();

		$data = $profile->findOrFail($profile_id)->getData();

		if (substr($data['configuration'], 0, 12) == '###AES128###')
		{
			// Load the server key file if necessary
			if (!defined('AKEEBA_SERVERKEY'))
			{
				$filename = JPATH_COMPONENT_ADMINISTRATOR . '/BackupEngine/serverkey.php';

				include_once $filename;
			}

			$key = Factory::getSecureSettings()->getKey();

			$data['configuration'] = Factory::getSecureSettings()->decryptSettings($data['configuration'], $key);
		}

		return array(
			'description'   => $data['description'],
			'configuration' => $data['configuration'],
			'filters'       => $data['filters'],
		);
	}
}
Model/Json/Task/SetFSFilter.php000060400000004574150752453440012301 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\FileFilters;
use Akeeba\Engine\Platform;

/**
 * Set or unset a filesystem filter
 */
class SetFSFilter extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		$filter = \JFilterInput::getInstance();

		// Get the passed configuration values
		$defConfig = array(
			'profile' => 0,
			'root'    => '[SITEROOT]',
			'path'    => '',
			'type'    => '',
			'status'  => 1
		);

		$defConfig = array_merge($defConfig, $parameters);

		$profile = $filter->clean($defConfig['profile'], 'int');
		$root    = $filter->clean($defConfig['root'], 'string');
		$path    = $filter->clean($defConfig['path'], 'path');
		$type    = $filter->clean($defConfig['type'], 'cmd');
		$status  = $filter->clean($defConfig['status'], 'bool');

		$crumbs = array();
		$node   = '';

		// We need a valid profile ID
		if ($profile <= 0)
		{
			$profile = 1;
		}

		// We need a root
		if (empty($root))
		{
			throw new \RuntimeException('Unknown filesystem root', 500);
		}

		// We need a path
		if (empty($path))
		{
			throw new \RuntimeException('Unknown path', 500);
		}

		// Get the subdirectory and explode it to its parts
		$path = trim($path, '/');

		if (!empty($path))
		{
			$crumbs = explode('/', $root);
			$node   = array_pop($crumbs);
		}

		if (empty($node))
		{
			throw new \RuntimeException('Unknown path', 500);
		}

		// We need a table name
		if (empty($type))
		{
			throw new \RuntimeException('Filter type is mandatory', 500);
		}

		// Set the active profile
		$this->container->platform->setSessionVar('profile', $profile);

		// Load the configuration
		Platform::getInstance()->load_configuration($profile);

		/** @var FileFilters $model */
		$model = $this->container->factory->model('FileFilters')->tmpInstance();

		if ($status)
		{
			$ret = $model->setFilter($root, $crumbs, $node, $type);
		}
		else
		{
			$ret = $model->remove($root, $crumbs, $node, $type);
		}

		return $ret;
	}
}
Model/Json/Task/Download.php000060400000004347150752453440011714 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Task;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;

/**
 * Download a chunk of a backup archive over HTTP
 */
class Download extends AbstractTask
{
	/**
	 * Execute the JSON API task
	 *
	 * @param   array $parameters The parameters to this task
	 *
	 * @return  mixed
	 *
	 * @throws  \RuntimeException  In case of an error
	 */
	public function execute(array $parameters = array())
	{
		// Get the passed configuration values
		$defConfig = array(
			'backup_id'  => 0,
			'part_id'    => 1,
			'segment'    => 1,
			'chunk_size' => 1
		);

		$defConfig = array_merge($defConfig, $parameters);

		$backup_id  = (int)$defConfig['backup_id'];
		$part_id    = (int)$defConfig['part_id'];
		$segment    = (int)$defConfig['segment'];
		$chunk_size = (int)$defConfig['chunk_size'];

		$backup_stats = Platform::getInstance()->get_statistics($backup_id);

		if (empty($backup_stats))
		{
			// Backup record doesn't exist
			throw new \RuntimeException('Invalid backup record identifier', 404);
		}

		$files = Factory::getStatistics()->get_all_filenames($backup_stats);

		if ((count($files) < $part_id) || ($part_id <= 0))
		{
			// Invalid part
			throw new \RuntimeException('Invalid backup part', 404);
		}

		$file = $files[ $part_id - 1 ];

		$filesize = @filesize($file);
		$seekPos  = $chunk_size * 1048576 * ($segment - 1);

		if ($seekPos > $filesize)
		{
			// Trying to seek past end of file
			throw new \RuntimeException('Invalid segment', 404);
		}

		$fp = fopen($file, 'rb');

		if ($fp === false)
		{
			// Could not read file
			throw new \RuntimeException('Error reading backup archive', 500);
		}

		rewind($fp);
		if (fseek($fp, $seekPos, SEEK_SET) === -1)
		{
			// Could not seek to position
			throw new \RuntimeException('Error reading specified segment', 500);
		}

		$buffer = fread($fp, 1048576);

		if ($buffer === false)
		{
			throw new \RuntimeException('Error reading specified segment', 500);
		}

		fclose($fp);

		return base64_encode($buffer);

	}
}
Model/Json/Encapsulation/AesCbc256.php000060400000004575150752453450013431 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Encapsulation;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;

/**
 * AES CBC 256 encapsulation
 */
class AesCbc256 extends Base
{
	/**
	 * Constructs the encapsulation handler object
	 */
	function __construct()
	{
		parent::__construct(5, 'ENCAPSULATION_AESCBC256', ' Data in AES-256 standard (CBC) mode encrypted JSON');
	}

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it and then JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to decode data
	 * @param   string  $data       Encoded data
	 *
	 * @return  string  The decoded data.
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02.html
	 */
	public function decode($serverKey, $data)
	{
		$data = base64_decode($data);
		return $this->getEncryption()->AESDecryptCBC($data, $serverKey, 256);
	}

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to encode data
	 * @param   mixed   $data       The data to encode, typically a string, array or object
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($serverKey, $data)
	{
		return base64_encode($this->getEncryption()->AESEncryptCBC($data, $serverKey, 256));
	}
}
Model/Json/Encapsulation/Raw.php000060400000006074150752453450012601 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Encapsulation;

// Protect from unauthorized access
defined('_JEXEC') or die();

/**
 * Raw (plain text) encapsulation
 */
class Raw extends Base
{
	/**
	 * Constructs the encapsulation handler object
	 */
	function __construct()
	{
		parent::__construct(1, 'ENCAPSULATION_RAW', 'Data in plain-text JSON');
	}

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it and then JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to decode data
	 * @param   string  $data       Encoded data
	 *
	 * @return  string  The decoded data.
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02.html
	 */
	public function decode($serverKey, $data)
	{
		return $data;
	}

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to encode data
	 * @param   mixed   $data       The data to encode, typically a string, array or object
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($serverKey, $data)
	{
		return $data;
	}

	/**
	 * Checks if the request body authorises the user to use the API. Each encapsulation can implement its own
	 * authorisation method. This method is only called after the request body has been successfully decoded, therefore
	 * encrypted encapsulations can simply return true.
	 *
	 * @param   string $serverKey The server key we need to check the authorisation
	 * @param   array  $body      The decoded body (as returned by the decode() method)
	 *
	 * @return  bool  True if authorised
	 */
	public function isAuthorised($serverKey, $body)
	{
		$authenticated = false;

		if (isset($body['challenge']) && (strpos($body['challenge'], ':') >= 2) && (strlen($body['challenge']) >= 3))
		{
			list ($challengeData, $providedHash) = explode(':', $body['challenge']);
			$computedHash = strtolower(md5($challengeData . $serverKey));
			$authenticated = ($computedHash == $providedHash);
		}

		return $authenticated;
	}

}
Model/Json/Encapsulation/Base.php000060400000011731150752453450012716 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Encapsulation;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Json\EncapsulationInterface;
use Akeeba\Engine\Factory;
use Akeeba\Engine\Util\Encrypt;

abstract class Base implements EncapsulationInterface
{
	/**
	 * The numeric ID of this encapsulation
	 *
	 * @var  int
	 */
	protected $id = 0;

	/**
	 * The code of this encapsulation
	 *
	 * @var  string
	 */
	protected $code = 'ENCAPSULATION_VOID';

	/**
	 * The description of this encapsulation
	 *
	 * @var  string
	 */
	protected $description = 'Invalid encapsulation';

	/**
	 * The encryption object which is set up for use with the JSON API
	 *
	 * @var  Encrypt
	 */
	private $encryption;

	/**
	 * Public constructor. Called by children to customise the encapsulation handler object
	 *
	 * @param   int     $id           Numeric ID
	 * @param   string  $code         Code
	 * @param   string  $description  Human readable description
	 */
	function __construct($id, $code, $description)
	{
		$this->id          = $id;
		$this->code        = strtoupper($code);
		$this->description = $description;
	}

	/**
	 * Returns information about the encapsulation supported by this class. The return array has the following keys:
	 * id: The numeric ID of the encapsulation, e.g. 3
	 * code: The short code of the encapsulation, e.g. ENCAPSULATION_AESCTR256
	 * description: A human readable descriptions, e.g. "Data in AES-256 stream (CTR) mode encrypted JSON"
	 *
	 * @return  array  See above
	 */
	public function getInformation()
	{
		return array(
			'id'          => $this->id,
			'code'        => $this->code,
			'description' => $this->description,
		);
	}

	/**
	 * Checks if the request body authorises the user to use the API. Each encapsulation can implement its own
	 * authorisation method. This method is only called after the request body has been successfully decoded, therefore
	 * encrypted encapsulations can simply return true.
	 *
	 * @param   string $serverKey The server key we need to check the authorisation
	 * @param   array  $body      The decoded body (as returned by the decode() method)
	 *
	 * @return  bool  True if authorised
	 */
	public function isAuthorised($serverKey, $body)
	{
		return true;
	}

	/**
	 * Is the provided encapsulation type supported by this class?
	 *
	 * @param   int  $encapsulation  Encapsulation type
	 *
	 * @return  bool  True if supported
	 */
	public function isSupported($encapsulation)
	{
		return $encapsulation == $this->id;
	}

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it and then JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to decode data
	 * @param   string  $data       Encoded data
	 *
	 * @return  string  The decoded data.
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02.html
	 */
	public function decode($serverKey, $data)
	{
	}

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to encode data
	 * @param   mixed   $data       The data to encode, typically a string, array or object
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($serverKey, $data)
	{
	}

	/**
	 * Returns an encryption object normalized for use in the JSON API: PBKDF2 uses a dynamic salt with SHA1 algorithm.
	 * This is necessary when we are running a backup against a profile which uses a static salt. In this case the
	 * static salt is not included in the ciphertext, making it impossible for the remote side to decipher our message,
	 * leading to backup failure.
	 *
	 * @return  Encrypt
	 */
	protected function getEncryption()
	{
		if (is_null($this->encryption))
		{
			$encryption = Factory::getEncryption();
			$this->encryption = clone $encryption;
			$this->encryption->setPbkdf2UseStaticSalt(false);
			$this->encryption->setPbkdf2Algorithm('sha1');
		}

		return $this->encryption;
	}
}
Model/Json/Encapsulation/AesCtr128.php000060400000004513150752453450013460 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Encapsulation;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;

/**
 * AES CTR 128 encapsulation
 */
class AesCtr128 extends Base
{
	/**
	 * Constructs the encapsulation handler object
	 */
	function __construct()
	{
		parent::__construct(2, 'ENCAPSULATION_AESCTR128', 'Data in AES-128 stream (CTR) mode encrypted JSON');
	}

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it and then JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to decode data
	 * @param   string  $data       Encoded data
	 *
	 * @return  string  The decoded data.
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02.html
	 */
	public function decode($serverKey, $data)
	{
		return $this->getEncryption()->AESDecryptCtr($data, $serverKey, 128);
	}

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to encode data
	 * @param   mixed   $data       The data to encode, typically a string, array or object
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($serverKey, $data)
	{
		return $this->getEncryption()->AESEncryptCtr($data, $serverKey, 128);
	}
}
Model/Json/Encapsulation/AesCtr256.php000060400000004513150752453450013462 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Encapsulation;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;

/**
 * AES CTR 256 encapsulation
 */
class AesCtr256 extends Base
{
	/**
	 * Constructs the encapsulation handler object
	 */
	function __construct()
	{
		parent::__construct(3, 'ENCAPSULATION_AESCTR256', 'Data in AES-256 stream (CTR) mode encrypted JSON');
	}

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it and then JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to decode data
	 * @param   string  $data       Encoded data
	 *
	 * @return  string  The decoded data.
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02.html
	 */
	public function decode($serverKey, $data)
	{
		return $this->getEncryption()->AESDecryptCtr($data, $serverKey, 256);
	}

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to encode data
	 * @param   mixed   $data       The data to encode, typically a string, array or object
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($serverKey, $data)
	{
		return $this->getEncryption()->AESEncryptCtr($data, $serverKey, 256);
	}
}
Model/Json/Encapsulation/AesCbc128.php000060400000004575150752453450013427 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json\Encapsulation;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Engine\Factory;

/**
 * AES CBC 128 encapsulation
 */
class AesCbc128 extends Base
{
	/**
	 * Constructs the encapsulation handler object
	 */
	function __construct()
	{
		parent::__construct(4, 'ENCAPSULATION_AESCBC128', ' Data in AES-128 standard (CBC) mode encrypted JSON');
	}

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it and then JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to decode data
	 * @param   string  $data       Encoded data
	 *
	 * @return  string  The decoded data.
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02.html
	 */
	public function decode($serverKey, $data)
	{
		$data = base64_decode($data);
		return $this->getEncryption()->AESDecryptCBC($data, $serverKey, 128);
	}

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   string  $serverKey  The server key we need to encode data
	 * @param   mixed   $data       The data to encode, typically a string, array or object
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throws  \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throws  \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($serverKey, $data)
	{
		return base64_encode($this->getEncryption()->AESEncryptCBC($data, $serverKey, 128));
	}
}
Model/Json/Encapsulation.php000060400000015464150752453450012053 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model\Json;

// Protect from unauthorized access
defined('_JEXEC') or die();

/**
 * Handles data encapsulation
 */
class Encapsulation
{
	/**
	 * Known encapsulation handlers
	 *
	 * @var  EncapsulationInterface[]
	 */
	protected $handlers = array();

	/**
	 * List of encapsulation types
	 *
	 * @var  array
	 */
	protected $encapsulations = array();

	/**
	 * The server key used to decrypt / encrypt data and check the authorisation
	 *
	 * @var  string
	 */
	protected $serverKey;

	/**
	 * Public constructor
	 *
	 * @param   string  $serverKey  The server key used for data encyrption/decryption and authorisation checks
	 */
	public function __construct($serverKey)
	{
		$this->serverKey = $serverKey;

		// Populate the list of encapsulation handlers
		$this->initialiseHandlers();
	}

	/**
	 * Returns the encapsulation ID given its code. For example given $code == 'ENCAPSULATION_AESCTR256' it will return
	 * the ID integer 3.
	 *
	 * @param   string  $code  The encapsulation code, e.g. ENCAPSULATION_AESCTR256
	 *
	 * @return  int  The numeric ID, e.g. 3
	 */
	public function getEncapsulationByCode($code)
	{
		$info = $this->getEncapsulationInfoByCode($code);

		return $info['id'];
	}

	/**
	 * Returns the encapsulation information array given its code. For example given $code == 'ENCAPSULATION_AESCTR256'
	 * it will return the information for the data in AES-256 stream (CTR) mode encrypted JSON type.
	 *
	 * @param   string  $code  The encapsulation code, e.g. ENCAPSULATION_AESCTR256
	 *
	 * @return  array  The information of the encapsulation handler
	 */
	public function getEncapsulationInfoByCode($code)
	{
		// Normalise the code
		$code = strtoupper($code);

		// If we have no idea what the encapsulation should be revert to raw (plain text)
		if (!isset($this->encapsulations[$code]))
		{
			return $this->encapsulations['ENCAPSULATION_RAW'];
		}

		return $this->encapsulations[$code];
	}

	/**
	 * Decodes the data. For encrypted encapsulations this means base64-decoding the data, decrypting it and then JSON-
	 * decoding the result. If any error occurs along the way the appropriate exception is thrown.
	 *
	 * The data being decoded corresponds to the Request Body described in the API documentation
	 *
	 * @param   int     $encapsulation  The encapsulation type
	 * @param   string  $data           Encoded data
	 *
	 * @return  array  The decoded data.
	 *
	 * @throw   \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throw   \InvalidArgumentException  When $data cannot be decoded successfully
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02.html
	 */
	public function decode($encapsulation, $data)
	{
		$body = null;

		// Find the suitable handler and encode the data
		foreach ($this->handlers as $handler)
		{
			if ($handler->isSupported($encapsulation))
			{
				$body = $handler->decode($this->serverKey, $data);

				break;
			}
		}

		// If the data cannot be encoded throw an exception
		if (!isset($handler) || is_null($body))
		{
			throw new \RuntimeException('The requested encapsulation type is not supported', 503);
		}

		$authorised = true;
		$body = rtrim($body, chr(0));

		// Make sure it looks like a valid JSON string and is at least 12 characters (minimum valid message length)
		if ((strlen($body) < 12) || (substr($body, 0, 1) != '{') || (substr($body, -1) != '}'))
		{
			$authorised = false;
		}

		// Try to JSON decode the body
		if ($authorised)
		{
			$body = json_decode($body, true);

			if (is_null($body))
			{
				$authorised = false;
			}
			elseif (!is_array($body))
			{
				$authorised = false;
			}
		}

		// Make sure there is a requested method
		if ($authorised)
		{
			if (!isset($body['method']) || empty($body['method']))
			{
				$authorised = false;
			}
		}

		if ($authorised)
		{
			$authorised = $handler->isAuthorised($this->serverKey, $body);
		}

		if (!$authorised)
		{
			throw new \InvalidArgumentException('Authentication failed', 401);
		}

		return (array)$body;
	}

	/**
	 * Encodes the data. The data is JSON encoded by this method before encapsulation takes place. Encrypted
	 * encapsulations will then encrypt the data and base64-encode it before returning it.
	 *
	 * The data being encoded correspond to the body > data structure described in the API documentation
	 *
	 * @param   int     $encapsulation  The encapsulation type
	 * @param   mixed   $data           The data to encode, typically a string, array or object
	 * @param   string  $key            Key to use for encoding. If not provided we revert to $this->serverKey
	 *
	 * @return  string  The encapsulated data
	 *
	 * @see     https://www.akeebabackup.com/documentation/json-api/ar01s02s02.html
	 *
	 * @throw   \RuntimeException  When the server capabilities don't match the requested encapsulation
	 * @throw   \InvalidArgumentException  When $data cannot be converted to JSON
	 */
	public function encode($encapsulation, $data, $key = null)
	{
		// Try to JSON-encode the data
		$data = json_encode($data);

		// If the data cannot be JSON-encoded throw an exception
		if ($data === false)
		{
			throw new \InvalidArgumentException('Empty data cannot be encapsulated', 500);
		}

		// Make sure we have a valid key
		if (empty($key))
		{
			$key = $this->serverKey;
		}

		// Find the suitable handler and encode the data
		foreach ($this->handlers as $handler)
		{
			if ($handler->isSupported($encapsulation))
			{
				return $handler->encode($key, $data);
			}
		}

		// If the data cannot be encoded throw an exception
		$format = print_r($encapsulation, true);
		throw new \RuntimeException("Data cannot be encapsulated in the requested format ($format)", 500);
	}

	/**
	 * Initialises the encapsulation handlers
	 *
	 * @return  void
	 */
	protected function initialiseHandlers()
	{
		// Reset the arrays
		$this->handlers = array();
		$this->encapsulations = array();

		// Look all files in the Encapsulation handlers' directory
		$dh = new \DirectoryIterator(__DIR__ . '/Encapsulation');

		/** @var \DirectoryIterator $entry */
		foreach ($dh as $entry)
		{
			$fileName = $entry->getFilename();

			// Ignore non-PHP files
			if (substr($fileName, -4) != '.php')
			{
				continue;
			}

			// Ignore the Base class
			if ($fileName == 'Base.php')
			{
				continue;
			}

			// Get the class name
			$className = '\\Akeeba\\Backup\\Site\\Model\\Json\\Encapsulation\\' . substr($fileName, 0, -4);

			// Check if the class really exists
			if (!class_exists($className, true))
			{
				continue;
			}

			/** @var EncapsulationInterface $o */
			$o = new $className;
			$info = $o->getInformation();
			$this->encapsulations[$info['code']] = $info;
			$this->handlers[] = $o;
		}
	}
}
Model/RegExFileFilters.php000060400000000606150752453450011470 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\RegExFileFilters as AdminModel;

class RegExFileFilters extends AdminModel
{
}
Model/web.config000060400000001025150752453450007554 0ustar00<?xml version="1.0"?>
<!--
    This only works on IIS 7 or later. See https://www.iis.net/configreference/system.webserver/security/requestfiltering/fileextensions
-->
<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <fileExtensions allowUnlisted="false" >
                    <clear />
                    <add fileExtension=".html" allowed="true"/>
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>Model/IncludeFolders.php000060400000000602150752453450011223 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\IncludeFolders as AdminModel;

class IncludeFolders extends AdminModel
{
}
Model/Profiles.php000060400000000566150752453450010115 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\Profiles as AdminModel;

class Profiles extends AdminModel
{
}
Model/Json.php000060400000013514150752453450007240 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Site\Model\Json\Encapsulation;
use Akeeba\Backup\Site\Model\Json\Task;
use Akeeba\Engine\Platform;
use Akeeba\Engine\Util\Complexify;
use FOF30\Container\Container;
use FOF30\Model\Model;

// JSON API version number
define('AKEEBA_JSON_API_VERSION', '350');

/*
 * Short API version history:
 * 300	First draft. Basic backup working. Encryption semi-broken.
 * 316	Fixed download feature.
 * 320  Minor bug fixes
 * 330  Introduction of Akeeba Solo
 * 335  Configuration overrides in startBackup
 * 340  Advanced API allows full configuration
 * 341  exportConfiguration, importConfiguration
 */

if (!defined('AKEEBA_BACKUP_ORIGIN'))
{
	define('AKEEBA_BACKUP_ORIGIN', 'json');
}

/**
 * JSON API model. Handles remote API calls through our JSON API.
 */
class Json extends Model
{
	const    COM_AKEEBA_CPANEL_LBL_STATUS_OK = 200; // Normal reply
	const    STATUS_NOT_AUTH = 401; // Invalid credentials
	const    STATUS_NOT_ALLOWED = 403; // Not enough privileges
	const    STATUS_NOT_FOUND = 404; // Requested resource not found
	const    STATUS_INVALID_METHOD = 405; // Unknown JSON method
	const    COM_AKEEBA_CPANEL_LBL_STATUS_ERROR = 500; // An error occurred
	const    STATUS_NOT_IMPLEMENTED = 501; // Not implemented feature
	const    STATUS_NOT_AVAILABLE = 503; // Remote service not activated

	/** @var int Data encapsulation format */
	private $encapsulationType = 1;

	/** @var  Encapsulation */
	private $encapsulation;

	/** @var string A password passed to us by the caller */
	private $password = null;

	/**
	 * Overridden constructor
	 *
	 * Sets up the encapsulation.
	 *
	 * @param   Container  $container  The configuration variables to this model
	 * @param   array      $config     Configuration values for this model
	 */
	public function __construct(Container $container, array $config)
	{
		parent::__construct($container, $config);

		$this->encapsulation = new Encapsulation($this->serverKey());
	}

	/**
	 * Parses the JSON data sent by the client and executes the appropriate JSON API task
	 *
	 * @param   string  $json  The raw JSON data received from the remote client
	 *
	 * @return  string  The JSON-encoded, fully encapsulated response
	 */
	public function execute($json)
	{
		// Check if we're activated
		$enabled = Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0);

		// Is the Secret Key strong enough?
		$validKey = $this->serverKey();

		if (!Complexify::isStrongEnough($validKey, false))
		{
			$enabled = false;
		}

		$rawEncapsulation = $this->encapsulation->getEncapsulationByCode('ENCAPSULATION_RAW');

		if (!$enabled)
		{
			return $this->getResponse('Access denied', 503);
		}

		// Try to JSON-decode the request's input first
		$request = @json_decode($json, true);

		if (is_null($request))
		{
			return $this->getResponse('JSON decoding error', 500);
		}

		// Transform legacy requests
		if (!is_array($request))
		{
			$request = array(
				'encapsulation' => $rawEncapsulation,
				'body' => $request
			);
		}

		// Transform partial requests
		if (!isset($request['encapsulation']))
		{
			$request['encapsulation'] = $rawEncapsulation;
		}

		// Make sure we have a request body
		if (!isset($request['body']))
		{
			$request['body'] = '';
		}

		try
		{
			$request['body'] = $this->encapsulation->decode($request['encapsulation'], $request['body']);
		}
		catch (\Exception $e)
		{
			return $this->getResponse($e->getMessage(), $e->getCode());
		}

		// Replicate the encapsulation preferences of the client for our own output
		$this->encapsulationType = $request['encapsulation'];

		// Store the client-specified key, or use the server key if none specified and the request
		// came encrypted.
		$this->password = isset($request['body']['key']) ? $request['body']['key'] : $this->serverKey();

		// Run the method
		$params = array();

		if (isset($request['body']['data']))
		{
			$params = (array)$request['body']['data'];
		}

		try
		{
			$taskHandler = new Task($this->container);
			$data = $taskHandler->execute($request['body']['method'], $params);
		}
		catch (\RuntimeException $e)
		{
			return $this->getResponse($e->getMessage(), $e->getCode());
		}

		return $this->getResponse($data);
	}

	/**
	 * Packages the response to a JSON-encoded object, optionally encrypting the data part with a caller-supplied
	 * password.
	 *
	 * @param   mixed  $data    The response to encapsulate
	 * @param   int    $status  The status code to return. 200 = Success, anything else is treated as an error.
	 *
	 * @return  string  The JSON-encoded response
	 */
	private function getResponse($data, $status = 200)
	{
		// Initialize the response
		$response = array(
			'encapsulation' => $this->encapsulationType,
			'body'          => array(
				'status' => $status,
				'data'   => null
			)
		);

		if ($status != 200)
		{
			$response['encapsulation'] = $this->encapsulation->getEncapsulationByCode('ENCAPSULATION_RAW');
		}

		try
		{
			$response['body']['data'] = $this->encapsulation->encode($response['encapsulation'], $data, $this->password);
		}
		catch (\Exception $e)
		{
			$response['encapsulation'] = $this->encapsulation->getEncapsulationByCode('ENCAPSULATION_RAW');
			$response['body'] = array(
				'status' => $e->getCode(),
				'data' => $e->getMessage(),
			);
		}

		return '###' . json_encode($response) . '###';
	}

	/**
	 * Get the server key, i.e. the Secret Word for the front-end backups and JSON API
	 *
	 * @return  mixed
	 */
	private function serverKey()
	{
		static $key = null;

		if (is_null($key))
		{
			$key = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', '');
		}

		return $key;
	}
}
Model/Browser.php000060400000000564150752453450007753 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\Browser as AdminModel;

class Browser extends AdminModel
{
}
Model/Statistics.php000060400000000572150752453450010461 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\Statistics as AdminModel;

class Statistics extends AdminModel
{
}
Model/DatabaseFilters.php000060400000000604150752453450011360 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\DatabaseFilters as AdminModel;

class DatabaseFilters extends AdminModel
{
}
Model/Backup.php000060400000000563150752453450007534 0ustar00<?php
/**
 * @package   akeebabackup
 * @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\Backup\Site\Model;

// Protect from unauthorized access
defined('_JEXEC') or die();

use Akeeba\Backup\Admin\Model\Backup as AdminModel;

class Backup extends AdminModel
{

}

Youez - 2016 - github.com/yon3zu
LinuXploit