                                                                                                                                                                                
                                                                                                                                                                                
privacy.php                                                                                         0000604                 00000000630 15242100622 0006717 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

$controller = JControllerLegacy::getInstance('Privacy');
$controller->execute(JFactory::getApplication()->input->get('task'));
$controller->redirect();
                                                                                                        controller.php                                                                                      0000604                 00000002646 15242100622 0007436 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Privacy Controller
 *
 * @since  3.9.0
 */
class PrivacyController extends JControllerLegacy
{
	/**
	 * Method to display a view.
	 *
	 * @param   boolean  $cachable   If true, the view output will be cached
	 * @param   array    $urlparams  An array of safe URL parameters and their variable types, for valid values see {@link JFilterInput::clean()}.
	 *
	 * @return  $this
	 *
	 * @since   3.9.0
	 */
	public function display($cachable = false, $urlparams = array())
	{
		$view = $this->input->get('view', $this->default_view);

		// Submitting information requests and confirmation through the frontend is restricted to authenticated users at this time
		if (in_array($view, array('confirm', 'request')) && JFactory::getUser()->guest)
		{
			$this->setRedirect(
				JRoute::_('index.php?option=com_users&view=login&return=' . base64_encode('index.php?option=com_privacy&view=' . $view), false)
			);

			return $this;
		}

		// Set a Referrer-Policy header for views which require it
		if (in_array($view, array('confirm', 'remind')))
		{
			JFactory::getApplication()->setHeader('Referrer-Policy', 'no-referrer', true);
		}

		return parent::display($cachable, $urlparams);
	}
}
                                                                                          router.php                                                                                          0000604                 00000003610 15242100622 0006563 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Routing class from com_privacy
 *
 * @since  3.9.0
 */
class PrivacyRouter extends JComponentRouterView
{
	/**
	 * Privacy Component router constructor
	 *
	 * @param   JApplicationCms  $app   The application object
	 * @param   JMenu            $menu  The menu object to work with
	 *
	 * @since   3.9.0
	 */
	public function __construct($app = null, $menu = null)
	{
		$this->registerView(new JComponentRouterViewconfiguration('confirm'));
		$this->registerView(new JComponentRouterViewconfiguration('request'));
		$this->registerView(new JComponentRouterViewconfiguration('remind'));

		parent::__construct($app, $menu);

		$this->attachRule(new JComponentRouterRulesMenu($this));
		$this->attachRule(new JComponentRouterRulesStandard($this));
		$this->attachRule(new JComponentRouterRulesNomenu($this));
	}
}

/**
 * Privacy router functions
 *
 * These functions are proxies for the new router interface
 * for old SEF extensions.
 *
 * @param   array  &$query  REQUEST query
 *
 * @return  array  Segments of the SEF url
 *
 * @since   3.9.0
 * @deprecated  4.0  Use Class based routers instead
 */
function privacyBuildRoute(&$query)
{
	$app = JFactory::getApplication();
	$router = new PrivacyRouter($app, $app->getMenu());

	return $router->build($query);
}

/**
 * Convert SEF URL segments into query variables
 *
 * @param   array  $segments  Segments in the current URL
 *
 * @return  array  Query variables
 *
 * @since   3.9.0
 * @deprecated  4.0  Use Class based routers instead
 */
function privacyParseRoute($segments)
{
	$app = JFactory::getApplication();
	$router = new PrivacyRouter($app, $app->getMenu());

	return $router->parse($segments);
}
                                                                                                                        controllers/request.php                                                                             0000604                 00000010443 15242100622 0011303 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Request action controller class.
 *
 * @since  3.9.0
 */
class PrivacyControllerRequest extends JControllerLegacy
{
	/**
	 * Method to confirm the information request.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function confirm()
	{
		// Check the request token.
		$this->checkToken('post');

		/** @var PrivacyModelConfirm $model */
		$model = $this->getModel('Confirm', 'PrivacyModel');
		$data  = $this->input->post->get('jform', array(), 'array');

		$return	= $model->confirmRequest($data);

