diff options
Diffstat (limited to 'phpBB')
-rw-r--r-- | phpBB/config/default/container/services.yml | 1 | ||||
-rw-r--r-- | phpBB/config/default/container/services_ucp.yml | 17 | ||||
-rw-r--r-- | phpBB/config/default/routing/routing.yml | 4 | ||||
-rw-r--r-- | phpBB/config/default/routing/ucp.yml | 7 | ||||
-rw-r--r-- | phpBB/includes/functions.php | 5 | ||||
-rw-r--r-- | phpBB/includes/ucp/ucp_remind.php | 174 | ||||
-rw-r--r-- | phpBB/language/en/email/user_activate_passwd.txt | 17 | ||||
-rw-r--r-- | phpBB/language/en/email/user_forgot_password.txt | 13 | ||||
-rw-r--r-- | phpBB/language/en/ucp.php | 8 | ||||
-rw-r--r-- | phpBB/phpbb/db/migration/data/v330/reset_password.php | 48 | ||||
-rw-r--r-- | phpBB/phpbb/ucp/controller/reset_password.php | 443 | ||||
-rw-r--r-- | phpBB/styles/prosilver/template/ucp_remind.html | 37 | ||||
-rw-r--r-- | phpBB/styles/prosilver/template/ucp_reset_password.html | 49 | ||||
-rw-r--r-- | phpBB/ucp.php | 6 |
14 files changed, 595 insertions, 234 deletions
diff --git a/phpBB/config/default/container/services.yml b/phpBB/config/default/container/services.yml index 3ead1e6181..2d4720029d 100644 --- a/phpBB/config/default/container/services.yml +++ b/phpBB/config/default/container/services.yml @@ -27,6 +27,7 @@ imports: - { resource: services_text_formatter.yml } - { resource: services_text_reparser.yml } - { resource: services_twig.yml } + - { resource: services_ucp.yml } - { resource: services_user.yml } - { resource: tables.yml } diff --git a/phpBB/config/default/container/services_ucp.yml b/phpBB/config/default/container/services_ucp.yml new file mode 100644 index 0000000000..861fa4ac75 --- /dev/null +++ b/phpBB/config/default/container/services_ucp.yml @@ -0,0 +1,17 @@ +services: + phpbb.ucp.controller.reset_password: + class: phpbb\ucp\controller\reset_password + arguments: + - '@config' + - '@dbal.conn' + - '@dispatcher' + - '@controller.helper' + - '@language' + - '@log' + - '@passwords.manager' + - '@request' + - '@template' + - '@user' + - '%tables.users%' + - '%core.root_path%' + - '%core.php_ext%' diff --git a/phpBB/config/default/routing/routing.yml b/phpBB/config/default/routing/routing.yml index 199c5229b0..a5e9265dc3 100644 --- a/phpBB/config/default/routing/routing.yml +++ b/phpBB/config/default/routing/routing.yml @@ -26,3 +26,7 @@ phpbb_help_routing: phpbb_report_routing: resource: report.yml + +phpbb_ucp_routing: + resource: ucp.yml + prefix: /user diff --git a/phpBB/config/default/routing/ucp.yml b/phpBB/config/default/routing/ucp.yml new file mode 100644 index 0000000000..06bd7c3a58 --- /dev/null +++ b/phpBB/config/default/routing/ucp.yml @@ -0,0 +1,7 @@ +phpbb_ucp_reset_password_controller: + path: /reset_password + defaults: { _controller: phpbb.ucp.controller.reset_password:reset } + +phpbb_ucp_forgot_password_controller: + path: /forgot_password + defaults: { _controller: phpbb.ucp.controller.reset_password:request } diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 667aa2df19..e1f6fa3d1b 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -2516,11 +2516,14 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa $s_hidden_fields = build_hidden_fields($s_hidden_fields); + /** @var \phpbb\controller\helper $controller_helper */ + $controller_helper = $phpbb_container->get('controller.helper'); + $login_box_template_data = array( 'LOGIN_ERROR' => $err, 'LOGIN_EXPLAIN' => $l_explain, - 'U_SEND_PASSWORD' => ($config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') : '', + 'U_SEND_PASSWORD' => ($config['email_enable']) ? $controller_helper->route('phpbb_ucp_forgot_password_controller') : '', 'U_RESEND_ACTIVATION' => ($config['require_activation'] == USER_ACTIVATION_SELF && $config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=resend_act') : '', 'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'), 'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'), diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php deleted file mode 100644 index e50428bfea..0000000000 --- a/phpBB/includes/ucp/ucp_remind.php +++ /dev/null @@ -1,174 +0,0 @@ -<?php -/** -* -* This file is part of the phpBB Forum Software package. -* -* @copyright (c) phpBB Limited <https://www.phpbb.com> -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* ucp_remind -* Sending password reminders -*/ -class ucp_remind -{ - var $u_action; - - function main($id, $mode) - { - global $config, $phpbb_root_path, $phpEx, $request; - global $db, $user, $template, $phpbb_container, $phpbb_dispatcher; - - if (!$config['allow_password_reset']) - { - trigger_error($user->lang('UCP_PASSWORD_RESET_DISABLED', '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>')); - } - - $username = $request->variable('username', '', true); - $email = strtolower($request->variable('email', '')); - $submit = (isset($_POST['submit'])) ? true : false; - - add_form_key('ucp_remind'); - - if ($submit) - { - if (!check_form_key('ucp_remind')) - { - trigger_error('FORM_INVALID'); - } - - if (empty($email)) - { - trigger_error('NO_EMAIL_USER'); - } - - $sql_array = array( - 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type, user_lang, user_inactive_reason', - 'FROM' => array(USERS_TABLE => 'u'), - 'WHERE' => "user_email_hash = '" . $db->sql_escape(phpbb_email_hash($email)) . "'" . - (!empty($username) ? " AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'" : ''), - ); - - /** - * Change SQL query for fetching user data - * - * @event core.ucp_remind_modify_select_sql - * @var string email User's email from the form - * @var string username User's username from the form - * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE - * @since 3.1.11-RC1 - */ - $vars = array( - 'email', - 'username', - 'sql_array', - ); - extract($phpbb_dispatcher->trigger_event('core.ucp_remind_modify_select_sql', compact($vars))); - - $sql = $db->sql_build_query('SELECT', $sql_array); - $result = $db->sql_query_limit($sql, 2); // don't waste resources on more rows than we need - $rowset = $db->sql_fetchrowset($result); - - if (count($rowset) > 1) - { - $db->sql_freeresult($result); - - $template->assign_vars(array( - 'USERNAME_REQUIRED' => true, - 'EMAIL' => $email, - )); - } - else - { - $message = $user->lang['PASSWORD_UPDATED_IF_EXISTED'] . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>'); - - if (empty($rowset)) - { - trigger_error($message); - } - - $user_row = $rowset[0]; - $db->sql_freeresult($result); - - if (!$user_row) - { - trigger_error($message); - } - - if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) - { - trigger_error($message); - } - - // Check users permissions - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($user_row); - - if (!$auth2->acl_get('u_chgpasswd')) - { - trigger_error($message); - } - - $server_url = generate_board_url(); - - // Make password at least 8 characters long, make it longer if admin wants to. - // gen_rand_string() however has a limit of 12 or 13. - $user_password = gen_rand_string_friendly(max(8, mt_rand((int) $config['min_pass_chars'], (int) $config['max_pass_chars']))); - - // For the activation key a random length between 6 and 10 will do. - $user_actkey = gen_rand_string(mt_rand(6, 10)); - - // Instantiate passwords manager - /* @var $manager \phpbb\passwords\manager */ - $passwords_manager = $phpbb_container->get('passwords.manager'); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_newpasswd = '" . $db->sql_escape($passwords_manager->hash($user_password)) . "', user_actkey = '" . $db->sql_escape($user_actkey) . "' - WHERE user_id = " . $user_row['user_id']; - $db->sql_query($sql); - - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - - $messenger = new messenger(false); - - $messenger->template('user_activate_passwd', $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($config, $user); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'PASSWORD' => htmlspecialchars_decode($user_password), - 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey") - ); - - $messenger->send($user_row['user_notify_type']); - - trigger_error($message); - } - } - - $template->assign_vars(array( - 'USERNAME' => $username, - 'EMAIL' => $email, - 'S_PROFILE_ACTION' => append_sid($phpbb_root_path . 'ucp.' . $phpEx, 'mode=sendpassword')) - ); - - $this->tpl_name = 'ucp_remind'; - $this->page_title = 'UCP_REMIND'; - } -} diff --git a/phpBB/language/en/email/user_activate_passwd.txt b/phpBB/language/en/email/user_activate_passwd.txt deleted file mode 100644 index 965d5a552c..0000000000 --- a/phpBB/language/en/email/user_activate_passwd.txt +++ /dev/null @@ -1,17 +0,0 @@ -Subject: New password activation - -Hello {USERNAME} - -You are receiving this notification because you have (or someone pretending to be you has) requested a new password be sent for your account on "{SITENAME}". If you did not request this notification then please ignore it, if you keep receiving it please contact the board administrator. - -To use the new password you need to activate it. To do this click the link provided below. - -{U_ACTIVATE} - -If successful you will be able to login using the following password: - -Password: {PASSWORD} - -You can of course change this password yourself via the profile page. If you have any difficulties please contact the board administrator. - -{EMAIL_SIG} diff --git a/phpBB/language/en/email/user_forgot_password.txt b/phpBB/language/en/email/user_forgot_password.txt new file mode 100644 index 0000000000..4826a7bfd9 --- /dev/null +++ b/phpBB/language/en/email/user_forgot_password.txt @@ -0,0 +1,13 @@ +Subject: Account password reset + +Hello {USERNAME} + +You are receiving this notification because you have requested to recover a forgotten password for your account on "{SITENAME}". + +To reset your password, please click the link provided below: + +{U_RESET_PASSWORD} + +If you did not authorize the request you can ignore this email. Please contact the board administrator if you keep receiving it. + +{EMAIL_SIG} diff --git a/phpBB/language/en/ucp.php b/phpBB/language/en/ucp.php index 66fb554f78..542d814911 100644 --- a/phpBB/language/en/ucp.php +++ b/phpBB/language/en/ucp.php @@ -402,6 +402,7 @@ $lang = array_merge($lang, array( 'NO_OLDER_PM' => 'No older messages.', 'NO_PASSWORD_SUPPLIED' => 'You cannot login without a password.', 'NO_RECIPIENT' => 'No recipient defined.', + 'NO_RESET_TOKEN' => 'You did not provide a password reset token.', 'NO_RULES_DEFINED' => 'No rules defined.', 'NO_SAVED_DRAFTS' => 'No drafts saved.', 'NO_TO_RECIPIENT' => 'None', @@ -415,7 +416,8 @@ $lang = array_merge($lang, array( 'PASS_TYPE_SYMBOL_EXPLAIN' => 'Password must be between %1$s and %2$s long, must contain letters in mixed case, must contain numbers and must contain symbols.', 'PASSWORD' => 'Password', 'PASSWORD_ACTIVATED' => 'Your new password has been activated.', - 'PASSWORD_UPDATED_IF_EXISTED' => 'If your account exists, a new password was sent to your registered email address. If you do not receive an email, it may be because you are banned, your account is not activated, or you are not allowed to change your password. Contact admin if any of those reasons apply. Also, check your spam filter.', + 'PASSWORD_RESET' => 'Your password has been successfully reset.', + 'PASSWORD_RESET_LINK_SENT' => 'If your account exists, a password reset link was sent to your registered email address. If you do not receive an email, it may be because you are banned, your account is not activated, you have requested multiple password resets within a short time frame, or you are not allowed to change your password. Contact an administrator if any of those reasons apply. Also, please check your spam filter.', 'PERMISSIONS_RESTORED' => 'Successfully restored original permissions.', 'PERMISSIONS_TRANSFERRED' => 'Successfully transferred permissions from <strong>%s</strong>, you are now able to browse the board with this user’s permissions.<br />Please note that admin permissions were not transferred. You are able to revert to your permission set at any time.', 'PM_DISABLED' => 'Private messaging has been disabled on this board.', @@ -463,6 +465,8 @@ $lang = array_merge($lang, array( 'REPLIED_MESSAGE' => 'Replied to message', 'REPLY_TO_ALL' => 'Reply to sender and all recipients.', 'REPORT_PM' => 'Report private message', + 'RESET_PASSWORD' => 'Reset password', + 'RESET_TOKEN_EXPIRED_OR_INVALID' => 'The password reset token you supplied is invalid or has expired.', 'RESIGN_SELECTED' => 'Resign selected', 'RETURN_FOLDER' => '%1$sReturn to previous folder%2$s', 'RETURN_UCP' => '%sReturn to the User Control Panel%s', @@ -478,7 +482,6 @@ $lang = array_merge($lang, array( 'SAME_PASSWORD_ERROR' => 'The new password you entered is the same as your current password.', 'SEARCH_YOUR_POSTS' => 'Show your posts', - 'SEND_PASSWORD' => 'Send password', 'SENT_AT' => 'Sent', // Used before dates in private messages 'SHOW_EMAIL' => 'Users can contact me by email', 'SIGNATURE_EXPLAIN' => 'This is a block of text that can be added to posts you make. There is a %d character limit.', @@ -562,7 +565,6 @@ $lang = array_merge($lang, array( 'UCP_PASSWORD_RESET_DISABLED' => 'The password reset functionality has been disabled. If you need help accessing your account, please contact the %sBoard Administrator%s', 'UCP_REGISTER_DISABLE' => 'Creating a new account is currently not possible.', - 'UCP_REMIND' => 'Send password', 'UCP_RESEND' => 'Send activation email', 'UCP_WELCOME' => 'Welcome to the User Control Panel. From here you can monitor, view and update your profile, preferences, subscribed forums and topics. You can also send messages to other users (if permitted). Please ensure you read any announcements before continuing.', 'UCP_ZEBRA' => 'Friends & Foes', diff --git a/phpBB/phpbb/db/migration/data/v330/reset_password.php b/phpBB/phpbb/db/migration/data/v330/reset_password.php new file mode 100644 index 0000000000..953d478ccc --- /dev/null +++ b/phpBB/phpbb/db/migration/data/v330/reset_password.php @@ -0,0 +1,48 @@ +<?php +/** + * + * This file is part of the phpBB Forum Software package. + * + * @copyright (c) phpBB Limited <https://www.phpbb.com> + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\db\migration\data\v330; + +class reset_password extends \phpbb\db\migration\migration +{ + static public function depends_on() + { + return [ + '\phpbb\db\migration\data\v330\dev', + ]; + } + + public function update_schema() + { + return [ + 'add_columns' => [ + $this->table_prefix . 'users' => [ + 'reset_token' => ['VCHAR:64', '', 'after' => 'user_actkey'], + 'reset_token_expiration' => ['TIMESTAMP', 0, 'after' => 'reset_token'], + ], + ], + ]; + } + + public function revert_schema() + { + return [ + 'drop_columns' => [ + $this->table_prefix . 'users' => [ + 'reset_token', + 'reset_token_expiration', + ], + ], + ]; + } +} diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php new file mode 100644 index 0000000000..666957b0dc --- /dev/null +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -0,0 +1,443 @@ +<?php +/** +* +* This file is part of the phpBB Forum Software package. +* +* @copyright (c) phpBB Limited <https://www.phpbb.com> +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +namespace phpbb\ucp\controller; + +use phpbb\auth\auth; +use phpbb\config\config; +use phpbb\controller\helper; +use phpbb\db\driver\driver_interface; +use phpbb\event\dispatcher; +use phpbb\exception\http_exception; +use phpbb\language\language; +use phpbb\log\log_interface; +use phpbb\passwords\manager; +use phpbb\request\request_interface; +use phpbb\template\template; +use phpbb\user; +use Symfony\Component\HttpFoundation\Response; + +/** +* Handling forgotten passwords via reset password functionality +*/ +class reset_password +{ + /** @var config */ + protected $config; + + /** @var driver_interface */ + protected $db; + + /** @var dispatcher */ + protected $dispatcher; + + /** @var helper */ + protected $helper; + + /** @var language */ + protected $language; + + /** @var log_interface */ + protected $log; + + /** @var manager */ + protected $passwords_manager; + + /** @var request_interface */ + protected $request; + + /** @var template */ + protected $template; + + /** @var user */ + protected $user; + + /** @var array phpBB DB table names */ + protected $users_table; + + /** @var string phpBB root path */ + protected $root_path; + + /** @var string PHP extension */ + protected $php_ext; + + /** + * Reset password controller constructor. + * + * @param config $config + * @param driver_interface $db + * @param dispatcher $dispatcher + * @param helper $helper + * @param language $language + * @param log_interface $log + * @param manager $passwords_manager + * @param request_interface $request + * @param template $template + * @param user $user + * @param string $users_table + * @param string $root_path + * @param string $php_ext + */ + public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, helper $helper, + language $language, log_interface $log, manager $passwords_manager, + request_interface $request, template $template, user $user, string $users_table, + string $root_path, string $php_ext) + { + $this->config = $config; + $this->db = $db; + $this->dispatcher = $dispatcher; + $this->helper = $helper; + $this->language = $language; + $this->log = $log; + $this->passwords_manager = $passwords_manager; + $this->request = $request; + $this->template = $template; + $this->user = $user; + $this->users_table = $users_table; + $this->root_path = $root_path; + $this->php_ext = $php_ext; + } + + /** + * Init controller + */ + protected function init_controller() + { + $this->language->add_lang('ucp'); + + if (!$this->config['allow_password_reset']) + { + throw new http_exception(Response::HTTP_OK, 'UCP_PASSWORD_RESET_DISABLED', [ + '<a href="mailto:' . htmlspecialchars($this->config['board_contact']) . '">', + '</a>' + ]); + } + } + + /** + * Remove reset token for specified user + * + * @param int $user_id User ID + */ + protected function remove_reset_token(int $user_id) + { + $sql_ary = [ + 'reset_token' => '', + 'reset_token_expiration' => 0, + ]; + + $sql = 'UPDATE ' . $this->users_table . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . $user_id; + $this->db->sql_query($sql); + } + + /** + * Handle password reset request + * + * @return Response + */ + public function request() + { + $this->init_controller(); + + $submit = $this->request->is_set_post('submit'); + $username = $this->request->variable('username', '', true); + $email = strtolower($this->request->variable('email', '')); + + add_form_key('ucp_reset_password'); + + if ($submit) + { + if (!check_form_key('ucp_reset_password')) + { + throw new http_exception(Response::HTTP_UNAUTHORIZED, 'FORM_INVALID'); + } + + if (empty($email)) + { + return $this->helper->message('NO_EMAIL_USER'); + } + + $sql_array = [ + 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type,' + . ' user_lang, user_inactive_reason, reset_token, reset_token_expiration', + 'FROM' => [$this->users_table => 'u'], + 'WHERE' => "user_email_hash = '" . $this->db->sql_escape(phpbb_email_hash($email)) . "'" . + (!empty($username) ? " AND username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'" : ''), + ]; + + /** + * Change SQL query for fetching user data + * + * @event core.ucp_remind_modify_select_sql + * @var string email User's email from the form + * @var string username User's username from the form + * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE + * @since 3.1.11-RC1 + * @changed 3.3.0-b1 Moved to reset password controller + */ + $vars = [ + 'email', + 'username', + 'sql_array', + ]; + extract($this->dispatcher->trigger_event('core.ucp_remind_modify_select_sql', compact($vars))); + + $sql = $this->db->sql_build_query('SELECT', $sql_array); + $result = $this->db->sql_query_limit($sql, 2); // don't waste resources on more rows than we need + $rowset = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + if (count($rowset) > 1) + { + $this->template->assign_vars([ + 'USERNAME_REQUIRED' => true, + 'EMAIL' => $email, + ]); + } + else + { + $message = $this->language->lang('PASSWORD_RESET_LINK_SENT') . '<br /><br />' . $this->language->lang('RETURN_INDEX', '<a href="' . append_sid("{$this->root_path}index.{$this->php_ext}") . '">', '</a>'); + + if (empty($rowset)) + { + return $this->helper->message($message); + } + + $user_row = $rowset[0]; + + if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) + { + return $this->helper->message($message); + } + + // Do not create multiple valid reset tokens + if (!empty($user_row['reset_token']) && (int) $user_row['reset_token_expiration'] >= time()) + { + return $this->helper->message($message); + } + + // Check users permissions + $auth = new auth(); + $auth->acl($user_row); + + if (!$auth->acl_get('u_chgpasswd')) + { + return $this->helper->message($message); + } + + // Generate reset token + $reset_token = strtolower(gen_rand_string(32)); + + $sql_ary = [ + 'reset_token' => $reset_token, + 'reset_token_expiration' => strtotime('+1 day'), + ]; + + $sql = 'UPDATE ' . $this->users_table . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . $user_row['user_id']; + $this->db->sql_query($sql); + + if (!class_exists('messenger')) + { + include($this->root_path . 'includes/functions_messenger.' . $this->php_ext); + } + + /** @var \messenger $messenger */ + $messenger = new \messenger(false); + + $messenger->template('user_forgot_password', $user_row['user_lang']); + + $messenger->set_addresses($user_row); + + $messenger->anti_abuse_headers($this->config, $this->user); + + $messenger->assign_vars([ + 'USERNAME' => htmlspecialchars_decode($user_row['username']), + 'U_RESET_PASSWORD' => generate_board_url(true) . $this->helper->route('phpbb_ucp_reset_password_controller', [ + 'u' => $user_row['user_id'], + 'token' => $reset_token, + ], false) + ]); + + $messenger->send($user_row['user_notify_type']); + + return $this->helper->message($message); + } + } + + $this->template->assign_vars([ + 'USERNAME' => $username, + 'EMAIL' => $email, + 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_forgot_password_controller'), + ]); + + return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); + } + + /** + * Handle controller requests + * + * @return Response + */ + public function reset() + { + $this->init_controller(); + + $submit = $this->request->is_set_post('submit'); + $reset_token = $this->request->variable('token', ''); + $user_id = $this->request->variable('u', 0); + + if (empty($reset_token)) + { + return $this->helper->message('NO_RESET_TOKEN'); + } + + if (!$user_id) + { + return $this->helper->message('NO_USER'); + } + + add_form_key('ucp_reset_password'); + + $sql_array = [ + 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type,' + . ' user_lang, user_inactive_reason, reset_token, reset_token_expiration', + 'FROM' => [$this->users_table => 'u'], + 'WHERE' => 'user_id = ' . $user_id, + ]; + + /** + * Change SQL query for fetching user data + * + * @event core.ucp_reset_password_modify_select_sql + * @var int user_id User ID from the form + * @var string reset_token Reset token + * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE + * @since 3.3.0-b1 + */ + $vars = [ + 'user_id', + 'reset_token', + 'sql_array', + ]; + extract($this->dispatcher->trigger_event('core.ucp_reset_password_modify_select_sql', compact($vars))); + + $sql = $this->db->sql_build_query('SELECT', $sql_array); + $result = $this->db->sql_query_limit($sql, 1); + $user_row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + $message = $this->language->lang('RESET_TOKEN_EXPIRED_OR_INVALID') . '<br /><br />' . $this->language->lang('RETURN_INDEX', '<a href="' . append_sid("{$this->root_path}index.{$this->php_ext}") . '">', '</a>'); + + if (empty($user_row)) + { + return $this->helper->message($message); + } + + if (!hash_equals($reset_token, $user_row['reset_token'])) + { + return $this->helper->message($message); + } + + if ($user_row['reset_token_expiration'] < time()) + { + $this->remove_reset_token($user_id); + + return $this->helper->message($message); + } + + $errors = []; + + if ($submit) + { + if (!check_form_key('ucp_reset_password')) + { + return $this->helper->message('FORM_INVALID'); + } + + if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) + { + return $this->helper->message($message); + } + + // Check users permissions + $auth = new auth(); + $auth->acl($user_row); + + if (!$auth->acl_get('u_chgpasswd')) + { + return $this->helper->message($message); + } + + if (!function_exists('validate_data')) + { + include($this->root_path . 'includes/functions_user.' . $this->php_ext); + } + + $data = [ + 'new_password' => $this->request->untrimmed_variable('new_password', '', true), + 'password_confirm' => $this->request->untrimmed_variable('new_password_confirm', '', true), + ]; + $check_data = [ + 'new_password' => [ + ['string', false, $this->config['min_pass_chars'], $this->config['max_pass_chars']], + ['password'], + ], + 'password_confirm' => ['string', true, $this->config['min_pass_chars'], $this->config['max_pass_chars']], + ]; + $errors = array_merge($errors, validate_data($data, $check_data)); + if (strcmp($data['new_password'], $data['password_confirm']) !== 0) + { + $errors[] = $data['password_confirm'] ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; + } + if (empty($errors)) + { + $sql_ary = [ + 'user_password' => $this->passwords_manager->hash($data['new_password']), + 'user_login_attempts' => 0, + 'reset_token' => '', + 'reset_token_expiration' => 0, + ]; + $sql = 'UPDATE ' . $this->users_table . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . (int) $user_row['user_id']; + $this->db->sql_query($sql); + $this->log->add('user', $user_row['user_id'], $this->user->ip, 'LOG_USER_NEW_PASSWORD', false, [ + 'reportee_id' => $user_row['user_id'], + $user_row['username'] + ]); + meta_refresh(3, append_sid("{$this->root_path}index.{$this->php_ext}")); + return $this->helper->message($this->language->lang('PASSWORD_RESET')); + } + } + + if (!empty($errors)) + { + $this->template->assign_block_vars_array('PASSWORD_RESET_ERRORS', array_map([$this->language, 'lang'], $errors)); + } + + $this->template->assign_vars([ + 'S_IS_PASSWORD_RESET' => true, + 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), + 'S_HIDDEN_FIELDS' => build_hidden_fields([ + 'u' => $user_id, + 'token' => $reset_token, + ]), + ]); + + return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); + } +} diff --git a/phpBB/styles/prosilver/template/ucp_remind.html b/phpBB/styles/prosilver/template/ucp_remind.html deleted file mode 100644 index 8b700de430..0000000000 --- a/phpBB/styles/prosilver/template/ucp_remind.html +++ /dev/null @@ -1,37 +0,0 @@ -<!-- INCLUDE overall_header.html --> - -<form action="{S_PROFILE_ACTION}" method="post" id="remind"> - -<div class="panel"> - <div class="inner"> - - <div class="content"> - <h2>{L_SEND_PASSWORD}</h2> - - <fieldset> - {% if USERNAME_REQUIRED %} - <p class="error">{{ lang('EMAIL_NOT_UNIQUE') }}</p> - {% endif %} - <dl> - <dt><label for="email">{L_EMAIL_ADDRESS}{L_COLON}</label><br /><span>{L_EMAIL_REMIND}</span></dt> - <dd><input class="inputbox narrow" type="email" name="email" id="email" size="25" maxlength="100" value="{{ EMAIL }}" autofocus /></dd> - </dl> - {% if USERNAME_REQUIRED %} - <dl> - <dt><label for="username">{L_USERNAME}{L_COLON}</label></dt> - <dd><input class="inputbox narrow" type="text" name="username" id="username" size="25" /></dd> - </dl> - {% endif %} - <dl> - <dt> </dt> - <dd>{S_HIDDEN_FIELDS}<input type="submit" name="submit" id="submit" class="button1" value="{L_SUBMIT}" tabindex="2" /> <input type="reset" value="{L_RESET}" name="reset" class="button2" /></dd> - </dl> - {S_FORM_TOKEN} - </fieldset> - </div> - - </div> -</div> -</form> - -<!-- INCLUDE overall_footer.html --> diff --git a/phpBB/styles/prosilver/template/ucp_reset_password.html b/phpBB/styles/prosilver/template/ucp_reset_password.html new file mode 100644 index 0000000000..0a05f69aed --- /dev/null +++ b/phpBB/styles/prosilver/template/ucp_reset_password.html @@ -0,0 +1,49 @@ +<!-- INCLUDE overall_header.html --> + +<form action="{{ U_RESET_PASSWORD_ACTION }}" method="post" id="reset_password"> + +<div class="panel"> + <div class="inner"> + + <div class="content"> + <h2>{{ lang('RESET_PASSWORD') }}</h2> + + <fieldset> + {% if S_IS_PASSWORD_RESET %} + {% if PASSWORD_RESET_ERRORS %}<p class="error">{{ PASSWORD_RESET_ERRORS | join('<br>') }}</p>{% endif %} + <dl> + <dt><label for="new_password">{{ lang('NEW_PASSWORD') ~ lang('COLON') }}</label></dt> + <dd><input type="password" name="new_password" id="new_password" size="25" maxlength="255" title="{{ lang('CHANGE_PASSWORD') }}" autocomplete="off" /></dd> + </dl> + <dl> + <dt><label for="new_password_confirm">{{ lang('CONFIRM_PASSWORD') ~ lang('COLON') }}</label></dt> + <dd><input type="password" name="new_password_confirm" id="new_password_confirm" size="25" maxlength="255" title="{{ lang('CONFIRM_PASSWORD') }}" autocomplete="off" /></dd> + </dl> + {% else %} + {% if USERNAME_REQUIRED %} + <p class="error">{{ lang('EMAIL_NOT_UNIQUE') }}</p> + {% endif %} + <dl> + <dt><label for="email">{{ lang('EMAIL_ADDRESS') ~ lang('COLON') }}</label><br /><span>{{ lang('EMAIL_REMIND') }}</span></dt> + <dd><input class="inputbox narrow" type="email" name="email" id="email" size="25" maxlength="100" value="{{ EMAIL }}" autofocus /></dd> + </dl> + {% if USERNAME_REQUIRED %} + <dl> + <dt><label for="username">{{ lang('USERNAME') ~ lang('COLON') }}</label></dt> + <dd><input class="inputbox narrow" type="text" name="username" id="username" size="25" /></dd> + </dl> + {% endif %} + {% endif %} + <dl> + <dt> </dt> + <dd>{{ S_HIDDEN_FIELDS }}<input type="submit" name="submit" id="submit" class="button1" value="{{ lang('SUBMIT') }}" tabindex="2" /> <input type="reset" value="{{ lang('RESET') }}" name="reset" class="button2" /></dd> + </dl> + {{ S_FORM_TOKEN }} + </fieldset> + </div> + + </div> +</div> +</form> + +<!-- INCLUDE overall_footer.html --> diff --git a/phpBB/ucp.php b/phpBB/ucp.php index c60d9930fc..0992e3ef90 100644 --- a/phpBB/ucp.php +++ b/phpBB/ucp.php @@ -63,8 +63,10 @@ switch ($mode) break; case 'sendpassword': - $module->load('ucp', 'remind'); - $module->display($user->lang['UCP_REMIND']); + /** @var \phpbb\controller\helper $controller_helper */ + $controller_helper = $phpbb_container->get('controller.helper'); + + redirect($controller_helper->route('phpbb_ucp_forgot_password_controller')); break; case 'register': |