primo commit

This commit is contained in:
2024-12-17 17:34:10 +01:00
commit e650f8df99
16435 changed files with 2451012 additions and 0 deletions

View File

@ -0,0 +1,26 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\Component\Users\Administrator\Controller\CallbackController as AdminCallbackController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Multi-factor Authentication plugins' AJAX callback controller
*
* @since 4.2.0
*/
class CallbackController extends AdminCallbackController
{
}

View File

@ -0,0 +1,55 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\CMS\Router\Route;
use Joomla\Component\Users\Administrator\Controller\CaptiveController as AdminCaptiveController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Captive Multi-factor Authentication page controller
*
* @since 4.2.0
*/
class CaptiveController extends AdminCaptiveController
{
/**
* Execute a task by triggering a Method in the derived class.
*
* @param string $task The task to perform.
*
* @return mixed The value returned by the called Method.
*
* @throws \Exception
* @since 4.2.0
*/
public function execute($task)
{
try {
return parent::execute($task);
} catch (\Exception $e) {
if ($e->getCode() !== 403) {
throw $e;
}
if ($this->app->getIdentity()->guest) {
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
return null;
}
}
return null;
}
}

View File

@ -0,0 +1,139 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Router\Route;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Base controller class for Users.
*
* @since 1.5
*/
class DisplayController extends BaseController
{
/**
* Method to display a view.
*
* @param boolean $cachable If true, the view output will be cached
* @param array|boolean $urlparams An array of safe URL parameters and their variable types.
* @see \Joomla\CMS\Filter\InputFilter::clean() for valid values.
*
* @return void
*
* @since 1.5
* @throws \Exception
*/
public function display($cachable = false, $urlparams = false)
{
// Get the document object.
$document = $this->app->getDocument();
// Set the default view name and format from the Request.
$vName = $this->input->getCmd('view', 'login');
$vFormat = $document->getType();
$lName = $this->input->getCmd('layout', 'default');
if ($view = $this->getView($vName, $vFormat)) {
// Do any specific processing by view.
switch ($vName) {
case 'registration':
// If the user is already logged in, redirect to the profile page.
$user = $this->app->getIdentity();
if ($user->guest != 1) {
// Redirect to profile page.
$this->setRedirect(Route::_('index.php?option=com_users&view=profile', false));
return;
}
// Check if user registration is enabled
if (ComponentHelper::getParams('com_users')->get('allowUserRegistration') == 0) {
// Registration is disabled - Redirect to login page.
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
return;
}
// The user is a guest, load the registration model and show the registration page.
$model = $this->getModel('Registration');
break;
case 'profile':
// Handle view specific models.
// If the user is a guest, redirect to the login page.
$user = $this->app->getIdentity();
if ($user->guest == 1) {
// Redirect to login page.
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
return;
}
$model = $this->getModel($vName);
break;
case 'login':
// Handle the default views.
$model = $this->getModel($vName);
break;
case 'remind':
case 'reset':
// If the user is already logged in, redirect to the profile page.
$user = $this->app->getIdentity();
if ($user->guest != 1) {
// Redirect to profile page.
$this->setRedirect(Route::_('index.php?option=com_users&view=profile', false));
return;
}
$model = $this->getModel($vName);
break;
case 'captive':
case 'methods':
case 'method':
$controller = $this->factory->createController($vName, 'Site', [], $this->app, $this->input);
$task = $this->input->get('task', '');
return $controller->execute($task);
default:
$model = $this->getModel('Login');
break;
}
// Make sure we don't send a referer
if (\in_array($vName, ['remind', 'reset'])) {
$this->app->setHeader('Referrer-Policy', 'no-referrer', true);
}
// Push the model into the view (as default).
$view->setModel($model, true);
$view->setLayout($lName);
// Push document object into the view.
$view->document = $document;
$view->display();
}
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\CMS\Router\Route;
use Joomla\Component\Users\Administrator\Controller\MethodController as AdminMethodController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Multi-factor Authentication method controller
*
* @since 4.2.0
*/
class MethodController extends AdminMethodController
{
/**
* Execute a task by triggering a Method in the derived class.
*
* @param string $task The task to perform.
*
* @return mixed The value returned by the called Method.
*
* @throws \Exception
* @since 4.2.0
*/
public function execute($task)
{
try {
return parent::execute($task);
} catch (\Exception $e) {
if ($e->getCode() !== 403) {
throw $e;
}
if ($this->app->getIdentity()->guest) {
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
return null;
}
}
return null;
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\CMS\Router\Route;
use Joomla\Component\Users\Administrator\Controller\MethodsController as AdminMethodsController;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Multi-factor Authentication methods selection and management controller
*
* @since 4.2.0
*/
class MethodsController extends AdminMethodsController
{
/**
* Execute a task by triggering a Method in the derived class.
*
* @param string $task The task to perform.
*
* @return mixed The value returned by the called Method.
*
* @throws \Exception
* @since 4.2.0
*/
public function execute($task)
{
try {
return parent::execute($task);
} catch (\Exception $e) {
if ($e->getCode() !== 403) {
throw $e;
}
if ($this->app->getIdentity()->guest) {
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
return null;
}
}
return null;
}
}

View File

@ -0,0 +1,232 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\CMS\Application\CMSWebApplicationInterface;
use Joomla\CMS\Event\Model;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Profile controller class for Users.
*
* @since 1.6
*/
class ProfileController extends BaseController
{
/**
* Method to check out a user for editing and redirect to the edit form.
*
* @return boolean
*
* @since 1.6
*/
public function edit()
{
$app = $this->app;
$user = $this->app->getIdentity();
$loginUserId = (int) $user->id;
// Get the current user id.
$userId = $this->input->getInt('user_id');
// Check if the user is trying to edit another users profile.
if ($userId != $loginUserId) {
$app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'error');
$app->setHeader('status', 403, true);
return false;
}
$cookieLogin = $user->get('cookieLogin');
// Check if the user logged in with a cookie
if (!empty($cookieLogin)) {
// If so, the user must login to edit the password and other data.
$app->enqueueMessage(Text::_('JGLOBAL_REMEMBER_MUST_LOGIN'), 'message');
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
return false;
}
// Set the user id for the user to edit in the session.
$app->setUserState('com_users.edit.profile.id', $userId);
// Redirect to the edit screen.
$this->setRedirect(Route::_('index.php?option=com_users&view=profile&layout=edit', false));
return true;
}
/**
* Method to save a user's profile data.
*
* @return void|boolean
*
* @since 1.6
* @throws \Exception
*/
public function save()
{
// Check for request forgeries.
$this->checkToken();
$app = $this->app;
/** @var \Joomla\Component\Users\Site\Model\ProfileModel $model */
$model = $this->getModel('Profile', 'Site');
$user = $this->app->getIdentity();
$userId = (int) $user->id;
// Get the user data.
$requestData = $app->getInput()->post->get('jform', [], 'array');
// Force the ID to this user.
$requestData['id'] = $userId;
// Validate the posted data.
$form = $model->getForm();
if (!$form) {
throw new \Exception($model->getError(), 500);
}
// Send an object which can be modified through the plugin event
$objData = (object) $requestData;
$this->getDispatcher()->dispatch(
'onContentNormaliseRequestData',
new Model\NormaliseRequestDataEvent('onContentNormaliseRequestData', [
'context' => 'com_users.user',
'data' => $objData,
'subject' => $form,
])
);
$requestData = (array) $objData;
// Validate the posted data.
$data = $model->validate($form, $requestData);
// Check for errors.
if ($data === false) {
// Get the validation messages.
$errors = $model->getErrors();
// Push up to three validation messages out to the user.
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof \Exception) {
$app->enqueueMessage($errors[$i]->getMessage(), CMSWebApplicationInterface::MSG_ERROR);
} else {
$app->enqueueMessage($errors[$i], CMSWebApplicationInterface::MSG_ERROR);
}
}
// Unset the passwords.
unset($requestData['password1'], $requestData['password2']);
// Save the data in the session.
$app->setUserState('com_users.edit.profile.data', $requestData);
// Redirect back to the edit screen.
$userId = (int) $app->getUserState('com_users.edit.profile.id');
$this->setRedirect(Route::_('index.php?option=com_users&view=profile&layout=edit&user_id=' . $userId, false));
return false;
}
// Attempt to save the data.
$return = $model->save($data);
// Check for errors.
if ($return === false) {
// Save the data in the session.
$app->setUserState('com_users.edit.profile.data', $data);
// Redirect back to the edit screen.
$userId = (int) $app->getUserState('com_users.edit.profile.id');
$this->setMessage(Text::sprintf('COM_USERS_PROFILE_SAVE_FAILED', $model->getError()), 'warning');
$this->setRedirect(Route::_('index.php?option=com_users&view=profile&layout=edit&user_id=' . $userId, false));
return false;
}
// Redirect the user and adjust session state based on the chosen task.
switch ($this->getTask()) {
case 'apply':
// Check out the profile.
$app->setUserState('com_users.edit.profile.id', $return);
// Redirect back to the edit screen.
$this->setMessage(Text::_('COM_USERS_PROFILE_SAVE_SUCCESS'));
$redirect = $app->getUserState('com_users.edit.profile.redirect', '');
// Don't redirect to an external URL.
if (!Uri::isInternal($redirect)) {
$redirect = null;
}
if (!$redirect) {
$redirect = 'index.php?option=com_users&view=profile&layout=edit&hidemainmenu=1';
}
$this->setRedirect(Route::_($redirect, false));
break;
default:
// Clear the profile id from the session.
$app->setUserState('com_users.edit.profile.id', null);
$redirect = $app->getUserState('com_users.edit.profile.redirect', '');
// Don't redirect to an external URL.
if (!Uri::isInternal($redirect)) {
$redirect = null;
}
if (!$redirect) {
$redirect = 'index.php?option=com_users&view=profile&user_id=' . $return;
}
// Redirect to the list screen.
$this->setMessage(Text::_('COM_USERS_PROFILE_SAVE_SUCCESS'));
$this->setRedirect(Route::_($redirect, false));
break;
}
// Flush the data from the session.
$app->setUserState('com_users.edit.profile.data', null);
}
/**
* Method to cancel an edit.
*
* @return void
*
* @since 4.0.0
*/
public function cancel()
{
// Check for request forgeries.
$this->checkToken();
// Flush the data from the session.
$this->app->setUserState('com_users.edit.profile', null);
// Redirect to user profile.
$this->setRedirect(Route::_('index.php?option=com_users&view=profile', false));
}
}

View File

@ -0,0 +1,251 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\CMS\Application\CMSWebApplicationInterface;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Router\Route;
use Joomla\CMS\User\UserFactoryAwareInterface;
use Joomla\CMS\User\UserFactoryAwareTrait;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Registration controller class for Users.
*
* @since 1.6
*/
class RegistrationController extends BaseController implements UserFactoryAwareInterface
{
use UserFactoryAwareTrait;
/**
* Method to activate a user.
*
* @return boolean True on success, false on failure.
*
* @since 1.6
* @throws \Exception
*/
public function activate()
{
$user = $this->app->getIdentity();
$input = $this->input;
$uParams = ComponentHelper::getParams('com_users');
// Check for admin activation. Don't allow non-super-admin to delete a super admin
if ($uParams->get('useractivation') != 2 && $user->id) {
$this->setRedirect('index.php');
return true;
}
// If user registration or account activation is disabled, throw a 403.
if ($uParams->get('useractivation') == 0 || $uParams->get('allowUserRegistration') == 0) {
throw new \Exception(Text::_('JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN'), 403);
}
/** @var \Joomla\Component\Users\Site\Model\RegistrationModel $model */
$model = $this->getModel('Registration', 'Site');
$token = $input->getAlnum('token');
// Check that the token is in a valid format.
if ($token === null || \strlen($token) !== 32) {
throw new \Exception(Text::_('JINVALID_TOKEN'), 403);
}
// Get the User ID
$userIdToActivate = $model->getUserIdFromToken($token);
if (!$userIdToActivate) {
$this->setMessage(Text::_('COM_USERS_ACTIVATION_TOKEN_NOT_FOUND'));
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
return false;
}
// Get the user we want to activate
$userToActivate = $this->getUserFactory()->loadUserById($userIdToActivate);
// Admin activation is on and admin is activating the account
if (($uParams->get('useractivation') == 2) && $userToActivate->getParam('activate', 0)) {
// If a user admin is not logged in, redirect them to the login page with an error message
if (!$user->authorise('core.create', 'com_users') || !$user->authorise('core.manage', 'com_users')) {
$activationUrl = 'index.php?option=com_users&task=registration.activate&token=' . $token;
$loginUrl = 'index.php?option=com_users&view=login&return=' . base64_encode($activationUrl);
// In case we still run into this in the second step the user does not have the right permissions
$message = Text::_('COM_USERS_REGISTRATION_ACL_ADMIN_ACTIVATION_PERMISSIONS');
// When we are not logged in we should login
if ($user->guest) {
$message = Text::_('COM_USERS_REGISTRATION_ACL_ADMIN_ACTIVATION');
}
$this->setMessage($message);
$this->setRedirect(Route::_($loginUrl, false));
return false;
}
}
// Attempt to activate the user.
$return = $model->activate($token);
// Check for errors.
if ($return === false) {
// Redirect back to the home page.
$this->setMessage(Text::sprintf('COM_USERS_REGISTRATION_SAVE_FAILED', $model->getError()), 'error');
$this->setRedirect('index.php');
return false;
}
$useractivation = $uParams->get('useractivation');
// Redirect to the login screen.
if ($useractivation == 0) {
$this->setMessage(Text::_('COM_USERS_REGISTRATION_SAVE_SUCCESS'));
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
} elseif ($useractivation == 1) {
$this->setMessage(Text::_('COM_USERS_REGISTRATION_ACTIVATE_SUCCESS'));
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
} elseif ($return->getParam('activate')) {
$this->setMessage(Text::_('COM_USERS_REGISTRATION_VERIFY_SUCCESS'));
$this->setRedirect(Route::_('index.php?option=com_users&view=registration&layout=complete', false));
} else {
$this->setMessage(Text::_('COM_USERS_REGISTRATION_ADMINACTIVATE_SUCCESS'));
$this->setRedirect(Route::_('index.php?option=com_users&view=registration&layout=complete', false));
}
return true;
}
/**
* Method to register a user.
*
* @return boolean True on success, false on failure.
*
* @since 1.6
* @throws \Exception
*/
public function register()
{
// Check for request forgeries.
$this->checkToken();
// If registration is disabled - Redirect to login page.
if (ComponentHelper::getParams('com_users')->get('allowUserRegistration') == 0) {
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
return false;
}
$app = $this->app;
/** @var \Joomla\Component\Users\Site\Model\RegistrationModel $model */
$model = $this->getModel('Registration', 'Site');
// Get the user data.
$requestData = $this->input->post->get('jform', [], 'array');
// Validate the posted data.
$form = $model->getForm();
if (!$form) {
throw new \Exception($model->getError(), 500);
}
$data = $model->validate($form, $requestData);
// Check for validation errors.
if ($data === false) {
// Get the validation messages.
$errors = $model->getErrors();
// Push up to three validation messages out to the user.
for ($i = 0, $n = \count($errors); $i < $n && $i < 3; $i++) {
if ($errors[$i] instanceof \Exception) {
$app->enqueueMessage($errors[$i]->getMessage(), CMSWebApplicationInterface::MSG_ERROR);
} else {
$app->enqueueMessage($errors[$i], CMSWebApplicationInterface::MSG_ERROR);
}
}
/**
* We need the filtered value of calendar fields because the UTC normalisation is
* done in the filter and on output. This would apply the Timezone offset on
* reload. We set the calendar values we save to the processed date.
*/
$filteredData = $form->filter($requestData);
foreach ($form->getFieldset() as $field) {
if ($field->type === 'Calendar') {
$fieldName = $field->fieldname;
if ($field->group) {
if (isset($filteredData[$field->group][$fieldName])) {
$requestData[$field->group][$fieldName] = $filteredData[$field->group][$fieldName];
}
} else {
if (isset($filteredData[$fieldName])) {
$requestData[$fieldName] = $filteredData[$fieldName];
}
}
}
}
// Save the data in the session.
$app->setUserState('com_users.registration.data', $requestData);
// Redirect back to the registration screen.
$this->setRedirect(Route::_('index.php?option=com_users&view=registration', false));
return false;
}
// Attempt to save the data.
$return = $model->register($data);
// Check for errors.
if ($return === false) {
// Save the data in the session.
$app->setUserState('com_users.registration.data', $data);
// Redirect back to the edit screen.
$this->setMessage($model->getError(), 'error');
$this->setRedirect(Route::_('index.php?option=com_users&view=registration', false));
return false;
}
// Flush the data from the session.
$app->setUserState('com_users.registration.data', null);
// Redirect to the profile screen.
if ($return === 'adminactivate') {
$this->setMessage(Text::_('COM_USERS_REGISTRATION_COMPLETE_VERIFY'));
$this->setRedirect(Route::_('index.php?option=com_users&view=registration&layout=complete', false));
} elseif ($return === 'useractivate') {
$this->setMessage(Text::_('COM_USERS_REGISTRATION_COMPLETE_ACTIVATE'));
$this->setRedirect(Route::_('index.php?option=com_users&view=registration&layout=complete', false));
} else {
$this->setMessage(Text::_('COM_USERS_REGISTRATION_SAVE_SUCCESS'));
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false));
}
return true;
}
}