		// Check for a hard error.
		if ($return instanceof Exception)
		{
			// Get the error message to display.
			if (JFactory::getApplication()->get('error_reporting'))
			{
				$message = $return->getMessage();
			}
			else
			{
				$message = JText::_('COM_PRIVACY_ERROR_CONFIRMING_REQUEST');
			}

			// Go back to the confirm form.
			$this->setRedirect(JRoute::_('index.php?option=com_privacy&view=confirm', false), $message, 'error');

			return false;
		}
		elseif ($return === false)
		{
			// Confirm failed.
			// Go back to the confirm form.
			$message = JText::sprintf('COM_PRIVACY_ERROR_CONFIRMING_REQUEST_FAILED', $model->getError());
			$this->setRedirect(JRoute::_('index.php?option=com_privacy&view=confirm', false), $message, 'notice');

			return false;
		}
		else
		{
			// Confirm succeeded.
			$this->setRedirect(JRoute::_(JUri::root()), JText::_('COM_PRIVACY_CONFIRM_REQUEST_SUCCEEDED'), 'info');

			return true;
		}
	}

	/**
	 * Method to submit an information request.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function submit()
	{
		// Check the request token.
		$this->checkToken('post');

		/** @var PrivacyModelRequest $model */
		$model = $this->getModel('Request', 'PrivacyModel');
		$data  = $this->input->post->get('jform', array(), 'array');

		$return	= $model->createRequest($data);

		// Check for a hard error.
		if ($return instanceof Exception)
		{
			// Get the error message to display.
			if (JFactory::getApplication()->get('error_reporting'))
			{
				$message = $return->getMessage();
			}
			else
			{
				$message = JText::_('COM_PRIVACY_ERROR_CREATING_REQUEST');
			}

			// Go back to the confirm form.
			$this->setRedirect(JRoute::_('index.php?option=com_privacy&view=request', false), $message, 'error');

			return false;
		}
		elseif ($return === false)
		{
			// Confirm failed.
			// Go back to the confirm form.
			$message = JText::sprintf('COM_PRIVACY_ERROR_CREATING_REQUEST_FAILED', $model->getError());
			$this->setRedirect(JRoute::_('index.php?option=com_privacy&view=request', false), $message, 'notice');

			return false;
		}
		else
		{
			// Confirm succeeded.
			$this->setRedirect(JRoute::_(JUri::root()), JText::_('COM_PRIVACY_CREATE_REQUEST_SUCCEEDED'), 'info');

			return true;
		}
	}

	/**
	 * Method to extend the privacy consent.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function remind()
	{
		// Check the request token.
		$this->checkToken('post');

		/** @var PrivacyModelConfirm $model */
		$model = $this->getModel('Remind', 'PrivacyModel');
		$data  = $this->input->post->get('jform', array(), 'array');

		$return	= $model->remindRequest($data);

		// Check for a hard error.
		if ($return instanceof Exception)
		{
			// Get the error message to display.
			if (JFactory::getApplication()->get('error_reporting'))
			{
				$message = $return->getMessage();
			}
			else
			{
				$message = JText::_('COM_PRIVACY_ERROR_REMIND_REQUEST');
			}

			// Go back to the confirm form.
			$this->setRedirect(JRoute::_('index.php?option=com_privacy&view=remind', false), $message, 'error');

			return false;
		}
		elseif ($return === false)
		{
			// Confirm failed.
			// Go back to the confirm form.
			$message = JText::sprintf('COM_PRIVACY_ERROR_CONFIRMING_REMIND_FAILED', $model->getError());
			$this->setRedirect(JRoute::_('index.php?option=com_privacy&view=remind', false), $message, 'notice');

			return false;
		}
		else
		{
			// Confirm succeeded.
			$this->setRedirect(JRoute::_(JUri::root()), JText::_('COM_PRIVACY_CONFIRM_REMIND_SUCCEEDED'), 'info');

			return true;
		}
	}
}
                                                                                                                                                                                                                             models/remind.php                                                                                   0000604                 00000010055 15242100622 0010005 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Remind confirmation model class.
 *
 * @since  3.9.0
 */
class PrivacyModelRemind extends JModelAdmin
{
	/**
	 * Confirms the remind request.
	 *
	 * @param   array  $data  The data expected for the form.
	 *
	 * @return  mixed  Exception | JException | boolean
	 *
	 * @since   3.9.0
	 */
	public function remindRequest($data)
	{
		// Get the form.
		$form = $this->getForm();
		$data['email'] = JStringPunycode::emailToPunycode($data['email']);

		// Check for an error.
		if ($form instanceof Exception)
		{
			return $form;
		}

		// Filter and validate the form data.
		$data = $form->filter($data);
		$return = $form->validate($data);

		// Check for an error.
		if ($return instanceof Exception)
		{
			return $return;
		}

		// Check the validation results.
		if ($return === false)
		{
			// Get the validation messages from the form.
			foreach ($form->getErrors() as $formError)
			{
				$this->setError($formError->getMessage());
			}

			return false;
		}

		/** @var PrivacyTableConsent $table */
		$table = $this->getTable();

		$db = $this->getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName(array('r.id', 'r.user_id', 'r.token')));
		$query->from($db->quoteName('#__privacy_consents', 'r'));
		$query->join('LEFT', $db->quoteName('#__users', 'u') . ' ON u.id = r.user_id');
		$query->where($db->quoteName('u.email') . ' = ' . $db->quote($data['email']));
		$query->where($db->quoteName('r.remind') . ' = 1');
		$db->setQuery($query);

		try
		{
			$remind = $db->loadObject();
		}
		catch (RuntimeException $e)
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REMIND'));

			return false;
		}

		if (!$remind)
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REMIND'));

			return false;
		}

		// Verify the token
		if (!JUserHelper::verifyPassword($data['remind_token'], $remind->token))
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_REMIND_REQUESTS'));

			return false;
		}

		// Everything is good to go, transition the request to extended
		$saved = $this->save(
			array(
				'id'      => $remind->id,
				'remind'  => 0,
				'token'   => '',
				'created' => JFactory::getDate()->toSql(),
			)
		);

		if (!$saved)
		{
			// Error was set by the save method
			return false;
		}

		return true;
	}

	/**
	 * Method for getting the form from the model.
	 *
	 * @param   array    $data      Data for the form.
	 * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
	 *
	 * @return  JForm|boolean  A JForm object on success, false on failure
	 *
	 * @since   3.9.0
	 */
	public function getForm($data = array(), $loadData = true)
	{
		// Get the form.
		$form = $this->loadForm('com_privacy.remind', 'remind', array('control' => 'jform'));

		if (empty($form))
		{
			return false;
		}

		$input = JFactory::getApplication()->input;

		if ($input->getMethod() === 'GET')
		{
			$form->setValue('remind_token', '', $input->get->getAlnum('remind_token'));
		}

		return $form;
	}

	/**
	 * Method to get a table object, load it if necessary.
	 *
	 * @param   string  $name     The table name. Optional.
	 * @param   string  $prefix   The class prefix. Optional.
	 * @param   array   $options  Configuration array for model. Optional.
	 *
	 * @return  JTable  A JTable object
	 *
	 * @since   3.9.0
	 * @throws  \Exception
	 */
	public function getTable($name = 'Consent', $prefix = 'PrivacyTable', $options = array())
	{
		return parent::getTable($name, $prefix, $options);
	}

	/**
	 * Method to auto-populate the model state.
	 *
	 * Note. Calling getState in this method will result in recursion.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function populateState()
	{
		// Get the application object.
		$params = JFactory::getApplication()->getParams('com_privacy');

		// Load the parameters.
		$this->setState('params', $params);
	}
}
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   models/forms/confirm.xml                                                                            0000604                 00000000557 15242100622 0011331 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset name="default" label="COM_PRIVACY_CONFIRM_REQUEST_FIELDSET_LABEL">
		<field
			name="confirm_token"
			type="text"
			label="COM_PRIVACY_FIELD_CONFIRM_CONFIRM_TOKEN_LABEL"
			description="COM_PRIVACY_FIELD_CONFIRM_CONFIRM_TOKEN_DESC"
			filter="alnum"
			required="true"
			size="32"
		/>
	</fieldset>
</form>
                                                                                                                                                 models/forms/request.xml                                                                            0000604                 00000000705 15242100622 0011357 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset name="default">
		<field
			name="request_type"
			type="list"
			label="COM_PRIVACY_FIELD_REQUEST_TYPE_LABEL"
			description="COM_PRIVACY_FIELD_REQUEST_TYPE_DESC"
			filter="string"
			default="export"
			validate="options"
			>
			<option value="export">COM_PRIVACY_REQUEST_TYPE_EXPORT</option>
			<option value="remove">COM_PRIVACY_REQUEST_TYPE_REMOVE</option>
		</field>
	</fieldset>
</form>
                                                           models/forms/remind.xml                                                                             0000604                 00000001034 15242100622 0011141 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset name="default" label="COM_PRIVACY_REMIND_REQUEST_FIELDSET_LABEL">
		<field
			name="email"
			type="text"
			label="JGLOBAL_EMAIL"
			description="COM_PRIVACY_FIELD_CONFIRM_EMAIL_DESC"
			validate="email"
			required="true"
			size="30"
		/>

		<field
			name="remind_token"
			type="text"
			label="COM_PRIVACY_FIELD_REMIND_CONFIRM_TOKEN_LABEL"
			description="COM_PRIVACY_FIELD_REMIND_CONFIRM_TOKEN_DESC"
			filter="alnum"
			required="true"
			size="32"
		/>
	</fieldset>
</form>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    models/confirm.php                                                                                  0000604                 00000013151 15242100622 0010164 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Request confirmation model class.
 *
 * @since  3.9.0
 */
class PrivacyModelConfirm extends JModelAdmin
{
	/**
	 * Confirms the information request.
	 *
	 * @param   array  $data  The data expected for the form.
	 *
	 * @return  mixed  Exception | JException | boolean
	 *
	 * @since   3.9.0
	 */
	public function confirmRequest($data)
	{
		// Get the form.
		$form = $this->getForm();

		// Check for an error.
		if ($form instanceof Exception)
		{
			return $form;
		}

		// Filter and validate the form data.
		$data = $form->filter($data);
		$return = $form->validate($data);

		// Check for an error.
		if ($return instanceof Exception)
		{
			return $return;
		}

		// Check the validation results.
		if ($return === false)
		{
			// Get the validation messages from the form.
			foreach ($form->getErrors() as $formError)
			{
				$this->setError($formError->getMessage());
			}

			return false;
		}

		// Get the user email address
		$data['email'] = JFactory::getUser()->email;

		// Search for the information request
		/** @var PrivacyTableRequest $table */
		$table = $this->getTable();

		if (!$table->load(array('email' => $data['email'], 'status' => 0)))
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REQUESTS'));

			return false;
		}

		// A request can only be confirmed if it is in a pending status and has a confirmation token
		if ($table->status != '0' || !$table->confirm_token)
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REQUESTS'));