View File

@ -0,0 +1,63 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Router\Route;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Reset controller class for Users.
*
* @since 1.6
*/
class RemindController extends BaseController
{
/**
* Method to request a username reminder.
*
* @return boolean
*
* @since 1.6
*/
public function remind()
{
// Check the request token.
$this->checkToken('post');
/** @var \Joomla\Component\Users\Site\Model\RemindModel $model */
$model = $this->getModel('Remind', 'Site');
$data = $this->input->post->get('jform', [], 'array');
// Submit the password reset request.
$return = $model->processRemindRequest($data);
// Check for a hard error.
if ($return == false && JDEBUG) {
// The request failed.
// Go back to the request form.
$message = Text::sprintf('COM_USERS_REMIND_REQUEST_FAILED', $model->getError());
$this->setRedirect(Route::_('index.php?option=com_users&view=remind', false), $message, 'notice');
return false;
}
// To not expose if the user exists or not we send a generic message.
$message = Text::_('COM_USERS_REMIND_REQUEST');
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false), $message, 'notice');
return true;
}
}

View File

@ -0,0 +1,185 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Router\Route;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Reset controller class for Users.
*
* @since 1.6
*/
class ResetController extends BaseController
{
/**
* Method to request a password reset.
*
* @return boolean
*
* @since 1.6
*/
public function request()
{
// Check the request token.
$this->checkToken('post');
$app = $this->app;
/** @var \Joomla\Component\Users\Site\Model\ResetModel $model */
$model = $this->getModel('Reset', 'Site');
$data = $this->input->post->get('jform', [], 'array');
// Submit the password reset request.
$return = $model->processResetRequest($data);
// Check for a hard error.
if ($return instanceof \Exception && JDEBUG) {
// Get the error message to display.
if ($app->get('error_reporting')) {
$message = $return->getMessage();
} else {
$message = Text::_('COM_USERS_RESET_REQUEST_ERROR');
}
// Go back to the request form.
$this->setRedirect(Route::_('index.php?option=com_users&view=reset', false), $message, 'error');
return false;
}
if ($return === false && JDEBUG) {
// The request failed.
// Go back to the request form.
$message = Text::sprintf('COM_USERS_RESET_REQUEST_FAILED', $model->getError());
$this->setRedirect(Route::_('index.php?option=com_users&view=reset', false), $message, 'notice');
return false;
}
// To not expose if the user exists or not we send a generic message.
$message = Text::_('COM_USERS_RESET_REQUEST');
$this->setRedirect(Route::_('index.php?option=com_users&view=reset&layout=confirm', false), $message, 'notice');
return true;
}
/**
* Method to confirm the password request.
*
* @return boolean
*
* @access public
* @since 1.6
*/
public function confirm()
{
// Check the request token.
$this->checkToken('request');
$app = $this->app;
/** @var \Joomla\Component\Users\Site\Model\ResetModel $model */
$model = $this->getModel('Reset', 'Site');
$data = $this->input->get('jform', [], 'array');
// Confirm the password reset request.
$return = $model->processResetConfirm($data);
// Check for a hard error.
if ($return instanceof \Exception) {
// Get the error message to display.
if ($app->get('error_reporting')) {
$message = $return->getMessage();
} else {
$message = Text::_('COM_USERS_RESET_CONFIRM_ERROR');
}
// Go back to the confirm form.
$this->setRedirect(Route::_('index.php?option=com_users&view=reset&layout=confirm', false), $message, 'error');
return false;
}
if ($return === false) {
// Confirm failed.
// Go back to the confirm form.
$message = Text::sprintf('COM_USERS_RESET_CONFIRM_FAILED', $model->getError());
$this->setRedirect(Route::_('index.php?option=com_users&view=reset&layout=confirm', false), $message, 'notice');
return false;
}
// Confirm succeeded.
// Proceed to step three.
$this->setRedirect(Route::_('index.php?option=com_users&view=reset&layout=complete', false));
return true;
}
/**
* Method to complete the password reset process.
*
* @return boolean
*
* @since 1.6
*/
public function complete()
{
// Check for request forgeries
$this->checkToken('post');
$app = $this->app;
/** @var \Joomla\Component\Users\Site\Model\ResetModel $model */
$model = $this->getModel('Reset', 'Site');
$data = $this->input->post->get('jform', [], 'array');
// Complete the password reset request.
$return = $model->processResetComplete($data);
// Check for a hard error.
if ($return instanceof \Exception) {
// Get the error message to display.
if ($app->get('error_reporting')) {
$message = $return->getMessage();
} else {
$message = Text::_('COM_USERS_RESET_COMPLETE_ERROR');
}
// Go back to the complete form.
$this->setRedirect(Route::_('index.php?option=com_users&view=reset&layout=complete', false), $message, 'error');
return false;
}
if ($return === false) {
// Complete failed.
// Go back to the complete form.
$message = Text::sprintf('COM_USERS_RESET_COMPLETE_FAILED', $model->getError());
$this->setRedirect(Route::_('index.php?option=com_users&view=reset&layout=complete', false), $message, 'notice');
return false;
}
// Complete succeeded.
// Proceed to the login form.
$message = Text::_('COM_USERS_RESET_COMPLETE_SUCCESS');
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false), $message);
return true;
}
}