			return false;
		}

		// A request can only be confirmed if the token is less than 24 hours old
		$confirmTokenCreatedAt = new JDate($table->confirm_token_created_at);
		$confirmTokenCreatedAt->add(new DateInterval('P1D'));

		$now = new JDate('now');

		if ($now > $confirmTokenCreatedAt)
		{
			// Invalidate the request
			$table->status = -1;
			$table->confirm_token = '';

			try
			{
				$table->store();
			}
			catch (JDatabaseException $exception)
			{
				// The error will be logged in the database API, we just need to catch it here to not let things fatal out
			}

			$this->setError(JText::_('COM_PRIVACY_ERROR_CONFIRM_TOKEN_EXPIRED'));

			return false;
		}

		// Verify the token
		if (!JUserHelper::verifyPassword($data['confirm_token'], $table->confirm_token))
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_NO_PENDING_REQUESTS'));

			return false;
		}

		// Everything is good to go, transition the request to confirmed
		$saved = $this->save(
			array(
				'id'     => $table->id,
				'status' => 1,
				'confirm_token' => '',
			)
		);

		if (!$saved)
		{
			// Error was set by the save method
			return false;
		}

		// Push a notification to the site's super users, deliberately ignoring if this process fails so the below message goes out
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/models', 'MessagesModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/tables');

		/** @var MessagesModelMessage $messageModel */
		$messageModel = JModelLegacy::getInstance('Message', 'MessagesModel');

		$messageModel->notifySuperUsers(
			JText::_('COM_PRIVACY_ADMIN_NOTIFICATION_USER_CONFIRMED_REQUEST_SUBJECT'),
			JText::sprintf('COM_PRIVACY_ADMIN_NOTIFICATION_USER_CONFIRMED_REQUEST_MESSAGE', $table->email)
		);

		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

		$message = array(
			'action'       => 'request-confirmed',
			'subjectemail' => $table->email,
			'id'           => $table->id,
			'itemlink'     => 'index.php?option=com_privacy&view=request&id=' . $table->id,
		);

		/** @var ActionlogsModelActionlog $model */
		$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
		$model->addLog(array($message), 'COM_PRIVACY_ACTION_LOG_CONFIRMED_REQUEST', 'com_privacy.request');

		return true;
	}

	/**
	 * Method for getting the form from the model.
	 *
	 * @param   array    $data      Data for the form.
	 * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
	 *
	 * @return  JForm|boolean  A JForm object on success, false on failure
	 *
	 * @since   3.9.0
	 */
	public function getForm($data = array(), $loadData = true)
	{
		// Get the form.
		$form = $this->loadForm('com_privacy.confirm', 'confirm', array('control' => 'jform'));

		if (empty($form))
		{
			return false;
		}

		$input = JFactory::getApplication()->input;

		if ($input->getMethod() === 'GET')
		{
			$form->setValue('confirm_token', '', $input->get->getAlnum('confirm_token'));
		}

		return $form;
	}

	/**
	 * Method to get a table object, load it if necessary.
	 *
	 * @param   string  $name     The table name. Optional.
	 * @param   string  $prefix   The class prefix. Optional.
	 * @param   array   $options  Configuration array for model. Optional.
	 *
	 * @return  JTable  A JTable object
	 *
	 * @since   3.9.0
	 * @throws  \Exception
	 */
	public function getTable($name = 'Request', $prefix = 'PrivacyTable', $options = array())
	{
		return parent::getTable($name, $prefix, $options);
	}

	/**
	 * Method to auto-populate the model state.
	 *
	 * Note. Calling getState in this method will result in recursion.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function populateState()
	{
		// Get the application object.
		$params = JFactory::getApplication()->getParams('com_privacy');

		// Load the parameters.
		$this->setState('params', $params);
	}
}
                                                                                                                                                                                                                                                                                                                                                                                                                       models/request.php                                                                                  0000604                 00000016533 15242100622 0010226 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Router\Route;

/**
 * Request model class.
 *
 * @since  3.9.0
 */
class PrivacyModelRequest extends JModelAdmin
{
	/**
	 * Creates an information request.
	 *
	 * @param   array  $data  The data expected for the form.
	 *
	 * @return  mixed  Exception | JException | boolean
	 *
	 * @since   3.9.0
	 */
	public function createRequest($data)
	{
		// Creating requests requires the site's email sending be enabled
		if (!JFactory::getConfig()->get('mailonline', 1))
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_CANNOT_CREATE_REQUEST_WHEN_SENDMAIL_DISABLED'));

			return false;
		}

		// Get the form.
		$form = $this->getForm();		

		// Check for an error.
		if ($form instanceof Exception)
		{
			return $form;
		}

		// Filter and validate the form data.
		$data = $form->filter($data);
		$return = $form->validate($data);

		// Check for an error.
		if ($return instanceof Exception)
		{
			return $return;
		}

		// Check the validation results.
		if ($return === false)
		{
			// Get the validation messages from the form.
			foreach ($form->getErrors() as $formError)
			{
				$this->setError($formError->getMessage());
			}

			return false;
		}

		// Get the user email address
		$data['email'] = JFactory::getUser()->email;

		// Search for an open information request matching the email and type
		$db = $this->getDbo();
		$query = $db->getQuery(true)
			->select('COUNT(id)')
			->from('#__privacy_requests')
			->where('email = ' . $db->quote($data['email']))
			->where('request_type = ' . $db->quote($data['request_type']))
			->where('status IN (0, 1)');

		try
		{
			$result = (int) $db->setQuery($query)->loadResult();
		}
		catch (JDatabaseException $exception)
		{
			// Can't check for existing requests, so don't create a new one
			$this->setError(JText::_('COM_PRIVACY_ERROR_CHECKING_FOR_EXISTING_REQUESTS'));

			return false;
		}

		if ($result > 0)
		{
			$this->setError(JText::_('COM_PRIVACY_ERROR_PENDING_REQUEST_OPEN'));

			return false;
		}

		// Everything is good to go, create the request
		$token       = JApplicationHelper::getHash(JUserHelper::genRandomPassword());
		$hashedToken = JUserHelper::hashPassword($token);

		$data['confirm_token']            = $hashedToken;
		$data['confirm_token_created_at'] = JFactory::getDate()->toSql();

		if (!$this->save($data))
		{
			// The save function will set the error message, so just return here
			return false;
		}

		// Push a notification to the site's super users, deliberately ignoring if this process fails so the below message goes out
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/models', 'MessagesModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_messages/tables');

		/** @var MessagesModelMessage $messageModel */
		$messageModel = JModelLegacy::getInstance('Message', 'MessagesModel');

		$messageModel->notifySuperUsers(
			JText::_('COM_PRIVACY_ADMIN_NOTIFICATION_USER_CREATED_REQUEST_SUBJECT'),
			JText::sprintf('COM_PRIVACY_ADMIN_NOTIFICATION_USER_CREATED_REQUEST_MESSAGE', $data['email'])
		);

		// The mailer can be set to either throw Exceptions or return boolean false, account for both
		try
		{
			$app = JFactory::getApplication();

			$linkMode = $app->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE;

			$substitutions = array(
				'[SITENAME]' => $app->get('sitename'),
				'[URL]'      => JUri::root(),
				'[TOKENURL]' => JRoute::link('site', 'index.php?option=com_privacy&view=confirm&confirm_token=' . $token, false, $linkMode, true),
				'[FORMURL]'  => JRoute::link('site', 'index.php?option=com_privacy&view=confirm', false, $linkMode, true),
				'[TOKEN]'    => $token,
				'\\n'        => "\n",
			);

			switch ($data['request_type'])
			{
				case 'export':
					$emailSubject = JText::_('COM_PRIVACY_EMAIL_REQUEST_SUBJECT_EXPORT_REQUEST');
					$emailBody    = JText::_('COM_PRIVACY_EMAIL_REQUEST_BODY_EXPORT_REQUEST');

					break;

				case 'remove':
					$emailSubject = JText::_('COM_PRIVACY_EMAIL_REQUEST_SUBJECT_REMOVE_REQUEST');
					$emailBody    = JText::_('COM_PRIVACY_EMAIL_REQUEST_BODY_REMOVE_REQUEST');

					break;

				default:
					$this->setError(JText::_('COM_PRIVACY_ERROR_UNKNOWN_REQUEST_TYPE'));

					return false;
			}

			foreach ($substitutions as $k => $v)
			{
				$emailSubject = str_replace($k, $v, $emailSubject);
				$emailBody    = str_replace($k, $v, $emailBody);
			}

			$mailer = JFactory::getMailer();
			$mailer->setSubject($emailSubject);
			$mailer->setBody($emailBody);
			$mailer->addRecipient($data['email']);

			$mailResult = $mailer->Send();

			if ($mailResult instanceof JException)
			{
				// JError was already called so we just need to return now
				return false;
			}
			elseif ($mailResult === false)
			{
				$this->setError($mailer->ErrorInfo);

				return false;
			}

			/** @var PrivacyTableRequest $table */
			$table = $this->getTable();

			if (!$table->load($this->getState($this->getName() . '.id')))
			{
				$this->setError($table->getError());

				return false;
			}

			// Log the request's creation
			JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_actionlogs/models', 'ActionlogsModel');

			$message = array(
				'action'       => 'request-created',
				'requesttype'  => $table->request_type,
				'subjectemail' => $table->email,
				'id'           => $table->id,
				'itemlink'     => 'index.php?option=com_privacy&view=request&id=' . $table->id,
			);

			/** @var ActionlogsModelActionlog $model */
			$model = JModelLegacy::getInstance('Actionlog', 'ActionlogsModel');
			$model->addLog(array($message), 'COM_PRIVACY_ACTION_LOG_CREATED_REQUEST', 'com_privacy.request');

			// The email sent and the record is saved, everything is good to go from here
			return true;
		}
		catch (phpmailerException $exception)
		{
			$this->setError($exception->getMessage());

			return false;
		}
	}

	/**
	 * Method for getting the form from the model.
	 *
	 * @param   array    $data      Data for the form.
	 * @param   boolean  $loadData  True if the form is to load its own data (default case), false if not.
	 *
	 * @return  JForm|boolean  A JForm object on success, false on failure
	 *
	 * @since   3.9.0
	 */
	public function getForm($data = array(), $loadData = true)
	{
		return $this->loadForm('com_privacy.request', 'request', array('control' => 'jform'));
	}

	/**
	 * Method to get a table object, load it if necessary.
	 *
	 * @param   string  $name     The table name. Optional.
	 * @param   string  $prefix   The class prefix. Optional.
	 * @param   array   $options  Configuration array for model. Optional.
	 *
	 * @return  JTable  A JTable object
	 *
	 * @since   3.9.0
	 * @throws  \Exception
	 */
	public function getTable($name = 'Request', $prefix = 'PrivacyTable', $options = array())
	{
		return parent::getTable($name, $prefix, $options);
	}

	/**
	 * Method to auto-populate the model state.
	 *
	 * Note. Calling getState in this method will result in recursion.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function populateState()
	{
		// Get the application object.
		$params = JFactory::getApplication()->getParams('com_privacy');

		// Load the parameters.
		$this->setState('params', $params);
	}
}
                                                                                                                                                                     views/confirm/tmpl/default.xml                                                                      0000604                 00000000505 15242100622 0012446 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?xml version="1.0" encoding="utf-8"?>
<metadata>
	<layout title="COM_PRIVACY_CONFIRM_VIEW_DEFAULT_TITLE" option="COM_PRIVACY_CONFIRM_VIEW_DEFAULT_OPTION">
		<help
			key="JHELP_MENUS_MENU_ITEM_PRIVACY_CONFIRM_REQUEST"
		/>
		<message>
			<![CDATA[COM_PRIVACY_CONFIRM_VIEW_DEFAULT_DESC]]>
		</message>
	</layout>
</metadata>
                                                                                                                                                                                           views/confirm/tmpl/default.php                                                                      0000604                 00000002466 15242100622 0012445 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/** @var PrivacyViewConfirm $this */