View File

@ -0,0 +1,270 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Controller;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Registration controller class for Users.
*
* @since 1.6
*/
class UserController extends BaseController
{
/**
* Method to log in a user.
*
* @return void
*
* @since 1.6
*/
public function login()
{
$this->checkToken('post');
$input = $this->input->getInputForRequestMethod();
// Populate the data array:
$data = [];
$data['return'] = base64_decode($input->get('return', '', 'BASE64'));
$data['username'] = $input->get('username', '', 'USERNAME');
$data['password'] = $input->get('password', '', 'RAW');
$data['secretkey'] = $input->get('secretkey', '', 'RAW');
// Check for a simple menu item id
if (is_numeric($data['return'])) {
$itemId = (int) $data['return'];
$data['return'] = 'index.php?Itemid=' . $itemId;
if (Multilanguage::isEnabled()) {
$language = $this->getModel('Login', 'Site')->getMenuLanguage($itemId);
if ($language !== '*') {
$data['return'] .= '&lang=' . $language;
}
}
} elseif (!Uri::isInternal($data['return'])) {
// Don't redirect to an external URL.
$data['return'] = '';
}
// Set the return URL if empty.
if (empty($data['return'])) {
$data['return'] = 'index.php?option=com_users&view=profile';
}
// Set the return URL in the user state to allow modification by plugins
$this->app->setUserState('users.login.form.return', $data['return']);
// Get the log in options.
$options = [];
$options['remember'] = $this->input->getBool('remember', false);
$options['return'] = $data['return'];
// Get the log in credentials.
$credentials = [];
$credentials['username'] = $data['username'];
$credentials['password'] = $data['password'];
$credentials['secretkey'] = $data['secretkey'];
// Perform the log in.
if (true !== $this->app->login($credentials, $options)) {
// Login failed !
// Clear user name, password and secret key before sending the login form back to the user.
$data['remember'] = (int) $options['remember'];
$data['username'] = '';
$data['password'] = '';
$data['secretkey'] = '';
$this->app->setUserState('users.login.form.data', $data);
$this->app->redirect(Route::_('index.php?option=com_users&view=login', false));
}
// Success
if ($options['remember'] == true) {
$this->app->setUserState('rememberLogin', true);
}
$this->app->setUserState('users.login.form.data', []);
$this->app->redirect(Route::_($this->app->getUserState('users.login.form.return'), false));
}
/**
* Method to log out a user.
*
* @return void
*
* @since 1.6
*/
public function logout()
{
$this->checkToken('request');
$app = $this->app;
// Prepare the logout options.
$options = [
'clientid' => $app->get('shared_session', '0') ? null : 0,
];
// Perform the log out.
$error = $app->logout(null, $options);
$input = $app->getInput()->getInputForRequestMethod();
// Check if the log out succeeded.
if ($error instanceof \Exception) {
$app->redirect(Route::_('index.php?option=com_users&view=login', false));
}
// Get the return URL from the request and validate that it is internal.
$return = $input->get('return', '', 'BASE64');
$return = base64_decode($return);
// Check for a simple menu item id
if (is_numeric($return)) {
$itemId = (int) $return;
$return = 'index.php?Itemid=' . $itemId;
if (Multilanguage::isEnabled()) {
$language = $this->getModel('Login', 'Site')->getMenuLanguage($itemId);
if ($language !== '*') {
$return .= '&lang=' . $language;
}
}
} elseif (!Uri::isInternal($return)) {
$return = '';
}
// In case redirect url is not set, redirect user to homepage
if (empty($return)) {
$return = Uri::root();
}
// Show a message when a user is logged out.
$app->enqueueMessage(Text::_('COM_USERS_FRONTEND_LOGOUT_SUCCESS'), 'message');
// Redirect the user.
$app->redirect(Route::_($return, false));
}
/**
* Method to logout directly and redirect to page.
*
* @return void
*
* @since 3.5
*/
public function menulogout()
{
// Get the ItemID of the page to redirect after logout
$app = $this->app;
$active = $app->getMenu()->getActive();
$itemid = $active ? $active->getParams()->get('logout') : 0;
// Get the language of the page when multilang is on
if (Multilanguage::isEnabled()) {
if ($itemid) {
$language = $this->getModel('Login', 'Site')->getMenuLanguage($itemid);
// URL to redirect after logout
$url = 'index.php?Itemid=' . $itemid . ($language !== '*' ? '&lang=' . $language : '');
} else {
// Logout is set to default. Get the home page ItemID
$lang_code = $app->getInput()->cookie->getString(ApplicationHelper::getHash('language'));
$item = $app->getMenu()->getDefault($lang_code);
$itemid = $item->id;
// Redirect to Home page after logout
$url = 'index.php?Itemid=' . $itemid;
}
} else {
// URL to redirect after logout, default page if no ItemID is set
$url = $itemid ? 'index.php?Itemid=' . $itemid : Uri::root();
}
// Logout and redirect
$this->setRedirect(Route::_('index.php?option=com_users&task=user.logout&' . Session::getFormToken() . '=1&return=' . base64_encode($url), false));
}
/**
* Method to request a username reminder.
*
* @return boolean
*
* @since 1.6
*/
public function remind()
{
// Check the request token.
$this->checkToken('post');
$app = $this->app;
/** @var \Joomla\Component\Users\Site\Model\RemindModel $model */
$model = $this->getModel('Remind', 'Site');
$data = $this->input->post->get('jform', [], 'array');
// Submit the username remind request.
$return = $model->processRemindRequest($data);
// Check for a hard error.
if ($return instanceof \Exception) {
// Get the error message to display.
$message = $app->get('error_reporting')
? $return->getMessage()
: Text::_('COM_USERS_REMIND_REQUEST_ERROR');
// Go back to the complete form.
$this->setRedirect(Route::_('index.php?option=com_users&view=remind', false), $message, 'error');
return false;
}
if ($return === false) {
// Go back to the complete form.
$message = Text::sprintf('COM_USERS_REMIND_REQUEST_FAILED', $model->getError());
$this->setRedirect(Route::_('index.php?option=com_users&view=remind', false), $message, 'notice');
return false;
}
// Proceed to the login form.
$message = Text::_('COM_USERS_REMIND_REQUEST_SUCCESS');
$this->setRedirect(Route::_('index.php?option=com_users&view=login', false), $message);
return true;
}
/**
* Method to resend a user.
*
* @return void
*
* @since 1.6
*/
public function resend()
{
// Check for request forgeries
// $this->checkToken('post');
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Model;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Model for managing backup codes
*
* @since 4.2.0
*/
class BackupcodesModel extends \Joomla\Component\Users\Administrator\Model\BackupcodesModel
{
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Model;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Captive Multi-factor Authentication page's model
*
* @since 4.2.0
*/
class CaptiveModel extends \Joomla\Component\Users\Administrator\Model\CaptiveModel
{
}

View File

@ -0,0 +1,155 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Model;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\MVC\Model\FormModel;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Login model class for Users.
*
* @since 1.6
*/
class LoginModel extends FormModel
{
/**
* Method to get the login form.
*
* The base form is loaded from XML and then an event is fired
* for users plugins to extend the form with extra fields.
*
* @param array $data An optional array of data for the form to interrogate.
* @param boolean $loadData True if the form is to load its own data (default case), false if not.
*
* @return Form A Form object on success, false on failure
*
* @since 1.6
*/
public function getForm($data = [], $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_users.login', 'login', ['load_data' => $loadData]);
if (empty($form)) {
return false;
}
return $form;
}
/**
* Method to get the data that should be injected in the form.
*
* @return array The default data is an empty array.
*
* @since 1.6
* @throws \Exception
*/
protected function loadFormData()
{
// Check the session for previously entered login form data.
$app = Factory::getApplication();
$data = $app->getUserState('users.login.form.data', []);
$input = $app->getInput()->getInputForRequestMethod();
// Check for return URL from the request first
if ($return = $input->get('return', '', 'BASE64')) {
$data['return'] = base64_decode($return);
if (!Uri::isInternal($data['return'])) {
$data['return'] = '';
}
}
$app->setUserState('users.login.form.data', $data);
$this->preprocessData('com_users.login', $data);
return $data;
}
/**
* Method to auto-populate the model state.
*
* Calling getState in this method will result in recursion.
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
protected function populateState()
{
// Get the application object.
$params = Factory::getApplication()->getParams('com_users');
// Load the parameters.
$this->setState('params', $params);
}
/**
* Override Joomla\CMS\MVC\Model\AdminModel::preprocessForm to ensure the correct plugin group is loaded.
*
* @param Form $form A Form object.
* @param mixed $data The data expected for the form.
* @param string $group The name of the plugin group to import (defaults to "content").
*
* @return void
*
* @since 1.6
* @throws \Exception if there is an error in the form event.
*/
protected function preprocessForm(Form $form, $data, $group = 'user')
{
parent::preprocessForm($form, $data, $group);
}
/**
* Returns the language for the given menu id.
*
* @param int $id The menu id
*
* @return string
*
* @since 4.2.0
*/
public function getMenuLanguage(int $id): string
{
if (!Multilanguage::isEnabled()) {
return '';
}
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName('language'))
->from($db->quoteName('#__menu'))
->where($db->quoteName('client_id') . ' = 0')
->where($db->quoteName('id') . ' = :id')
->bind(':id', $id, ParameterType::INTEGER);
$db->setQuery($query);
try {
return $db->loadResult();
} catch (\RuntimeException $e) {
return '';
}
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Model;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Multi-factor Authentication Method management model
*
* @since 4.2.0
*/
class MethodModel extends \Joomla\Component\Users\Administrator\Model\MethodModel
{
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Model;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Multi-factor Authentication Methods list page's model
*
* @since 4.2.0
*/
class MethodsModel extends \Joomla\Component\Users\Administrator\Model\MethodsModel
{
}

View File

@ -0,0 +1,337 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Model;
use Joomla\CMS\Access\Access;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormFactoryInterface;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\FormModel;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\String\PunycodeHelper;
use Joomla\CMS\User\User;
use Joomla\CMS\User\UserHelper;
use Joomla\Component\Users\Administrator\Model\UserModel;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Profile model class for Users.
*
* @since 1.6
*/
class ProfileModel extends FormModel
{
/**
* @var object The user profile data.
* @since 1.6
*/
protected $data;
/**
* Constructor.
*
* @param array $config An array of configuration options (name, state, dbo, table_path, ignore_request).
* @param ?MVCFactoryInterface $factory The factory.
* @param ?FormFactoryInterface $formFactory The form factory.
*
* @see \Joomla\CMS\MVC\Model\BaseDatabaseModel
* @since 3.2
*/
public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?FormFactoryInterface $formFactory = null)
{
$config = array_merge(
[
'events_map' => ['validate' => 'user'],
],
$config
);
parent::__construct($config, $factory, $formFactory);
}
/**
* Method to get the profile form data.
*
* The base form data is loaded and then an event is fired
* for users plugins to extend the data.
*
* @return User
*
* @since 1.6
* @throws \Exception
*/
public function getData()
{
if ($this->data === null) {
$userId = $this->getState('user.id');
// Initialise the table with Joomla\CMS\User\User.
$this->data = new User($userId);
// Set the base user data.
$this->data->email1 = $this->data->email;
// Override the base user data with any data in the session.
$temp = (array) Factory::getApplication()->getUserState('com_users.edit.profile.data', []);
foreach ($temp as $k => $v) {
$this->data->$k = $v;
}
// Unset the passwords.
unset($this->data->password1, $this->data->password2);
$registry = new Registry($this->data->params);
$this->data->params = $registry->toArray();
}
return $this->data;
}
/**
* Method to get the profile form.
*
* The base form is loaded from XML and then an event is fired
* for users plugins to extend the form with extra fields.
*
* @param array $data An optional array of data for the form to interrogate.
* @param boolean $loadData True if the form is to load its own data (default case), false if not.
*
* @return Form|bool A Form object on success, false on failure
*
* @since 1.6
*/
public function getForm($data = [], $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_users.profile', 'profile', ['control' => 'jform', 'load_data' => $loadData]);
if (empty($form)) {
return false;
}
// Check for username compliance and parameter set
$isUsernameCompliant = true;
$username = $loadData ? $form->getValue('username') : $this->loadFormData()->username;
if ($username) {
$isUsernameCompliant = !(preg_match('#[<>"\'%;()&\\\\]|\\.\\./#', $username)
|| \strlen(mb_convert_encoding($username, 'ISO-8859-1', 'UTF-8')) < 2
|| trim($username) !== $username);
}
$this->setState('user.username.compliant', $isUsernameCompliant);
if ($isUsernameCompliant && !ComponentHelper::getParams('com_users')->get('change_login_name')) {
$form->setFieldAttribute('username', 'class', '');
$form->setFieldAttribute('username', 'filter', '');
$form->setFieldAttribute('username', 'description', 'COM_USERS_PROFILE_NOCHANGE_USERNAME_DESC');
$form->setFieldAttribute('username', 'validate', '');
$form->setFieldAttribute('username', 'message', '');
$form->setFieldAttribute('username', 'readonly', 'true');
$form->setFieldAttribute('username', 'required', 'false');
}
// When multilanguage is set, a user's default site language should also be a Content Language
if (Multilanguage::isEnabled()) {
$form->setFieldAttribute('language', 'type', 'frontendlanguage', 'params');
}
// If the user needs to change their password, mark the password fields as required
if ($this->getCurrentUser()->requireReset) {
$form->setFieldAttribute('password1', 'required', 'true');
$form->setFieldAttribute('password2', 'required', 'true');
}
return $form;
}
/**
* Method to get the data that should be injected in the form.
*
* @return mixed The data for the form.
*
* @since 1.6
*/
protected function loadFormData()
{
$data = $this->getData();
$this->preprocessData('com_users.profile', $data, 'user');
return $data;
}
/**
* Override preprocessForm to load the user plugin group instead of content.
*
* @param Form $form A Form object.
* @param mixed $data The data expected for the form.
* @param string $group The name of the plugin group to import (defaults to "content").
*
* @return void
*
* @throws \Exception if there is an error in the form event.
*
* @since 1.6
*/
protected function preprocessForm(Form $form, $data, $group = 'user')
{
if (ComponentHelper::getParams('com_users')->get('frontend_userparams')) {
$form->loadFile('frontend', false);
if ($this->getCurrentUser()->authorise('core.login.admin')) {
$form->loadFile('frontend_admin', false);
}
}
parent::preprocessForm($form, $data, $group);
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
protected function populateState()
{
// Get the application object.
$params = Factory::getApplication()->getParams('com_users');
// Get the user id.
$userId = Factory::getApplication()->getUserState('com_users.edit.profile.id');
$userId = !empty($userId) ? $userId : (int) $this->getCurrentUser()->id;
// Set the user id.
$this->setState('user.id', $userId);
// Load the parameters.
$this->setState('params', $params);
}
/**
* Method to save the form data.
*
* @param array $data The form data.
*
* @return mixed The user id on success, false on failure.
*
* @since 1.6
* @throws \Exception
*/
public function save($data)
{
$userId = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('user.id');
$user = new User($userId);
// Prepare the data for the user object.
$data['email'] = PunycodeHelper::emailToPunycode($data['email1']);
$data['password'] = $data['password1'];
// Unset the username if it should not be overwritten
$isUsernameCompliant = $this->getState('user.username.compliant');
if ($isUsernameCompliant && !ComponentHelper::getParams('com_users')->get('change_login_name')) {
unset($data['username']);
}
// Unset block and sendEmail so they do not get overwritten
unset($data['block'], $data['sendEmail']);
// Bind the data.
if (!$user->bind($data)) {
$this->setError($user->getError());
return false;
}
// Load the users plugin group.
PluginHelper::importPlugin('user');
// Retrieve the user groups so they don't get overwritten
unset($user->groups);
$user->groups = Access::getGroupsByUser($user->id, false);
// Store the data.
if (!$user->save()) {
$this->setError($user->getError());
return false;
}
// Destroy all active sessions for the user after changing the password
if ($data['password1']) {
UserHelper::destroyUserSessions($user->id, true);
}
return $user->id;
}
/**
* Gets the configuration forms for all two-factor authentication methods
* in an array.
*
* @param integer $userId The user ID to load the forms for (optional)
*
* @return array
*
* @since 3.2
*
* @deprecated 4.2 will be removed in 6.0.
* Will be removed without replacement
*/
public function getTwofactorform($userId = null)
{
return [];
}
/**
* No longer used
*
* @param integer $userId Ignored
*
* @return \stdClass
*
* @since 3.2
*
* @deprecated 4.2 will be removed in 6.0.
* Will be removed without replacement
*/
public function getOtpConfig($userId = null)
{
@trigger_error(
\sprintf(
'%s() is deprecated. Use \Joomla\Component\Users\Administrator\Helper\Mfa::getUserMfaRecords() instead.',
__METHOD__
),
E_USER_DEPRECATED
);
/** @var UserModel $model */
$model = $this->bootComponent('com_users')
->getMVCFactory()->createModel('User', 'Administrator');
return $model->getOtpConfig();
}
}

View File

@ -0,0 +1,656 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Model;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Date\Date;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormFactoryInterface;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Mail\MailTemplate;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\FormModel;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\String\PunycodeHelper;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\User\User;
use Joomla\CMS\User\UserFactoryAwareInterface;
use Joomla\CMS\User\UserFactoryAwareTrait;
use Joomla\CMS\User\UserHelper;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Registration model class for Users.
*
* @since 1.6
*/
class RegistrationModel extends FormModel implements UserFactoryAwareInterface
{
use UserFactoryAwareTrait;
/**
* @var object The user registration data.
* @since 1.6
*/
protected $data;
/**
* Constructor.
*
* @param array $config An array of configuration options (name, state, dbo, table_path, ignore_request).
* @param ?MVCFactoryInterface $factory The factory.
* @param ?FormFactoryInterface $formFactory The form factory.
*
* @see \Joomla\CMS\MVC\Model\BaseDatabaseModel
* @since 3.2
*/
public function __construct($config = [], ?MVCFactoryInterface $factory = null, ?FormFactoryInterface $formFactory = null)
{
$config = array_merge(
[
'events_map' => ['validate' => 'user'],
],
$config
);
parent::__construct($config, $factory, $formFactory);
}
/**
* Method to get the user ID from the given token
*
* @param string $token The activation token.
*
* @return mixed False on failure, id of the user on success
*
* @since 3.8.13
*/
public function getUserIdFromToken($token)
{
$db = $this->getDatabase();
// Get the user id based on the token.
$query = $db->getQuery(true);
$query->select($db->quoteName('id'))
->from($db->quoteName('#__users'))
->where($db->quoteName('activation') . ' = :activation')
->where($db->quoteName('block') . ' = 1')
->where($db->quoteName('lastvisitDate') . ' IS NULL')
->bind(':activation', $token);
$db->setQuery($query);
try {
return (int) $db->loadResult();
} catch (\RuntimeException $e) {
$this->setError(Text::sprintf('COM_USERS_DATABASE_ERROR', $e->getMessage()));
return false;
}
}
/**
* Method to activate a user account.
*
* @param string $token The activation token.
*
* @return mixed False on failure, user object on success.
*
* @since 1.6
*/
public function activate($token)
{
$app = Factory::getApplication();
$userParams = ComponentHelper::getParams('com_users');
$userId = $this->getUserIdFromToken($token);
// Check for a valid user id.
if (!$userId) {
$this->setError(Text::_('COM_USERS_ACTIVATION_TOKEN_NOT_FOUND'));
return false;
}
// Load the users plugin group.
PluginHelper::importPlugin('user');
// Activate the user.
$user = $this->getUserFactory()->loadUserById($userId);
// Admin activation is on and user is verifying their email
if (($userParams->get('useractivation') == 2) && !$user->getParam('activate', 0)) {
$linkMode = $app->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE;
// Compile the admin notification mail values.
$data = $user->getProperties();
$data['activation'] = ApplicationHelper::getHash(UserHelper::genRandomPassword());
$user->set('activation', $data['activation']);
$data['siteurl'] = Uri::base();
$data['activate'] = Route::link(
'site',
'index.php?option=com_users&task=registration.activate&token=' . $data['activation'],
false,
$linkMode,
true
);
$data['fromname'] = $app->get('fromname');
$data['mailfrom'] = $app->get('mailfrom');
$data['sitename'] = $app->get('sitename');
$user->setParam('activate', 1);
// Get all admin users
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName(['name', 'email', 'sendEmail', 'id']))
->from($db->quoteName('#__users'))
->where($db->quoteName('sendEmail') . ' = 1')
->where($db->quoteName('block') . ' = 0');
$db->setQuery($query);
try {
$rows = $db->loadObjectList();
} catch (\RuntimeException $e) {
$this->setError(Text::sprintf('COM_USERS_DATABASE_ERROR', $e->getMessage()));
return false;
}
// Send mail to all users with users creating permissions and receiving system emails
foreach ($rows as $row) {
$usercreator = $this->getUserFactory()->loadUserById($row->id);
if ($usercreator->authorise('core.create', 'com_users') && $usercreator->authorise('core.manage', 'com_users')) {
try {
$mailer = new MailTemplate('com_users.registration.admin.verification_request', $app->getLanguage()->getTag());
$mailer->addTemplateData($data);
$mailer->addRecipient($row->email);
$return = $mailer->send();
} catch (\Exception $exception) {
try {
Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror');
$return = false;
} catch (\RuntimeException $exception) {
Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning');
$return = false;
}
}
// Check for an error.
if ($return !== true) {
$this->setError(Text::_('COM_USERS_REGISTRATION_ACTIVATION_NOTIFY_SEND_MAIL_FAILED'));
return false;
}
}
}
} elseif (($userParams->get('useractivation') == 2) && $user->getParam('activate', 0)) {
// Admin activation is on and admin is activating the account
$user->set('activation', '');
$user->set('block', '0');
// Compile the user activated notification mail values.
$data = $user->getProperties();
$user->setParam('activate', 0);
$data['fromname'] = $app->get('fromname');
$data['mailfrom'] = $app->get('mailfrom');
$data['sitename'] = $app->get('sitename');
$data['siteurl'] = Uri::base();
$mailer = new MailTemplate('com_users.registration.user.admin_activated', $app->getLanguage()->getTag());
$mailer->addTemplateData($data);
$mailer->addRecipient($data['email']);
try {
$return = $mailer->send();
} catch (\Exception $exception) {
try {
Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror');
$return = false;
} catch (\RuntimeException $exception) {
Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning');
$return = false;
}
}
// Check for an error.
if ($return !== true) {
$this->setError(Text::_('COM_USERS_REGISTRATION_ACTIVATION_NOTIFY_SEND_MAIL_FAILED'));
return false;
}
} else {
$user->set('activation', '');
$user->set('block', '0');
}
// Store the user object.
if (!$user->save()) {
$this->setError(Text::sprintf('COM_USERS_REGISTRATION_ACTIVATION_SAVE_FAILED', $user->getError()));
return false;
}
return $user;
}
/**
* Method to get the registration form data.
*
* The base form data is loaded and then an event is fired
* for users plugins to extend the data.
*
* @return mixed Data object on success, false on failure.
*
* @since 1.6
* @throws \Exception
*/
public function getData()
{
if ($this->data === null) {
$this->data = new \stdClass();
$app = Factory::getApplication();
$params = ComponentHelper::getParams('com_users');
// Override the base user data with any data in the session.
$temp = (array) $app->getUserState('com_users.registration.data', []);
// Don't load the data in this getForm call, or we'll call ourself
$form = $this->getForm([], false);
foreach ($temp as $k => $v) {
// Here we could have a grouped field, let's check it
if (\is_array($v)) {
$this->data->$k = new \stdClass();
foreach ($v as $key => $val) {
if ($form->getField($key, $k) !== false) {
$this->data->$k->$key = $val;
}
}
} elseif ($form->getField($k) !== false) {
// Only merge the field if it exists in the form.
$this->data->$k = $v;
}
}
// Get the groups the user should be added to after registration.
$this->data->groups = [];
// Get the default new user group, guest or public group if not specified.
$system = $params->get('new_usertype', $params->get('guest_usergroup', 1));
$this->data->groups[] = $system;
// Unset the passwords.
unset($this->data->password1, $this->data->password2);
// Get the dispatcher and load the users plugins.
PluginHelper::importPlugin('user');
// Trigger the data preparation event.
Factory::getApplication()->triggerEvent('onContentPrepareData', ['com_users.registration', $this->data]);
}
return $this->data;
}
/**
* Method to get the registration form.
*
* The base form is loaded from XML and then an event is fired
* for users plugins to extend the form with extra fields.
*
* @param array $data An optional array of data for the form to interrogate.
* @param boolean $loadData True if the form is to load its own data (default case), false if not.
*
* @return Form A Form object on success, false on failure
*
* @since 1.6
*/
public function getForm($data = [], $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_users.registration', 'registration', ['control' => 'jform', 'load_data' => $loadData]);
if (empty($form)) {
return false;
}
// When multilanguage is set, a user's default site language should also be a Content Language
if (Multilanguage::isEnabled()) {
$form->setFieldAttribute('language', 'type', 'frontendlanguage', 'params');
}
return $form;
}
/**
* Method to get the data that should be injected in the form.
*
* @return mixed The data for the form.
*
* @since 1.6
*/
protected function loadFormData()
{
$data = $this->getData();
if (Multilanguage::isEnabled() && empty($data->language)) {
$data->language = Factory::getLanguage()->getTag();
}
$this->preprocessData('com_users.registration', $data);
return $data;
}
/**
* Override preprocessForm to load the user plugin group instead of content.
*
* @param Form $form A Form object.
* @param mixed $data The data expected for the form.
* @param string $group The name of the plugin group to import (defaults to "content").
*
* @return void
*
* @since 1.6
* @throws \Exception if there is an error in the form event.
*/
protected function preprocessForm(Form $form, $data, $group = 'user')
{
$userParams = ComponentHelper::getParams('com_users');
// Add the choice for site language at registration time
if ($userParams->get('site_language') == 1 && $userParams->get('frontend_userparams') == 1) {
$form->loadFile('sitelang', false);
}
parent::preprocessForm($form, $data, $group);
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
protected function populateState()
{
// Get the application object.
$app = Factory::getApplication();
$params = $app->getParams('com_users');
// Load the parameters.
$this->setState('params', $params);
}
/**
* Method to save the form data.
*
* @param array $temp The form data.
*
* @return mixed The user id on success, false on failure.
*
* @since 1.6
* @throws \Exception
*/
public function register($temp)
{
$params = ComponentHelper::getParams('com_users');
// Initialise the table with Joomla\CMS\User\User.
$user = new User();
$data = (array) $this->getData();
// Merge in the registration data.
foreach ($temp as $k => $v) {
$data[$k] = $v;
}
// Prepare the data for the user object.
$data['email'] = PunycodeHelper::emailToPunycode($data['email1']);
$data['password'] = $data['password1'];
$useractivation = $params->get('useractivation');
$sendpassword = $params->get('sendpassword', 1);
// Check if the user needs to activate their account.
if (($useractivation == 1) || ($useractivation == 2)) {
$data['activation'] = ApplicationHelper::getHash(UserHelper::genRandomPassword());
$data['block'] = 1;
}
// Bind the data.
if (!$user->bind($data)) {
$this->setError($user->getError());
return false;
}
// Load the users plugin group.
PluginHelper::importPlugin('user');
// Store the data.
if (!$user->save()) {
$this->setError(Text::sprintf('COM_USERS_REGISTRATION_SAVE_FAILED', $user->getError()));
return false;
}
$app = Factory::getApplication();
$db = $this->getDatabase();
$query = $db->getQuery(true);
// Compile the notification mail values.
$data = $user->getProperties();
$data['fromname'] = $app->get('fromname');
$data['mailfrom'] = $app->get('mailfrom');
$data['sitename'] = $app->get('sitename');
$data['siteurl'] = Uri::root();
// Handle account activation/confirmation emails.
if ($useractivation == 2) {
// Set the link to confirm the user email.
$linkMode = $app->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE;
$data['activate'] = Route::link(
'site',
'index.php?option=com_users&task=registration.activate&token=' . $data['activation'],
false,
$linkMode,
true
);
$mailtemplate = 'com_users.registration.user.admin_activation';
} elseif ($useractivation == 1) {
// Set the link to activate the user account.
$linkMode = $app->get('force_ssl', 0) == 2 ? Route::TLS_FORCE : Route::TLS_IGNORE;
$data['activate'] = Route::link(
'site',
'index.php?option=com_users&task=registration.activate&token=' . $data['activation'],
false,
$linkMode,
true
);
$mailtemplate = 'com_users.registration.user.self_activation';
} else {
$mailtemplate = 'com_users.registration.user.registration_mail';
}
if ($sendpassword) {
$mailtemplate .= '_w_pw';
}
// Try to send the registration email.
try {
$mailer = new MailTemplate($mailtemplate, $app->getLanguage()->getTag());
$mailer->addTemplateData($data);
$mailer->addRecipient($data['email']);
$mailer->addUnsafeTags(['username', 'password_clear', 'name']);
$return = $mailer->send();
} catch (\Exception $exception) {
try {
Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror');
$return = false;
} catch (\RuntimeException $exception) {
Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning');
$this->setError(Text::_('COM_MESSAGES_ERROR_MAIL_FAILED'));
$return = false;
}
}
// Send mail to all users with user creating permissions and receiving system emails
if (($params->get('useractivation') < 2) && ($params->get('mail_to_admin') == 1)) {
// Get all admin users
$query->clear()
->select($db->quoteName(['name', 'email', 'sendEmail', 'id']))
->from($db->quoteName('#__users'))
->where($db->quoteName('sendEmail') . ' = 1')
->where($db->quoteName('block') . ' = 0');
$db->setQuery($query);
try {
$rows = $db->loadObjectList();
} catch (\RuntimeException $e) {
$this->setError(Text::sprintf('COM_USERS_DATABASE_ERROR', $e->getMessage()));
return false;
}
// Send mail to all superadministrators id
foreach ($rows as $row) {
$usercreator = $this->getUserFactory()->loadUserById($row->id);
if (!$usercreator->authorise('core.create', 'com_users') || !$usercreator->authorise('core.manage', 'com_users')) {
continue;
}
try {
$mailer = new MailTemplate('com_users.registration.admin.new_notification', $app->getLanguage()->getTag());
$mailer->addTemplateData($data);
$mailer->addRecipient($row->email);
$mailer->addUnsafeTags(['username', 'name']);
$return = $mailer->send();
} catch (\Exception $exception) {
try {
Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror');
$return = false;
} catch (\RuntimeException $exception) {
Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning');
$return = false;
}
}
// Check for an error.
if ($return !== true) {
$this->setError(Text::_('COM_USERS_REGISTRATION_ACTIVATION_NOTIFY_SEND_MAIL_FAILED'));
return false;
}
}
}
// Check for an error.
if ($return !== true) {
$this->setError(Text::_('COM_USERS_REGISTRATION_SEND_MAIL_FAILED'));
// Send a system message to administrators receiving system mails
$db = $this->getDatabase();
$query->clear()
->select($db->quoteName('id'))
->from($db->quoteName('#__users'))
->where($db->quoteName('block') . ' = 0')
->where($db->quoteName('sendEmail') . ' = 1');
$db->setQuery($query);
try {
$userids = $db->loadColumn();
} catch (\RuntimeException $e) {
$this->setError(Text::sprintf('COM_USERS_DATABASE_ERROR', $e->getMessage()));
return false;
}
if (\count($userids) > 0) {
$jdate = new Date();
$dateToSql = $jdate->toSql();
$subject = Text::_('COM_USERS_MAIL_SEND_FAILURE_SUBJECT');
$message = Text::sprintf('COM_USERS_MAIL_SEND_FAILURE_BODY', $data['username']);
// Build the query to add the messages
foreach ($userids as $userid) {
$values = [
':user_id_from',
':user_id_to',
':date_time',
':subject',
':message',
];
$query->clear()
->insert($db->quoteName('#__messages'))
->columns($db->quoteName(['user_id_from', 'user_id_to', 'date_time', 'subject', 'message']))
->values(implode(',', $values));
$query->bind(':user_id_from', $userid, ParameterType::INTEGER)
->bind(':user_id_to', $userid, ParameterType::INTEGER)
->bind(':date_time', $dateToSql)
->bind(':subject', $subject)
->bind(':message', $message);
$db->setQuery($query);
try {
$db->execute();
} catch (\RuntimeException $e) {
$this->setError(Text::sprintf('COM_USERS_DATABASE_ERROR', $e->getMessage()));
return false;
}
}
}
return false;
}
if ($useractivation == 1) {
return 'useractivate';
}
if ($useractivation == 2) {
return 'adminactivate';
}
return $user->id;
}
}

View File

@ -0,0 +1,211 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Model;
use Joomla\CMS\Event\User\AfterRemindEvent;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Mail\MailTemplate;
use Joomla\CMS\MVC\Model\FormModel;
use Joomla\CMS\Router\Route;
use Joomla\CMS\String\PunycodeHelper;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Remind model class for Users.
*
* @since 1.5
*/
class RemindModel extends FormModel
{
/**
* Method to get the username remind request form.
*
* @param array $data An optional array of data for the form to interrogate.
* @param boolean $loadData True if the form is to load its own data (default case), false if not.
*
* @return Form|bool A Form object on success, false on failure
*
* @since 1.6
*/
public function getForm($data = [], $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_users.remind', 'remind', ['control' => 'jform', 'load_data' => $loadData]);
if (empty($form)) {
return false;
}
return $form;
}
/**
* Override preprocessForm to load the user plugin group instead of content.
*
* @param Form $form A Form object.
* @param mixed $data The data expected for the form.
* @param string $group The name of the plugin group to import (defaults to "content").
*
* @return void
*
* @throws \Exception if there is an error in the form event.
*
* @since 1.6
*/
protected function preprocessForm(Form $form, $data, $group = 'user')
{
parent::preprocessForm($form, $data, 'user');
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @return void
*
* @since 1.6
*
* @throws \Exception
*/
protected function populateState()
{
// Get the application object.
$app = Factory::getApplication();
$params = $app->getParams('com_users');
// Load the parameters.
$this->setState('params', $params);
}
/**
* Send the remind username email
*
* @param array $data Array with the data received from the form
*
* @return boolean
*
* @since 1.6
*/
public function processRemindRequest($data)
{
// Get the form.
$form = $this->getForm();
$data['email'] = PunycodeHelper::emailToPunycode($data['email']);
// Check for an error.
if (empty($form)) {
return false;
}
// Validate the data.
$data = $this->validate($form, $data);
// Check for an error.
if ($data instanceof \Exception) {
return false;
}
// Check the validation results.
if ($data === false) {
// Get the validation messages from the form.
foreach ($form->getErrors() as $formError) {
$this->setError($formError->getMessage());
}
return false;
}
// Find the user id for the given email address.
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__users'))
->where('LOWER(' . $db->quoteName('email') . ') = LOWER(:email)')
->bind(':email', $data['email']);
// Get the user id.
$db->setQuery($query);
try {
$user = $db->loadObject();
} catch (\RuntimeException $e) {
$this->setError(Text::sprintf('COM_USERS_DATABASE_ERROR', $e->getMessage()));
return false;
}
// Check for a user.
if (empty($user)) {
$this->setError(Text::_('COM_USERS_USER_NOT_FOUND'));
return false;
}
// Make sure the user isn't blocked.
if ($user->block) {
$this->setError(Text::_('COM_USERS_USER_BLOCKED'));
return false;
}
$app = Factory::getApplication();
// Assemble the login link.
$link = 'index.php?option=com_users&view=login';
$mode = $app->get('force_ssl', 0) == 2 ? 1 : (-1);
// Put together the email template data.
$data = ArrayHelper::fromObject($user);
$data['sitename'] = $app->get('sitename');
$data['link_text'] = Route::_($link, false, $mode);
$data['link_html'] = Route::_($link, true, $mode);
$mailer = new MailTemplate('com_users.reminder', $app->getLanguage()->getTag());
$mailer->addTemplateData($data);
$mailer->addRecipient($user->email, $user->name);
// Try to send the password reset request email.
try {
$return = $mailer->send();
} catch (\Exception $exception) {
try {
Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror');
$return = false;
} catch (\RuntimeException $exception) {
Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning');
$return = false;
}
}
// Check for an error.
if ($return !== true) {
$this->setError(Text::_('COM_USERS_MAIL_FAILED'));
return false;
}
$this->getDispatcher()->dispatch('onUserAfterRemind', new AfterRemindEvent('onUserAfterRemind', [
'subject' => $user,
]));
return true;
}
}

View File

@ -0,0 +1,547 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Model;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Event\AbstractEvent;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Mail\MailTemplate;
use Joomla\CMS\MVC\Model\FormModel;
use Joomla\CMS\Router\Route;
use Joomla\CMS\String\PunycodeHelper;
use Joomla\CMS\User\User;
use Joomla\CMS\User\UserFactoryAwareInterface;
use Joomla\CMS\User\UserFactoryAwareTrait;
use Joomla\CMS\User\UserHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Reset model class for Users.
*
* @since 1.5
*/
class ResetModel extends FormModel implements UserFactoryAwareInterface
{
use UserFactoryAwareTrait;
/**
* Method to get the password reset request form.
*
* The base form is loaded from XML and then an event is fired
* for users plugins to extend the form with extra fields.
*
* @param array $data An optional array of data for the form to interrogate.
* @param boolean $loadData True if the form is to load its own data (default case), false if not.
*
* @return Form A Form object on success, false on failure
*
* @since 1.6
*/
public function getForm($data = [], $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_users.reset_request', 'reset_request', ['control' => 'jform', 'load_data' => $loadData]);
if (empty($form)) {
return false;
}
return $form;
}
/**
* Method to get the password reset complete form.
*
* @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 Form A Form object on success, false on failure
*
* @since 1.6
*/
public function getResetCompleteForm($data = [], $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_users.reset_complete', 'reset_complete', $options = ['control' => 'jform']);
if (empty($form)) {
return false;
}
return $form;
}
/**
* Method to get the password reset confirm form.
*
* @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 Form A Form object on success, false on failure
*
* @since 1.6
* @throws \Exception
*/
public function getResetConfirmForm($data = [], $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_users.reset_confirm', 'reset_confirm', $options = ['control' => 'jform']);
if (empty($form)) {
return false;
}
$form->setValue('token', '', Factory::getApplication()->getInput()->get('token'));
return $form;
}
/**
* Override preprocessForm to load the user plugin group instead of content.
*
* @param Form $form A Form object.
* @param mixed $data The data expected for the form.
* @param string $group The name of the plugin group to import (defaults to "content").
*
* @return void
*
* @throws \Exception if there is an error in the form event.
*
* @since 1.6
*/
protected function preprocessForm(Form $form, $data, $group = 'user')
{
parent::preprocessForm($form, $data, $group);
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
protected function populateState()
{
// Get the application object.
$params = Factory::getApplication()->getParams('com_users');
// Load the parameters.
$this->setState('params', $params);
}
/**
* Save the new password after reset is done
*
* @param array $data The data expected for the form.
*
* @return mixed \Exception | boolean
*
* @since 1.6
* @throws \Exception
*/
public function processResetComplete($data)
{
// Get the form.
$form = $this->getResetCompleteForm();
// 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 token and user id from the confirmation process.
$app = Factory::getApplication();
$token = $app->getUserState('com_users.reset.token', null);
$userId = $app->getUserState('com_users.reset.user', null);
// Check the token and user id.
if (empty($token) || empty($userId)) {
return new \Exception(Text::_('COM_USERS_RESET_COMPLETE_TOKENS_MISSING'), 403);
}
// Get the user object.
$user = $this->getUserFactory()->loadUserById($userId);
$event = AbstractEvent::create(
'onUserBeforeResetComplete',
[
'subject' => $user,
]
);
$app->getDispatcher()->dispatch($event->getName(), $event);
// Check for a user and that the tokens match.
if (empty($user) || $user->activation !== $token) {
$this->setError(Text::_('COM_USERS_USER_NOT_FOUND'));
return false;
}
// Make sure the user isn't blocked.
if ($user->block) {
$this->setError(Text::_('COM_USERS_USER_BLOCKED'));
return false;
}
// Check if the user is reusing the current password if required to reset their password
if ($user->requireReset == 1 && UserHelper::verifyPassword($data['password1'], $user->password)) {
$this->setError(Text::_('JLIB_USER_ERROR_CANNOT_REUSE_PASSWORD'));
return false;
}
// Prepare user data.
$data['password'] = $data['password1'];
$data['activation'] = '';
// Update the user object.
if (!$user->bind($data)) {
return new \Exception($user->getError(), 500);
}
// Save the user to the database.
if (!$user->save(true)) {
return new \Exception(Text::sprintf('COM_USERS_USER_SAVE_FAILED', $user->getError()), 500);
}
// Destroy all active sessions for the user
UserHelper::destroyUserSessions($user->id);
// Flush the user data from the session.
$app->setUserState('com_users.reset.token', null);
$app->setUserState('com_users.reset.user', null);
$event = AbstractEvent::create(
'onUserAfterResetComplete',
[
'subject' => $user,
]
);
$app->getDispatcher()->dispatch($event->getName(), $event);
return true;
}
/**
* Receive the reset password request
*
* @param array $data The data expected for the form.
*
* @return mixed \Exception | boolean
*
* @since 1.6
* @throws \Exception
*/
public function processResetConfirm($data)
{
// Get the form.
$form = $this->getResetConfirmForm();
// 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;
}
// Find the user id for the given token.
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName(['activation', 'id', 'block']))
->from($db->quoteName('#__users'))
->where($db->quoteName('username') . ' = :username')
->bind(':username', $data['username']);
// Get the user id.
$db->setQuery($query);
try {
$user = $db->loadObject();
} catch (\RuntimeException $e) {
return new \Exception(Text::sprintf('COM_USERS_DATABASE_ERROR', $e->getMessage()), 500);
}
// Check for a user.
if (empty($user)) {
$this->setError(Text::_('COM_USERS_USER_NOT_FOUND'));
return false;
}
if (!$user->activation) {
$this->setError(Text::_('COM_USERS_USER_NOT_FOUND'));
return false;
}
// Verify the token
if (!UserHelper::verifyPassword($data['token'], $user->activation)) {
$this->setError(Text::_('COM_USERS_USER_NOT_FOUND'));
return false;
}
// Make sure the user isn't blocked.
if ($user->block) {
$this->setError(Text::_('COM_USERS_USER_BLOCKED'));
return false;
}
// Push the user data into the session.
$app = Factory::getApplication();
$app->setUserState('com_users.reset.token', $user->activation);
$app->setUserState('com_users.reset.user', $user->id);
return true;
}
/**
* Method to start the password reset process.
*
* @param array $data The data expected for the form.
*
* @return mixed \Exception | boolean
*
* @since 1.6
* @throws \Exception
*/
public function processResetRequest($data)
{
$app = Factory::getApplication();
// Get the form.
$form = $this->getForm();
$data['email'] = PunycodeHelper::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;
}
// Find the user id for the given email address.
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName('id'))
->from($db->quoteName('#__users'))
->where('LOWER(' . $db->quoteName('email') . ') = LOWER(:email)')
->bind(':email', $data['email']);
// Get the user object.
$db->setQuery($query);
try {
$userId = $db->loadResult();
} catch (\RuntimeException $e) {
$this->setError(Text::sprintf('COM_USERS_DATABASE_ERROR', $e->getMessage()));
return false;
}
// Check for a user.
if (empty($userId)) {
$this->setError(Text::_('COM_USERS_INVALID_EMAIL'));
return false;
}
// Get the user object.
$user = $this->getUserFactory()->loadUserById($userId);
// Make sure the user isn't blocked.
if ($user->block) {
$this->setError(Text::_('COM_USERS_USER_BLOCKED'));
return false;
}
// Make sure the user isn't a Super Admin.
if ($user->authorise('core.admin')) {
$this->setError(Text::_('COM_USERS_REMIND_SUPERADMIN_ERROR'));
return false;
}
// Make sure the user has not exceeded the reset limit
if (!$this->checkResetLimit($user)) {
$resetLimit = (int) Factory::getApplication()->getParams()->get('reset_time');
$this->setError(Text::plural('COM_USERS_REMIND_LIMIT_ERROR_N_HOURS', $resetLimit));
return false;
}
// Set the confirmation token.
$token = ApplicationHelper::getHash(UserHelper::genRandomPassword());
$hashedToken = UserHelper::hashPassword($token);
$user->activation = $hashedToken;
$event = AbstractEvent::create(
'onUserBeforeResetRequest',
[
'subject' => $user,
]
);
$app->getDispatcher()->dispatch($event->getName(), $event);
// Save the user to the database.
if (!$user->save(true)) {
return new \Exception(Text::sprintf('COM_USERS_USER_SAVE_FAILED', $user->getError()), 500);
}
// Assemble the password reset confirmation link.
$mode = $app->get('force_ssl', 0) == 2 ? 1 : (-1);
$link = 'index.php?option=com_users&view=reset&layout=confirm&token=' . $token;
// Put together the email template data.
$data = $user->getProperties();
$data['sitename'] = $app->get('sitename');
$data['link_text'] = Route::_($link, false, $mode);
$data['link_html'] = Route::_($link, true, $mode);
$data['token'] = $token;
$mailer = new MailTemplate('com_users.password_reset', $app->getLanguage()->getTag());
$mailer->addTemplateData($data);
$mailer->addRecipient($user->email, $user->name);
// Try to send the password reset request email.
try {
$return = $mailer->send();
} catch (\Exception $exception) {
try {
Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror');
$return = false;
} catch (\RuntimeException $exception) {
$app->enqueueMessage(Text::_($exception->errorMessage()), 'warning');
$return = false;
}
}
// Check for an error.
if ($return !== true) {
return new \Exception(Text::_('COM_USERS_MAIL_FAILED'), 500);
}
$event = AbstractEvent::create(
'onUserAfterResetRequest',
[
'subject' => $user,
]
);
$app->getDispatcher()->dispatch($event->getName(), $event);
return true;
}
/**
* Method to check if user reset limit has been exceeded within the allowed time period.
*
* @param User $user User doing the password reset
*
* @return boolean true if user can do the reset, false if limit exceeded
*
* @since 2.5
* @throws \Exception
*/
public function checkResetLimit($user)
{
$params = Factory::getApplication()->getParams();
$maxCount = (int) $params->get('reset_count');
$resetHours = (int) $params->get('reset_time');
$result = true;
$lastResetTime = strtotime($user->lastResetTime) ?: 0;
$hoursSinceLastReset = (strtotime(Factory::getDate()->toSql()) - $lastResetTime) / 3600;
if ($hoursSinceLastReset > $resetHours) {
// If it's been long enough, start a new reset count
$user->lastResetTime = Factory::getDate()->toSql();
$user->resetCount = 1;
} elseif ($user->resetCount < $maxCount) {
// If we are under the max count, just increment the counter
++$user->resetCount;
} else {
// At this point, we know we have exceeded the maximum resets for the time period
$result = false;
}
return $result;
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Rule;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormRule;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* FormRule for com_users to be sure only one redirect login field has a value
*
* @since 3.6
*/
class LoginUniqueFieldRule extends FormRule
{
/**
* Method to test if two fields have a value in order to use only one field.
* To use this rule, the form
* XML needs a validate attribute of loginuniquefield and a field attribute
* that is equal to the field to test against.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value. This acts as an array container for the field.
* For example if the field has name="foo" and the group value is set to "bar" then the
* full field name would end up being "bar[foo]".
* @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form.
* @param ?Form $form The form object for which the field is being tested.
*
* @return boolean True if the value is valid, false otherwise.
*
* @since 3.6
*/
public function test(\SimpleXMLElement $element, $value, $group = null, ?Registry $input = null, ?Form $form = null)
{
$loginRedirectUrl = $input['params']->login_redirect_url;
$loginRedirectMenuitem = $input['params']->login_redirect_menuitem;
if ($form === null) {
throw new \InvalidArgumentException(\sprintf('The value for $form must not be null in %s', \get_class($this)));
}
if ($input === null) {
throw new \InvalidArgumentException(\sprintf('The value for $input must not be null in %s', \get_class($this)));
}
// Test the input values for login.
if ($loginRedirectUrl != '' && $loginRedirectMenuitem != '') {
return false;
}
return true;
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Rule;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormRule;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* FormRule for com_users to be sure only one redirect logout field has a value
*
* @since 3.6
*/
class LogoutUniqueFieldRule extends FormRule
{
/**
* Method to test if two fields have a value in order to use only one field.
* To use this rule, the form
* XML needs a validate attribute of logoutuniquefield and a field attribute
* that is equal to the field to test against.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value. This acts as an array container for the field.
* For example if the field has name="foo" and the group value is set to "bar" then the
* full field name would end up being "bar[foo]".
* @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form.
* @param ?Form $form The form object for which the field is being tested.
*
* @return boolean True if the value is valid, false otherwise.
*
* @since 3.6
*/
public function test(\SimpleXMLElement $element, $value, $group = null, ?Registry $input = null, ?Form $form = null)
{
$logoutRedirectUrl = $input['params']->logout_redirect_url;
$logoutRedirectMenuitem = $input['params']->logout_redirect_menuitem;
if ($form === null) {
throw new \InvalidArgumentException(\sprintf('The value for $form must not be null in %s', \get_class($this)));
}
if ($input === null) {
throw new \InvalidArgumentException(\sprintf('The value for $input must not be null in %s', \get_class($this)));
}
// Test the input values for logout.
if ($logoutRedirectUrl != '' && $logoutRedirectMenuitem != '') {
return false;
}
return true;
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\Service;
use Joomla\CMS\Application\SiteApplication;
use Joomla\CMS\Component\Router\RouterView;
use Joomla\CMS\Component\Router\RouterViewConfiguration;
use Joomla\CMS\Component\Router\Rules\MenuRules;
use Joomla\CMS\Component\Router\Rules\NomenuRules;
use Joomla\CMS\Component\Router\Rules\StandardRules;
use Joomla\CMS\Menu\AbstractMenu;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Routing class from com_users
*
* @since 3.2
*/
class Router extends RouterView
{
/**
* Users Component router constructor
*
* @param SiteApplication $app The application object
* @param AbstractMenu $menu The menu object to work with
*/
public function __construct(SiteApplication $app, AbstractMenu $menu)
{
$this->registerView(new RouterViewConfiguration('login'));
$profile = new RouterViewConfiguration('profile');
$profile->addLayout('edit');
$this->registerView($profile);
$this->registerView(new RouterViewConfiguration('registration'));
$this->registerView(new RouterViewConfiguration('remind'));
$this->registerView(new RouterViewConfiguration('reset'));
$this->registerView(new RouterViewConfiguration('callback'));
$this->registerView(new RouterViewConfiguration('captive'));
$this->registerView(new RouterViewConfiguration('methods'));
$method = new RouterViewConfiguration('method');
$method->setKey('id');
$this->registerView($method);
parent::__construct($app, $menu);
$this->attachRule(new MenuRules($this));
$this->attachRule(new StandardRules($this));
$this->attachRule(new NomenuRules($this));
}
/**
* Get the method ID from a URL segment
*
* @param string $segment The URL segment
* @param array $query The URL query parameters
*
* @return integer
* @since 4.2.0
*/
public function getMethodId($segment, $query)
{
return (int) $segment;
}
/**
* Get a segment from a method ID
*
* @param integer $id The method ID
* @param array $query The URL query parameters
*
* @return int[]
* @since 4.2.0
*/
public function getMethodSegment($id, $query)
{
return [$id => (int) $id];
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\View\Captive;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* View for Multi-factor Authentication captive page
*
* @since 4.2.0
*/
class HtmlView extends \Joomla\Component\Users\Administrator\View\Captive\HtmlView
{
}

View File

@ -0,0 +1,158 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\View\Login;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\AuthenticationHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\User\User;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Login view class for Users.
*
* @since 1.5
*/
class HtmlView extends BaseHtmlView
{
/**
* The Form object
*
* @var \Joomla\CMS\Form\Form
*/
protected $form;
/**
* The page parameters
*
* @var \Joomla\Registry\Registry|null
*/
protected $params;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* The logged in user
*
* @var User
*/
protected $user;
/**
* The page class suffix
*
* @var string
* @since 4.0.0
*/
protected $pageclass_sfx = '';
/**
* No longer used
*
* @var boolean
* @since 4.0.0
*
* @deprecated 4.3 will be removed in 6.0
* Will be removed without replacement
*/
protected $tfa = false;
/**
* Additional buttons to show on the login page
*
* @var array
* @since 4.0.0
*/
protected $extraButtons = [];
/**
* Method to display the view.
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void
*
* @since 1.5
* @throws \Exception
*/
public function display($tpl = null)
{
// Get the view data.
$this->user = $this->getCurrentUser();
$this->form = $this->get('Form');
$this->state = $this->get('State');
$this->params = $this->state->get('params');
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
// Check for layout override
$active = Factory::getApplication()->getMenu()->getActive();
if (isset($active->query['layout'])) {
$this->setLayout($active->query['layout']);
}
$this->extraButtons = AuthenticationHelper::getLoginButtons('com-users-login__form');
// Escape strings for HTML output
$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''), ENT_COMPAT, 'UTF-8');
$this->prepareDocument();
parent::display($tpl);
}
/**
* Prepares the document
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
protected function prepareDocument()
{
$login = (bool) $this->getCurrentUser()->guest;
// Because the application sets a default page title,
// we need to get it from the menu item itself
$menu = Factory::getApplication()->getMenu()->getActive();
if ($menu) {
$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
} else {
$this->params->def('page_heading', $login ? Text::_('JLOGIN') : Text::_('JLOGOUT'));
}
$this->setDocumentTitle($this->params->get('page_title', ''));
if ($this->params->get('menu-meta_description')) {
$this->getDocument()->setDescription($this->params->get('menu-meta_description'));
}
if ($this->params->get('robots')) {
$this->getDocument()->setMetaData('robots', $this->params->get('robots'));
}
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\View\Method;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* View for Multi-factor Authentication method add/edit page
*
* @since 4.2.0
*/
class HtmlView extends \Joomla\Component\Users\Administrator\View\Method\HtmlView
{
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @package Joomla.Administrator
* @subpackage com_users
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\View\Methods;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* View for Multi-factor Authentication methods list page
*
* @since 4.2.0
*/
class HtmlView extends \Joomla\Component\Users\Administrator\View\Methods\HtmlView
{
}

View File

@ -0,0 +1,190 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\View\Profile;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Object\CMSObject;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\User\User;
use Joomla\Component\Users\Administrator\Helper\Mfa;
use Joomla\Database\DatabaseDriver;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Profile view class for Users.
*
* @since 1.6
*/
class HtmlView extends BaseHtmlView
{
/**
* Profile form data for the user
*
* @var User
*/
protected $data;
/**
* The Form object
*
* @var \Joomla\CMS\Form\Form
*/
protected $form;
/**
* The page parameters
*
* @var \Joomla\Registry\Registry|null
*/
protected $params;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* An instance of DatabaseDriver.
*
* @var DatabaseDriver
* @since 3.6.3
*
* @deprecated 4.3 will be removed in 6.0
* Will be removed without replacement use database from the container instead
* Example: Factory::getContainer()->get(DatabaseInterface::class);
*/
protected $db;
/**
* The page class suffix
*
* @var string
* @since 4.0.0
*/
protected $pageclass_sfx = '';
/**
* The Multi-factor Authentication configuration interface for the user.
*
* @var string|null
* @since 4.2.0
*/
protected $mfaConfigurationUI;
/**
* Execute and display a template script.
*
* @param string $tpl The name of the template file to parse; automatically searches through the template paths.
*
* @return void|boolean
*
* @since 1.6
* @throws \Exception
*/
public function display($tpl = null)
{
$user = $this->getCurrentUser();
// Get the view data.
$this->data = $this->get('Data');
$this->form = $this->getModel()->getForm(new CMSObject(['id' => $user->id]));
$this->state = $this->get('State');
$this->params = $this->state->get('params');
$this->mfaConfigurationUI = Mfa::getConfigurationInterface($user);
$this->db = Factory::getDbo();
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
// View also takes responsibility for checking if the user logged in with remember me.
$cookieLogin = $user->get('cookieLogin');
if (!empty($cookieLogin)) {
// If so, the user must login to edit the password and other data.
// What should happen here? Should we force a logout which destroys the cookies?
$app = Factory::getApplication();
$app->enqueueMessage(Text::_('JGLOBAL_REMEMBER_MUST_LOGIN'), 'message');
$app->redirect(Route::_('index.php?option=com_users&view=login', false));
return false;
}
// Check if a user was found.
if (!$this->data->id) {
throw new \Exception(Text::_('JERROR_USERS_PROFILE_NOT_FOUND'), 404);
}
PluginHelper::importPlugin('content');
$this->data->text = '';
Factory::getApplication()->triggerEvent('onContentPrepare', ['com_users.user', &$this->data, &$this->data->params, 0]);
unset($this->data->text);
// Check for layout from menu item.
$active = Factory::getApplication()->getMenu()->getActive();
if (
$active && isset($active->query['layout'])
&& isset($active->query['option']) && $active->query['option'] === 'com_users'
&& isset($active->query['view']) && $active->query['view'] === 'profile'
) {
$this->setLayout($active->query['layout']);
}
// Escape strings for HTML output
$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''));
$this->prepareDocument();
parent::display($tpl);
}
/**
* Prepares the document
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
protected function prepareDocument()
{
// Because the application sets a default page title,
// we need to get it from the menu item itself
$menu = Factory::getApplication()->getMenu()->getActive();
if ($menu) {
$this->params->def('page_heading', $this->params->get('page_title', $this->getCurrentUser()->name));
} else {
$this->params->def('page_heading', Text::_('COM_USERS_PROFILE'));
}
$this->setDocumentTitle($this->params->get('page_title', ''));
if ($this->params->get('menu-meta_description')) {
$this->getDocument()->setDescription($this->params->get('menu-meta_description'));
}
if ($this->params->get('robots')) {
$this->getDocument()->setMetaData('robots', $this->params->get('robots'));
}
}
}

View File

@ -0,0 +1,160 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\View\Registration;
use Joomla\CMS\Document\HtmlDocument;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Plugin\PluginHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Registration view class for Users.
*
* @since 1.6
*/
class HtmlView extends BaseHtmlView
{
/**
* Registration form data
*
* @var \stdClass|false
*/
protected $data;
/**
* The Form object
*
* @var \Joomla\CMS\Form\Form
*/
protected $form;
/**
* The page parameters
*
* @var \Joomla\Registry\Registry|null
*/
protected $params;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* The HtmlDocument instance
*
* @var HtmlDocument
*/
public $document;
/**
* Should we show a captcha form for the submission of the article?
*
* @var boolean
*
* @since 3.7.0
*/
protected $captchaEnabled = false;
/**
* The page class suffix
*
* @var string
* @since 4.0.0
*/
protected $pageclass_sfx = '';
/**
* Method to display the view.
*
* @param string $tpl The template file to include
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
public function display($tpl = null)
{
// Get the view data.
$this->form = $this->get('Form');
$this->data = $this->get('Data');
$this->state = $this->get('State');
$this->params = $this->state->get('params');
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
// Check for layout override
$active = Factory::getApplication()->getMenu()->getActive();
if (isset($active->query['layout'])) {
$this->setLayout($active->query['layout']);
}
$captchaSet = $this->params->get('captcha', Factory::getApplication()->get('captcha', '0'));
foreach (PluginHelper::getPlugin('captcha') as $plugin) {
if ($captchaSet === $plugin->name) {
$this->captchaEnabled = true;
break;
}
}
// Escape strings for HTML output
$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''), ENT_COMPAT, 'UTF-8');
$this->prepareDocument();
parent::display($tpl);
}
/**
* Prepares the document.
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
protected function prepareDocument()
{
// Because the application sets a default page title,
// we need to get it from the menu item itself
$menu = Factory::getApplication()->getMenu()->getActive();
if ($menu) {
$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
} else {
$this->params->def('page_heading', Text::_('COM_USERS_REGISTRATION'));
}
$this->setDocumentTitle($this->params->get('page_title', ''));
if ($this->params->get('menu-meta_description')) {
$this->getDocument()->setDescription($this->params->get('menu-meta_description'));
}
if ($this->params->get('robots')) {
$this->getDocument()->setMetaData('robots', $this->params->get('robots'));
}
}
}

View File

@ -0,0 +1,125 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\View\Remind;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Remind view class for Users.
*
* @since 1.5
*/
class HtmlView extends BaseHtmlView
{
/**
* The Form object
*
* @var \Joomla\CMS\Form\Form
*/
protected $form;
/**
* The page parameters
*
* @var \Joomla\Registry\Registry|null
*/
protected $params;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* The page class suffix
*
* @var string
* @since 4.0.0
*/
protected $pageclass_sfx = '';
/**
* Method to display the view.
*
* @param string $tpl The template file to include
*
* @return void
*
* @since 1.5
* @throws \Exception
*/
public function display($tpl = null)
{
// Get the view data.
$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 GenericDataException(implode("\n", $errors), 500);
}
// Check for layout override
$active = Factory::getApplication()->getMenu()->getActive();
if (isset($active->query['layout'])) {
$this->setLayout($active->query['layout']);
}
// Escape strings for HTML output
$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''), ENT_COMPAT, 'UTF-8');
$this->prepareDocument();
parent::display($tpl);
}
/**
* Prepares the document.
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
protected function prepareDocument()
{
// Because the application sets a default page title,
// we need to get it from the menu item itself
$menu = Factory::getApplication()->getMenu()->getActive();
if ($menu) {
$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
} else {
$this->params->def('page_heading', Text::_('COM_USERS_REMIND'));
}
$this->setDocumentTitle($this->params->get('page_title', ''));
if ($this->params->get('menu-meta_description')) {
$this->getDocument()->setDescription($this->params->get('menu-meta_description'));
}
if ($this->params->get('robots')) {
$this->getDocument()->setMetaData('robots', $this->params->get('robots'));
}
}
}

View File

@ -0,0 +1,131 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_users
*
* @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Users\Site\View\Reset;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\GenericDataException;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Reset view class for Users.
*
* @since 1.5
*/
class HtmlView extends BaseHtmlView
{
/**
* The Form object
*
* @var \Joomla\CMS\Form\Form
*/
protected $form;
/**
* The page parameters
*
* @var \Joomla\Registry\Registry|null
*/
protected $params;
/**
* The model state
*
* @var \Joomla\Registry\Registry
*/
protected $state;
/**
* The page class suffix
*
* @var string
* @since 4.0.0
*/
protected $pageclass_sfx = '';
/**
* Method to display the view.
*
* @param string $tpl The template file to include
*
* @return void
*
* @since 1.5
*/
public function display($tpl = null)
{
// This name will be used to get the model
$name = $this->getLayout();
// Check that the name is valid - has an associated model.
if (!\in_array($name, ['confirm', 'complete'])) {
$name = 'default';
}
if ('default' === $name) {
$formname = 'Form';
} else {
$formname = ucfirst($this->_name) . ucfirst($name) . 'Form';
}
// Get the view data.
$this->form = $this->get($formname);
$this->state = $this->get('State');
$this->params = $this->state->params;
// Check for errors.
if (\count($errors = $this->get('Errors'))) {
throw new GenericDataException(implode("\n", $errors), 500);
}
// Escape strings for HTML output
$this->pageclass_sfx = htmlspecialchars($this->params->get('pageclass_sfx', ''), ENT_COMPAT, 'UTF-8');
$this->prepareDocument();
parent::display($tpl);
}
/**
* Prepares the document.
*
* @return void
*
* @since 1.6
* @throws \Exception
*/
protected function prepareDocument()
{
// Because the application sets a default page title,
// we need to get it from the menu item itself
$menu = Factory::getApplication()->getMenu()->getActive();
if ($menu) {
$this->params->def('page_heading', $this->params->get('page_title', $menu->title));
} else {
$this->params->def('page_heading', Text::_('COM_USERS_RESET'));
}
$this->setDocumentTitle($this->params->get('page_title', ''));
if ($this->params->get('menu-meta_description')) {
$this->getDocument()->setDescription($this->params->get('menu-meta_description'));
}
if ($this->params->get('robots')) {
$this->getDocument()->setMetaData('robots', $this->params->get('robots'));
}
}
}