JHtml::_('behavior.keepalive');
JHtml::_('behavior.formvalidator');

?>
<div class="request-confirm<?php echo $this->pageclass_sfx; ?>">
	<?php if ($this->params->get('show_page_heading')) : ?>
		<div class="page-header">
			<h1>
				<?php echo $this->escape($this->params->get('page_heading')); ?>
			</h1>
		</div>
	<?php endif; ?>
	<form action="<?php echo JRoute::_('index.php?option=com_privacy&task=request.confirm'); ?>" method="post" class="form-validate form-horizontal well">
		<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
			<fieldset>
				<?php if (!empty($fieldset->label)) : ?>
					<legend><?php echo JText::_($fieldset->label); ?></legend>
				<?php endif; ?>
				<?php echo $this->form->renderFieldset($fieldset->name); ?>
			</fieldset>
		<?php endforeach; ?>
		<div class="control-group">
			<div class="controls">
				<button type="submit" class="btn btn-primary validate">
					<?php echo JText::_('JSUBMIT'); ?>
				</button>
			</div>
		</div>
		<?php echo JHtml::_('form.token'); ?>
	</form>
</div>
                                                                                                                                                                                                          views/confirm/view.html.php                                                                         0000604                 00000005765 15242100622 0011767 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

/**
 * Request confirmation view class
 *
 * @since  3.9.0
 */
class PrivacyViewConfirm extends JViewLegacy
{
	/**
	 * The form object
	 *
	 * @var    JForm
	 * @since  3.9.0
	 */
	protected $form;

	/**
	 * The CSS class suffix to append to the view container
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $pageclass_sfx;

	/**
	 * The view parameters
	 *
	 * @var    Registry
	 * @since  3.9.0
	 */
	protected $params;

	/**
	 * The state information
	 *
	 * @var    JObject
	 * @since  3.9.0
	 */
	protected $state;

	/**
	 * Execute and display a template script.
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		// Initialise variables.
		$this->form   = $this->get('Form');
		$this->state  = $this->get('State');
		$this->params = $this->state->params;

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		// Escape strings for HTML output
		$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''), ENT_COMPAT, 'UTF-8');

		$this->prepareDocument();

		return parent::display($tpl);
	}

	/**
	 * Prepares the document.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function prepareDocument()
	{
		$app   = JFactory::getApplication();
		$menus = $app->getMenu();
		$title = null;

		// Because the application sets a default page title,
		// we need to get it from the menu item itself
		$menu = $menus->getActive();

		if ($menu)
		{
			$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
		}
		else
		{
			$this->params->def('page_heading', JText::_('COM_PRIVACY_VIEW_CONFIRM_PAGE_TITLE'));
		}

		$title = $this->params->get('page_title', '');

		if (empty($title))
		{
			$title = $app->get('sitename');
		}
		elseif ($app->get('sitename_pagetitles', 0) == 1)
		{
			$title = JText::sprintf('JPAGETITLE', $app->get('sitename'), $title);
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2)
		{
			$title = JText::sprintf('JPAGETITLE', $title, $app->get('sitename'));
		}

		$this->document->setTitle($title);

		if ($this->params->get('menu-meta_description'))
		{
			$this->document->setDescription($this->params->get('menu-meta_description'));
		}

		if ($this->params->get('menu-meta_keywords'))
		{
			$this->document->setMetadata('keywords', $this->params->get('menu-meta_keywords'));
		}

		if ($this->params->get('robots'))
		{
			$this->document->setMetadata('robots', $this->params->get('robots'));
		}
	}
}
           views/request/tmpl/default.php                                                                      0000604                 00000003114 15242100622 0012467 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/** @var PrivacyViewRequest $this */

JHtml::_('behavior.keepalive');
JHtml::_('behavior.formvalidator');
JHtml::_('formbehavior.chosen', 'select');

?>
<div class="request-form<?php echo $this->pageclass_sfx; ?>">
	<?php if ($this->params->get('show_page_heading')) : ?>
		<div class="page-header">
			<h1>
				<?php echo $this->escape($this->params->get('page_heading')); ?>
			</h1>
		</div>
	<?php endif; ?>
	<?php if ($this->sendMailEnabled) : ?>
		<form action="<?php echo JRoute::_('index.php?option=com_privacy&task=request.submit'); ?>" method="post" class="form-validate form-horizontal well">
			<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
				<fieldset>
					<?php if (!empty($fieldset->label)) : ?>
						<legend><?php echo JText::_($fieldset->label); ?></legend>
					<?php endif; ?>
					<?php echo $this->form->renderFieldset($fieldset->name); ?>
				</fieldset>
			<?php endforeach; ?>
			<div class="control-group">
				<div class="controls">
					<button type="submit" class="btn btn-primary validate">
						<?php echo JText::_('JSUBMIT'); ?>
					</button>
				</div>
			</div>
			<?php echo JHtml::_('form.token'); ?>
		</form>
	<?php else : ?>
		<div class="alert alert-warning">
			<p><?php echo JText::_('COM_PRIVACY_WARNING_CANNOT_CREATE_REQUEST_WHEN_SENDMAIL_DISABLED'); ?></p>
		</div>
	<?php endif; ?>
</div>
                                                                                                                                                                                                                                                                                                                                                                                                                                                    views/request/tmpl/default.xml                                                                      0000604                 00000000504 15242100622 0012500 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?xml version="1.0" encoding="utf-8"?>
<metadata>
	<layout title="COM_PRIVACY_REQUEST_VIEW_DEFAULT_TITLE" option="COM_PRIVACY_REQUEST_VIEW_DEFAULT_OPTION">
		<help
			key="JHELP_MENUS_MENU_ITEM_PRIVACY_CREATE_REQUEST"
		/>
		<message>
			<![CDATA[COM_PRIVACY_REQUEST_VIEW_DEFAULT_DESC]]>
		</message>
	</layout>
</metadata>
                                                                                                                                                                                            views/request/view.html.php                                                                         0000604                 00000006330 15242100622 0012007 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

/**
 * Request view class
 *
 * @since  3.9.0
 */
class PrivacyViewRequest extends JViewLegacy
{
	/**
	 * The form object
	 *
	 * @var    JForm
	 * @since  3.9.0
	 */
	protected $form;

	/**
	 * The CSS class suffix to append to the view container
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $pageclass_sfx;

	/**
	 * The view parameters
	 *
	 * @var    Registry
	 * @since  3.9.0
	 */
	protected $params;

	/**
	 * Flag indicating the site supports sending email
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $sendMailEnabled;

	/**
	 * The state information
	 *
	 * @var    JObject
	 * @since  3.9.0
	 */
	protected $state;

	/**
	 * Execute and display a template script.
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		// Initialise variables.
		$this->form            = $this->get('Form');
		$this->state           = $this->get('State');
		$this->params          = $this->state->params;
		$this->sendMailEnabled = (bool) JFactory::getConfig()->get('mailonline', 1);

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		// Escape strings for HTML output
		$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''), ENT_COMPAT, 'UTF-8');

		$this->prepareDocument();

		return parent::display($tpl);
	}

	/**
	 * Prepares the document.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function prepareDocument()
	{
		$app   = JFactory::getApplication();
		$menus = $app->getMenu();
		$title = null;

		// Because the application sets a default page title,
		// we need to get it from the menu item itself
		$menu = $menus->getActive();

		if ($menu)
		{
			$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
		}
		else
		{
			$this->params->def('page_heading', JText::_('COM_PRIVACY_VIEW_REQUEST_PAGE_TITLE'));
		}

		$title = $this->params->get('page_title', '');

		if (empty($title))
		{
			$title = $app->get('sitename');
		}
		elseif ($app->get('sitename_pagetitles', 0) == 1)
		{
			$title = JText::sprintf('JPAGETITLE', $app->get('sitename'), $title);
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2)
		{
			$title = JText::sprintf('JPAGETITLE', $title, $app->get('sitename'));
		}

		$this->document->setTitle($title);

		if ($this->params->get('menu-meta_description'))
		{
			$this->document->setDescription($this->params->get('menu-meta_description'));
		}

		if ($this->params->get('menu-meta_keywords'))
		{
			$this->document->setMetadata('keywords', $this->params->get('menu-meta_keywords'));
		}

		if ($this->params->get('robots'))
		{
			$this->document->setMetadata('robots', $this->params->get('robots'));
		}
	}
}
                                                                                                                                                                                                                                                                                                        views/remind/view.html.php                                                                          0000604                 00000005762 15242100622 0011605 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

/**
 * Remind confirmation view class
 *
 * @since  3.9.0
 */
class PrivacyViewRemind extends JViewLegacy
{
	/**
	 * The form object
	 *
	 * @var    JForm
	 * @since  3.9.0
	 */
	protected $form;

	/**
	 * The CSS class suffix to append to the view container
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $pageclass_sfx;

	/**
	 * The view parameters
	 *
	 * @var    Registry
	 * @since  3.9.0
	 */
	protected $params;

	/**
	 * The state information
	 *
	 * @var    JObject
	 * @since  3.9.0
	 */
	protected $state;

	/**
	 * Execute and display a template script.
	 *
	 * @param   string  $tpl  The name of the template file to parse; automatically searches through the template paths.
	 *
	 * @return  mixed  A string if successful, otherwise an Error object.
	 *
	 * @see     JViewLegacy::loadTemplate()
	 * @since   3.9.0
	 * @throws  Exception
	 */
	public function display($tpl = null)
	{
		// Initialise variables.
		$this->form   = $this->get('Form');
		$this->state  = $this->get('State');
		$this->params = $this->state->params;

		// Check for errors.
		if (count($errors = $this->get('Errors')))
		{
			throw new Exception(implode("\n", $errors), 500);
		}

		// Escape strings for HTML output
		$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''), ENT_COMPAT, 'UTF-8');

		$this->prepareDocument();

		return parent::display($tpl);
	}

	/**
	 * Prepares the document.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	protected function prepareDocument()
	{
		$app   = JFactory::getApplication();
		$menus = $app->getMenu();
		$title = null;

		// Because the application sets a default page title,
		// we need to get it from the menu item itself
		$menu = $menus->getActive();

		if ($menu)
		{
			$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
		}
		else
		{
			$this->params->def('page_heading', JText::_('COM_PRIVACY_VIEW_REMIND_PAGE_TITLE'));
		}

		$title = $this->params->get('page_title', '');

		if (empty($title))
		{
			$title = $app->get('sitename');
		}
		elseif ($app->get('sitename_pagetitles', 0) == 1)
		{
			$title = JText::sprintf('JPAGETITLE', $app->get('sitename'), $title);
		}
		elseif ($app->get('sitename_pagetitles', 0) == 2)
		{
			$title = JText::sprintf('JPAGETITLE', $title, $app->get('sitename'));
		}

		$this->document->setTitle($title);

		if ($this->params->get('menu-meta_description'))
		{
			$this->document->setDescription($this->params->get('menu-meta_description'));
		}

		if ($this->params->get('menu-meta_keywords'))
		{
			$this->document->setMetadata('keywords', $this->params->get('menu-meta_keywords'));
		}

		if ($this->params->get('robots'))
		{
			$this->document->setMetadata('robots', $this->params->get('robots'));
		}
	}
}
              views/remind/tmpl/default.xml                                                                       0000604                 00000000501 15242100622 0012263 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?xml version="1.0" encoding="utf-8"?>
<metadata>
	<layout title="COM_PRIVACY_REMIND_VIEW_DEFAULT_TITLE" option="COM_PRIVACY_REMIND_VIEW_DEFAULT_OPTION">
		<help
			key="JHELP_MENUS_MENU_ITEM_PRIVACY_REMIND_REQUEST"
		/>
		<message>
			<![CDATA[COM_PRIVACY_REMIND_VIEW_DEFAULT_DESC]]>
		</message>
	</layout>
</metadata>
                                                                                                                                                                                               views/remind/tmpl/default.php                                                                       0000604                 00000002464 15242100622 0012264 0                                                                                                    ustar 00                                                                                                                                                                                                                                                       <?php
/**
 * @package     Joomla.Site
 * @subpackage  com_privacy
 *
 * @copyright   (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('_JEXEC') or die;

/** @var PrivacyViewConfirm $this */

JHtml::_('behavior.keepalive');
JHtml::_('behavior.formvalidator');

?>
<div class="remind-confirm<?php echo $this->pageclass_sfx; ?>">
	<?php if ($this->params->get('show_page_heading')) : ?>
		<div class="page-header">
			<h1>
				<?php echo $this->escape($this->params->get('page_heading')); ?>
			</h1>
		</div>
	<?php endif; ?>
	<form action="<?php echo JRoute::_('index.php?option=com_privacy&task=request.remind'); ?>" method="post" class="form-validate form-horizontal well">
		<?php foreach ($this->form->getFieldsets() as $fieldset) : ?>
			<fieldset>
				<?php if (!empty($fieldset->label)) : ?>
					<legend><?php echo JText::_($fieldset->label); ?></legend>
				<?php endif; ?>
				<?php echo $this->form->renderFieldset($fieldset->name); ?>
			</fieldset>
		<?php endforeach; ?>
		<div class="control-group">
			<div class="controls">
				<button type="submit" class="btn btn-primary validate">
					<?php echo JText::_('JSUBMIT'); ?>
				</button>
			</div>
		</div>
		<?php echo JHtml::_('form.token'); ?>
	</form>
</div>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            