From 3f852a3233b2ee51c3fab7dc6d077778fd35e0fd Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Thu, 8 Aug 2019 22:01:51 +0200 Subject: [ticket/11327] Move UCP remind functionality to a controller for password reset PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 174 ++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 phpBB/phpbb/ucp/controller/reset_password.php (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php new file mode 100644 index 0000000000..e50428bfea --- /dev/null +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -0,0 +1,174 @@ + +* @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', '', '')); + } + + $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'] . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); + + 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'; + } +} -- cgit v1.2.1 From 276f350bcb29e5db6efc1a91747f2a83bcfd9246 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Thu, 8 Aug 2019 22:03:27 +0200 Subject: [ticket/11327] Refactor ucp_remind to reset_password controller PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 149 +++++++++++++++++++------- 1 file changed, 109 insertions(+), 40 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index e50428bfea..49c264be6c 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -11,34 +11,105 @@ * */ -/** -* @ignore -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} +namespace phpbb\ucp\controller; + +use phpbb\config\config; +use phpbb\controller\helper; +use phpbb\db\driver\driver_interface; +use phpbb\event\dispatcher; +use phpbb\language\language; +use phpbb\passwords\manager; +use phpbb\request\request_interface; +use phpbb\template\template; +use phpbb\user; /** * ucp_remind * Sending password reminders */ -class ucp_remind +class reset_password { - var $u_action; + /** @var config */ + protected $config; + + /** @var driver_interface */ + protected $db; + + /** @var dispatcher */ + protected $dispatcher; + + /** @var helper */ + protected $helper; + + /** @var language */ + protected $language; + + /** @var manager */ + protected $passwords_manager; + + /** @var request_interface */ + protected $request; + + /** @var template */ + protected $template; + + /** @var user */ + protected $user; + + /** @var string phpBB root path */ + protected $root_path; + + /** @var string PHP extension */ + protected $php_ext; + + /** + * ucp_remind constructor. + * + * @param config $config + * @param driver_interface $db + * @param dispatcher $dispatcher + * @param helper $helper + * @param language $language + * @param manager $passwords_manager + * @param request_interface $request + * @param template $template + * @param user $user + * @param $root_path + * @param $php_ext + */ + public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, helper $helper, + language $language, manager $passwords_manager, request_interface $request, + template $template, user $user, $root_path, $php_ext) + { + $this->config = $config; + $this->db = $db; + $this->dispatcher = $dispatcher; + $this->helper = $helper; + $this->language = $language; + $this->passwords_manager = $passwords_manager; + $this->request = $request; + $this->template = $template; + $this->user = $user; + $this->root_path = $root_path; + $this->php_ext = $php_ext; + } - function main($id, $mode) + /** + * Handle controller requests + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function handle() { - global $config, $phpbb_root_path, $phpEx, $request; - global $db, $user, $template, $phpbb_container, $phpbb_dispatcher; + $this->language->add_lang('ucp'); - if (!$config['allow_password_reset']) + if (!$this->config['allow_password_reset']) { - trigger_error($user->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); + trigger_error($this->language->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); } - $username = $request->variable('username', '', true); - $email = strtolower($request->variable('email', '')); + $username = $this->request->variable('username', '', true); + $email = strtolower($this->request->variable('email', '')); $submit = (isset($_POST['submit'])) ? true : false; add_form_key('ucp_remind'); @@ -58,8 +129,8 @@ class ucp_remind $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)) . "'" : ''), + '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)) . "'" : ''), ); /** @@ -76,24 +147,24 @@ class ucp_remind 'username', 'sql_array', ); - extract($phpbb_dispatcher->trigger_event('core.ucp_remind_modify_select_sql', compact($vars))); + extract($this->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); + $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); if (count($rowset) > 1) { - $db->sql_freeresult($result); + $this->db->sql_freeresult($result); - $template->assign_vars(array( + $this->template->assign_vars(array( 'USERNAME_REQUIRED' => true, 'EMAIL' => $email, )); } else { - $message = $user->lang['PASSWORD_UPDATED_IF_EXISTED'] . '

' . sprintf($user->lang['RETURN_INDEX'], '', ''); + $message = $this->language->lang('PASSWORD_UPDATED_IF_EXISTED') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); if (empty($rowset)) { @@ -101,7 +172,7 @@ class ucp_remind } $user_row = $rowset[0]; - $db->sql_freeresult($result); + $this->db->sql_freeresult($result); if (!$user_row) { @@ -126,21 +197,17 @@ class ucp_remind // 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']))); + $user_password = gen_rand_string_friendly(max(8, mt_rand((int) $this->config['min_pass_chars'], (int) $this->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) . "' + SET user_newpasswd = '" . $this->db->sql_escape($this->passwords_manager->hash($user_password)) . "', user_actkey = '" . $this->db->sql_escape($user_actkey) . "' WHERE user_id = " . $user_row['user_id']; - $db->sql_query($sql); + $this->db->sql_query($sql); - include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); + include_once($this->root_path . 'includes/functions_messenger.' . $this->php_ext); $messenger = new messenger(false); @@ -148,12 +215,12 @@ class ucp_remind $messenger->set_addresses($user_row); - $messenger->anti_abuse_headers($config, $user); + $messenger->anti_abuse_headers($this->config, $this->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") + 'U_ACTIVATE' => "$server_url/ucp.{$this->php_ext}?mode=activate&u={$user_row['user_id']}&k=$user_actkey") ); $messenger->send($user_row['user_notify_type']); @@ -162,13 +229,15 @@ class ucp_remind } } - $template->assign_vars(array( + $this->template->assign_vars(array( 'USERNAME' => $username, 'EMAIL' => $email, - 'S_PROFILE_ACTION' => append_sid($phpbb_root_path . 'ucp.' . $phpEx, 'mode=sendpassword')) + 'S_PROFILE_ACTION' => append_sid($this->root_path . 'ucp.' . $this->php_ext, 'mode=sendpassword')) ); - $this->tpl_name = 'ucp_remind'; - $this->page_title = 'UCP_REMIND'; + //$this->tpl_name = 'ucp_remind'; + //$this->page_title = 'UCP_REMIND'; + + return $this->helper->render('ucp_remind.html', 'UCP_REMIND'); } } -- cgit v1.2.1 From fe030f67efc354729033ebc1726fc5b729057fb2 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Thu, 8 Aug 2019 22:11:13 +0200 Subject: [ticket/11327] Adjust display of page title PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 49c264be6c..55397b1c0e 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -235,9 +235,6 @@ class reset_password 'S_PROFILE_ACTION' => append_sid($this->root_path . 'ucp.' . $this->php_ext, 'mode=sendpassword')) ); - //$this->tpl_name = 'ucp_remind'; - //$this->page_title = 'UCP_REMIND'; - - return $this->helper->render('ucp_remind.html', 'UCP_REMIND'); + return $this->helper->render('ucp_remind.html', $this->language->lang('UCP_REMIND')); } } -- cgit v1.2.1 From 0a5599697fb9d52f067ac1846492641cf1adc05a Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Fri, 9 Aug 2019 22:51:51 +0200 Subject: [ticket/11327] Split up into forgot password and reset password PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 158 +++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 5 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 55397b1c0e..57fef00f79 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -56,6 +56,9 @@ class reset_password /** @var user */ protected $user; + /** @var array phpBB DB table names */ + protected $tables; + /** @var string phpBB root path */ protected $root_path; @@ -74,12 +77,13 @@ class reset_password * @param request_interface $request * @param template $template * @param user $user + * @param array $tables * @param $root_path * @param $php_ext */ public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, helper $helper, language $language, manager $passwords_manager, request_interface $request, - template $template, user $user, $root_path, $php_ext) + template $template, user $user, $tables, $root_path, $php_ext) { $this->config = $config; $this->db = $db; @@ -94,12 +98,154 @@ class reset_password $this->php_ext = $php_ext; } + public function request() + { + $this->language->add_lang('ucp'); + + if (!$this->config['allow_password_reset']) + { + trigger_error($this->language->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); + } + + $submit = $this->request->is_set_post('submit'); + $username = $this->request->variable('username', '', true); + $email = strtolower($this->request->variable('email', '')); + + 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, reset_token, reset_token_expiration', + 'FROM' => array(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 + */ + $vars = array( + '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); + + if (count($rowset) > 1) + { + $this->db->sql_freeresult($result); + + $this->template->assign_vars(array( + 'USERNAME_REQUIRED' => true, + 'EMAIL' => $email, + )); + } + else + { + $message = $this->language->lang('PASSWORD_UPDATED_IF_EXISTED') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); + + $user_row = empty($rowset) ? [] : $rowset[0]; + $this->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); + } + + // Do not create multiple valid reset tokens + if (!empty($user_row['reset_token']) && (int) $user_row['reset_token_expiration'] <= (time() + $this->config['reset_token_lifetime'])) + { + 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(); + + // Generate reset token + $reset_token = gen_rand_string_friendly(32); + + $sql_ary = array( + 'reset_token' => $reset_token, + 'reset_token_expiration' => time() + $this->config['reset_token_lifetime'], + ); + + $sql = 'UPDATE ' . $this->tables['users'] . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . $user_row['user_id']; + $this->db->sql_query($sql); + + include_once($this->root_path . 'includes/functions_messenger.' . $this->php_ext); + + /** @var \messenger $messenger */ + $messenger = new \messenger(false); + + $messenger->template('user_activate_passwd', $user_row['user_lang']); + + $messenger->set_addresses($user_row); + + $messenger->anti_abuse_headers($this->config, $this->user); + + $messenger->assign_vars(array( + 'USERNAME' => htmlspecialchars_decode($user_row['username']), + 'U_ACTIVATE' => $this->helper->route('phpbb_ucp_reset_password_controller') + )); + + $messenger->send($user_row['user_notify_type']); + + trigger_error($message); + } + } + + $this->template->assign_vars(array( + 'USERNAME' => $username, + 'EMAIL' => $email, + 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_forgot_password_controller'), + )); + + return $this->helper->render('ucp_remind.html', $this->language->lang('UCP_REMIND')); + } + /** * Handle controller requests * * @return \Symfony\Component\HttpFoundation\Response */ - public function handle() + public function reset() { $this->language->add_lang('ucp'); @@ -108,9 +254,11 @@ class reset_password trigger_error($this->language->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); } + $submit = $this->request->is_set_post('submit'); $username = $this->request->variable('username', '', true); $email = strtolower($this->request->variable('email', '')); - $submit = (isset($_POST['submit'])) ? true : false; + $key = $this->request->variable('key', ''); + $user_id = $this->request->variable('user_id', 0); add_form_key('ucp_remind'); @@ -232,8 +380,8 @@ class reset_password $this->template->assign_vars(array( 'USERNAME' => $username, 'EMAIL' => $email, - 'S_PROFILE_ACTION' => append_sid($this->root_path . 'ucp.' . $this->php_ext, 'mode=sendpassword')) - ); + 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), + )); return $this->helper->render('ucp_remind.html', $this->language->lang('UCP_REMIND')); } -- cgit v1.2.1 From 1d1d963c14d9db54df69469758163f1f50a9b4b3 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Fri, 9 Aug 2019 23:32:49 +0200 Subject: [ticket/11327] Adjust wording of forgot password email PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 57fef00f79..4b2660aebb 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -221,8 +221,8 @@ class reset_password $messenger->anti_abuse_headers($this->config, $this->user); $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'U_ACTIVATE' => $this->helper->route('phpbb_ucp_reset_password_controller') + 'USERNAME' => htmlspecialchars_decode($user_row['username']), + 'U_RESET_PASSWORD' => $this->helper->route('phpbb_ucp_reset_password_controller') )); $messenger->send($user_row['user_notify_type']); -- cgit v1.2.1 From e991df195baa75cc2bb36a34621eb8aea1f9f9e7 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Sat, 10 Aug 2019 15:09:35 +0200 Subject: [ticket/11327] Continue with implementation of password reset functionality PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 255 ++++++++++++++------------ 1 file changed, 133 insertions(+), 122 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 4b2660aebb..3d34c4740b 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -22,6 +22,7 @@ use phpbb\passwords\manager; use phpbb\request\request_interface; use phpbb\template\template; use phpbb\user; +use Symfony\Component\HttpFoundation\Response; /** * ucp_remind @@ -94,18 +95,32 @@ class reset_password $this->request = $request; $this->template = $template; $this->user = $user; + $this->tables = $tables; $this->root_path = $root_path; $this->php_ext = $php_ext; } - public function request() + /** + * Init controller + */ + protected function init_controller() { $this->language->add_lang('ucp'); if (!$this->config['allow_password_reset']) { - trigger_error($this->language->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); + $this->helper->message($this->language->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); } + } + + /** + * 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); @@ -125,13 +140,13 @@ class reset_password trigger_error('NO_EMAIL_USER'); } - $sql_array = array( + $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' => array(USERS_TABLE => 'u'), + 'FROM' => [$this->tables['users'] => '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 @@ -141,12 +156,13 @@ class reset_password * @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 = array( + $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); @@ -157,10 +173,10 @@ class reset_password { $this->db->sql_freeresult($result); - $this->template->assign_vars(array( + $this->template->assign_vars([ 'USERNAME_REQUIRED' => true, 'EMAIL' => $email, - )); + ]); } else { @@ -194,15 +210,13 @@ class reset_password trigger_error($message); } - $server_url = generate_board_url(); - // Generate reset token - $reset_token = gen_rand_string_friendly(32); + $reset_token = strtolower(gen_rand_string(32)); - $sql_ary = array( + $sql_ary = [ 'reset_token' => $reset_token, 'reset_token_expiration' => time() + $this->config['reset_token_lifetime'], - ); + ]; $sql = 'UPDATE ' . $this->tables['users'] . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' @@ -214,16 +228,19 @@ class reset_password /** @var \messenger $messenger */ $messenger = new \messenger(false); - $messenger->template('user_activate_passwd', $user_row['user_lang']); + $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(array( + $messenger->assign_vars([ 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'U_RESET_PASSWORD' => $this->helper->route('phpbb_ucp_reset_password_controller') - )); + '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']); @@ -231,11 +248,11 @@ class reset_password } } - $this->template->assign_vars(array( + $this->template->assign_vars([ 'USERNAME' => $username, 'EMAIL' => $email, 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_forgot_password_controller'), - )); + ]); return $this->helper->render('ucp_remind.html', $this->language->lang('UCP_REMIND')); } @@ -243,25 +260,73 @@ class reset_password /** * Handle controller requests * - * @return \Symfony\Component\HttpFoundation\Response + * @return Response */ public function reset() { - $this->language->add_lang('ucp'); + $this->init_controller(); - if (!$this->config['allow_password_reset']) + $submit = $this->request->is_set_post('submit'); + $reset_token = $this->request->variable('token', ''); + $user_id = $this->request->variable('u', 0); + + if (empty($reset_token)) { - trigger_error($this->language->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); + $this->helper->message('NO_RESET_TOKEN'); } - $submit = $this->request->is_set_post('submit'); - $username = $this->request->variable('username', '', true); - $email = strtolower($this->request->variable('email', '')); - $key = $this->request->variable('key', ''); - $user_id = $this->request->variable('user_id', 0); + if (!$user_id) + { + $this->helper->message('NO_USER'); + } add_form_key('ucp_remind'); + $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->tables['users'] => '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') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); + + if (empty($user_row)) + { + $this->helper->message($message); + } + + if (!hash_equals($reset_token, $user_row['reset_token'])) + { + $this->helper->message($message); + } + + if ($user_row['reset_token_expiration'] < time()) + { + $this->helper->message($message); + } + if ($submit) { if (!check_form_key('ucp_remind')) @@ -269,119 +334,65 @@ class reset_password trigger_error('FORM_INVALID'); } - if (empty($email)) + $message = $this->language->lang('PASSWORD_UPDATED_IF_EXISTED') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); + + if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) { - trigger_error('NO_EMAIL_USER'); + trigger_error($message); } - $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 = '" . $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 - */ - $vars = array( - '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); + // Check users permissions + $auth2 = new \phpbb\auth\auth(); + $auth2->acl($user_row); - if (count($rowset) > 1) + if (!$auth2->acl_get('u_chgpasswd')) { - $this->db->sql_freeresult($result); - - $this->template->assign_vars(array( - 'USERNAME_REQUIRED' => true, - 'EMAIL' => $email, - )); + trigger_error($message); } - else - { - $message = $this->language->lang('PASSWORD_UPDATED_IF_EXISTED') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); - if (empty($rowset)) - { - trigger_error($message); - } + $server_url = generate_board_url(); - $user_row = $rowset[0]; - $this->db->sql_freeresult($result); + // 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) $this->config['min_pass_chars'], (int) $this->config['max_pass_chars']))); - if (!$user_row) - { - trigger_error($message); - } + // For the activation key a random length between 6 and 10 will do. + $user_actkey = gen_rand_string(mt_rand(6, 10)); - if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) - { - trigger_error($message); - } + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_newpasswd = '" . $this->db->sql_escape($this->passwords_manager->hash($user_password)) . "', user_actkey = '" . $this->db->sql_escape($user_actkey) . "' + WHERE user_id = " . $user_row['user_id']; + $this->db->sql_query($sql); - // Check users permissions - $auth2 = new \phpbb\auth\auth(); - $auth2->acl($user_row); + include_once($this->root_path . 'includes/functions_messenger.' . $this->php_ext); - if (!$auth2->acl_get('u_chgpasswd')) - { - trigger_error($message); - } + $messenger = new messenger(false); - $server_url = generate_board_url(); + $messenger->template('user_activate_passwd', $user_row['user_lang']); - // 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) $this->config['min_pass_chars'], (int) $this->config['max_pass_chars']))); + $messenger->set_addresses($user_row); - // For the activation key a random length between 6 and 10 will do. - $user_actkey = gen_rand_string(mt_rand(6, 10)); + $messenger->anti_abuse_headers($this->config, $this->user); - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_newpasswd = '" . $this->db->sql_escape($this->passwords_manager->hash($user_password)) . "', user_actkey = '" . $this->db->sql_escape($user_actkey) . "' - WHERE user_id = " . $user_row['user_id']; - $this->db->sql_query($sql); - - include_once($this->root_path . 'includes/functions_messenger.' . $this->php_ext); + $messenger->assign_vars([ + 'USERNAME' => htmlspecialchars_decode($user_row['username']), + 'PASSWORD' => htmlspecialchars_decode($user_password), + 'U_ACTIVATE' => "$server_url/ucp.{$this->php_ext}?mode=activate&u={$user_row['user_id']}&k=$user_actkey" + ]); - $messenger = new messenger(false); + $messenger->send($user_row['user_notify_type']); - $messenger->template('user_activate_passwd', $user_row['user_lang']); - - $messenger->set_addresses($user_row); - - $messenger->anti_abuse_headers($this->config, $this->user); - - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($user_row['username']), - 'PASSWORD' => htmlspecialchars_decode($user_password), - 'U_ACTIVATE' => "$server_url/ucp.{$this->php_ext}?mode=activate&u={$user_row['user_id']}&k=$user_actkey") - ); - - $messenger->send($user_row['user_notify_type']); - - trigger_error($message); - } + trigger_error($message); } - $this->template->assign_vars(array( - 'USERNAME' => $username, - 'EMAIL' => $email, - 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), - )); + $this->template->assign_vars([ + 'S_IS_PASSWORD_RESET' => true, + 'S_PROFILE_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_remind.html', $this->language->lang('UCP_REMIND')); } -- cgit v1.2.1 From cefdf8bf19d764b7fef3d04383a41ed856af5503 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Sat, 10 Aug 2019 17:18:39 +0200 Subject: [ticket/11327] Finish up initial version of password reset system PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 130 ++++++++++++++++---------- 1 file changed, 82 insertions(+), 48 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 3d34c4740b..c686f198c5 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -18,6 +18,7 @@ use phpbb\controller\helper; use phpbb\db\driver\driver_interface; use phpbb\event\dispatcher; use phpbb\language\language; +use phpbb\log\log_interface; use phpbb\passwords\manager; use phpbb\request\request_interface; use phpbb\template\template; @@ -45,6 +46,9 @@ class reset_password /** @var language */ protected $language; + /** @var log_interface */ + protected $log; + /** @var manager */ protected $passwords_manager; @@ -74,6 +78,7 @@ class reset_password * @param dispatcher $dispatcher * @param helper $helper * @param language $language + * @param log_interface $log * @param manager $passwords_manager * @param request_interface $request * @param template $template @@ -83,14 +88,15 @@ class reset_password * @param $php_ext */ public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, helper $helper, - language $language, manager $passwords_manager, request_interface $request, - template $template, user $user, $tables, $root_path, $php_ext) + language $language, log_interface $log, manager $passwords_manager, + request_interface $request, template $template, user $user, $tables, $root_path, $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; @@ -109,10 +115,28 @@ class reset_password if (!$this->config['allow_password_reset']) { - $this->helper->message($this->language->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); + trigger_error($this->language->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); } } + /** + * 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->tables['users'] . ' + SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . $user_id; + $this->db->sql_query($sql); + } + /** * Handle password reset request * @@ -180,7 +204,7 @@ class reset_password } else { - $message = $this->language->lang('PASSWORD_UPDATED_IF_EXISTED') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); + $message = $this->language->lang('PASSWORD_RESET_LINK_SENT') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); $user_row = empty($rowset) ? [] : $rowset[0]; $this->db->sql_freeresult($result); @@ -254,7 +278,7 @@ class reset_password 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_forgot_password_controller'), ]); - return $this->helper->render('ucp_remind.html', $this->language->lang('UCP_REMIND')); + return $this->helper->render('ucp_reset_password.html', $this->language->lang('UCP_REMIND')); } /** @@ -272,12 +296,12 @@ class reset_password if (empty($reset_token)) { - $this->helper->message('NO_RESET_TOKEN'); + return $this->helper->message('NO_RESET_TOKEN'); } if (!$user_id) { - $this->helper->message('NO_USER'); + return $this->helper->message('NO_USER'); } add_form_key('ucp_remind'); @@ -314,31 +338,33 @@ class reset_password if (empty($user_row)) { - $this->helper->message($message); + return $this->helper->message($message); } if (!hash_equals($reset_token, $user_row['reset_token'])) { - $this->helper->message($message); + return $this->helper->message($message); } if ($user_row['reset_token_expiration'] < time()) { - $this->helper->message($message); + $this->remove_reset_token($user_id); + + return $this->helper->message($message); } + $error = []; + if ($submit) { if (!check_form_key('ucp_remind')) { - trigger_error('FORM_INVALID'); + return $this->helper->message('FORM_INVALID'); } - $message = $this->language->lang('PASSWORD_UPDATED_IF_EXISTED') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); - if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) { - trigger_error($message); + return $this->helper->message($message); } // Check users permissions @@ -347,46 +373,54 @@ class reset_password if (!$auth2->acl_get('u_chgpasswd')) { - trigger_error($message); + return $this->helper->message($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) $this->config['min_pass_chars'], (int) $this->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)); - - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_newpasswd = '" . $this->db->sql_escape($this->passwords_manager->hash($user_password)) . "', user_actkey = '" . $this->db->sql_escape($user_actkey) . "' - WHERE user_id = " . $user_row['user_id']; - $this->db->sql_query($sql); - - include_once($this->root_path . 'includes/functions_messenger.' . $this->php_ext); - - $messenger = new messenger(false); - - $messenger->template('user_activate_passwd', $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']), - 'PASSWORD' => htmlspecialchars_decode($user_password), - 'U_ACTIVATE' => "$server_url/ucp.{$this->php_ext}?mode=activate&u={$user_row['user_id']}&k=$user_actkey" - ]); - - $messenger->send($user_row['user_notify_type']); + if (!function_exists('validate_data')) + { + include($this->root_path . 'includes/functions_user.' . $this->php_ext); + } - trigger_error($message); + $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']], + ]; + $error = array_merge($error, validate_data($data, $check_data)); + if (strcmp($data['new_password'], $data['password_confirm']) !== 0) + { + $error[] = ($data['password_confirm']) ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; + } + if (empty($error)) + { + $sql_ary = [ + 'user_password' => $this->passwords_manager->hash($data['new_password']), + 'user_login_attempts' => 0, + 'reset_token' => '', + 'reset_token_expiration' => 0, + ]; + $sql = 'UPDATE ' . $this->tables['users'] . ' + 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}")); + trigger_error($this->language->lang('PASSWORD_RESET')); + } } $this->template->assign_vars([ 'S_IS_PASSWORD_RESET' => true, + 'ERROR' => !empty($error) ? implode('
', array_map([$this->language, 'lang'], $error)) : '', 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), 'S_HIDDEN_FIELDS' => build_hidden_fields([ 'u' => $user_id, @@ -394,6 +428,6 @@ class reset_password ]), ]); - return $this->helper->render('ucp_remind.html', $this->language->lang('UCP_REMIND')); + return $this->helper->render('ucp_reset_password.html', $this->language->lang('UCP_REMIND')); } } -- cgit v1.2.1 From fa5a0d5e210646d0d271f5ed7433e4cc028b5cf1 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Sat, 10 Aug 2019 21:18:55 +0200 Subject: [ticket/11327] Update tests to reflect changes PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index c686f198c5..679c659eb0 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -220,7 +220,7 @@ class reset_password } // Do not create multiple valid reset tokens - if (!empty($user_row['reset_token']) && (int) $user_row['reset_token_expiration'] <= (time() + $this->config['reset_token_lifetime'])) + if (!empty($user_row['reset_token']) && (int) $user_row['reset_token_expiration'] >= time()) { trigger_error($message); } @@ -239,7 +239,7 @@ class reset_password $sql_ary = [ 'reset_token' => $reset_token, - 'reset_token_expiration' => time() + $this->config['reset_token_lifetime'], + 'reset_token_expiration' => strtotime('+1 day'), ]; $sql = 'UPDATE ' . $this->tables['users'] . ' -- cgit v1.2.1 From ba92e7d2d6fa946de715e3ff6b72275374824f8d Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Sat, 10 Aug 2019 21:23:54 +0200 Subject: [ticket/11327] Clean up code a bit PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 43 ++++++++++++++------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 679c659eb0..50d3ce91eb 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -13,6 +13,7 @@ namespace phpbb\ucp\controller; +use phpbb\auth\auth; use phpbb\config\config; use phpbb\controller\helper; use phpbb\db\driver\driver_interface; @@ -26,8 +27,7 @@ use phpbb\user; use Symfony\Component\HttpFoundation\Response; /** -* ucp_remind -* Sending password reminders +* Handling forgotten passwords via reset password functionality */ class reset_password { @@ -71,7 +71,7 @@ class reset_password protected $php_ext; /** - * ucp_remind constructor. + * Reset password controller constructor. * * @param config $config * @param driver_interface $db @@ -150,18 +150,18 @@ class reset_password $username = $this->request->variable('username', '', true); $email = strtolower($this->request->variable('email', '')); - add_form_key('ucp_remind'); + add_form_key('ucp_reset_password'); if ($submit) { - if (!check_form_key('ucp_remind')) + if (!check_form_key('ucp_reset_password')) { - trigger_error('FORM_INVALID'); + return $this->helper->message('FORM_INVALID'); } if (empty($email)) { - trigger_error('NO_EMAIL_USER'); + return $this->helper->message('NO_EMAIL_USER'); } $sql_array = [ @@ -211,27 +211,27 @@ class reset_password if (!$user_row) { - trigger_error($message); + return $this->helper->message($message); } if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) { - trigger_error($message); + 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()) { - trigger_error($message); + return $this->helper->message($message); } // Check users permissions - $auth2 = new \phpbb\auth\auth(); + $auth2 = new auth(); $auth2->acl($user_row); if (!$auth2->acl_get('u_chgpasswd')) { - trigger_error($message); + return $this->helper->message($message); } // Generate reset token @@ -247,7 +247,10 @@ class reset_password WHERE user_id = ' . $user_row['user_id']; $this->db->sql_query($sql); - include_once($this->root_path . 'includes/functions_messenger.' . $this->php_ext); + if (!class_exists('messenger')) + { + include($this->root_path . 'includes/functions_messenger.' . $this->php_ext); + } /** @var \messenger $messenger */ $messenger = new \messenger(false); @@ -268,7 +271,7 @@ class reset_password $messenger->send($user_row['user_notify_type']); - trigger_error($message); + return $this->helper->message($message); } } @@ -278,7 +281,7 @@ class reset_password 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_forgot_password_controller'), ]); - return $this->helper->render('ucp_reset_password.html', $this->language->lang('UCP_REMIND')); + return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); } /** @@ -304,7 +307,7 @@ class reset_password return $this->helper->message('NO_USER'); } - add_form_key('ucp_remind'); + add_form_key('ucp_reset_password'); $sql_array = [ 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type,' @@ -357,7 +360,7 @@ class reset_password if ($submit) { - if (!check_form_key('ucp_remind')) + if (!check_form_key('ucp_reset_password')) { return $this->helper->message('FORM_INVALID'); } @@ -368,7 +371,7 @@ class reset_password } // Check users permissions - $auth2 = new \phpbb\auth\auth(); + $auth2 = new auth(); $auth2->acl($user_row); if (!$auth2->acl_get('u_chgpasswd')) @@ -414,7 +417,7 @@ class reset_password $user_row['username'] ]); meta_refresh(3, append_sid("{$this->root_path}index.{$this->php_ext}")); - trigger_error($this->language->lang('PASSWORD_RESET')); + return $this->helper->message($this->language->lang('PASSWORD_RESET')); } } @@ -428,6 +431,6 @@ class reset_password ]), ]); - return $this->helper->render('ucp_reset_password.html', $this->language->lang('UCP_REMIND')); + return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); } } -- cgit v1.2.1 From 7a3e351178fde9d8b785867868fb40cbae4c8ab2 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Thu, 22 Aug 2019 14:05:58 +0200 Subject: [ticket/11327] Clean up code style a bit PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 50d3ce91eb..82b9083175 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -18,6 +18,7 @@ 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; @@ -156,7 +157,7 @@ class reset_password { if (!check_form_key('ucp_reset_password')) { - return $this->helper->message('FORM_INVALID'); + throw new http_exception(Response::HTTP_UNAUTHORIZED, 'FORM_INVALID'); } if (empty($email)) @@ -192,11 +193,10 @@ class reset_password $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->db->sql_freeresult($result); - $this->template->assign_vars([ 'USERNAME_REQUIRED' => true, 'EMAIL' => $email, @@ -206,14 +206,13 @@ class reset_password { $message = $this->language->lang('PASSWORD_RESET_LINK_SENT') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); - $user_row = empty($rowset) ? [] : $rowset[0]; - $this->db->sql_freeresult($result); - - if (!$user_row) + if ($rowset === false) { 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); @@ -356,7 +355,7 @@ class reset_password return $this->helper->message($message); } - $error = []; + $errors = []; if ($submit) { @@ -395,12 +394,12 @@ class reset_password ], 'password_confirm' => ['string', true, $this->config['min_pass_chars'], $this->config['max_pass_chars']], ]; - $error = array_merge($error, validate_data($data, $check_data)); + $errors = array_merge($errors, validate_data($data, $check_data)); if (strcmp($data['new_password'], $data['password_confirm']) !== 0) { - $error[] = ($data['password_confirm']) ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; + $errors[] = $data['password_confirm'] ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; } - if (empty($error)) + if (empty($errors)) { $sql_ary = [ 'user_password' => $this->passwords_manager->hash($data['new_password']), @@ -423,7 +422,7 @@ class reset_password $this->template->assign_vars([ 'S_IS_PASSWORD_RESET' => true, - 'ERROR' => !empty($error) ? implode('
', array_map([$this->language, 'lang'], $error)) : '', + 'ERROR' => !empty($errors) ? implode('
', array_map([$this->language, 'lang'], $errors)) : '', 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), 'S_HIDDEN_FIELDS' => build_hidden_fields([ 'u' => $user_id, -- cgit v1.2.1 From 454ea081f17c0dfb9eb75287698a301e5c5d275b Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Mon, 26 Aug 2019 18:14:39 +0200 Subject: [ticket/11327] Use U_ prefix for reset password URL template variable PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 82b9083175..9d736b26b8 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -275,9 +275,9 @@ class reset_password } $this->template->assign_vars([ - 'USERNAME' => $username, - 'EMAIL' => $email, - 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_forgot_password_controller'), + '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')); @@ -421,10 +421,10 @@ class reset_password } $this->template->assign_vars([ - 'S_IS_PASSWORD_RESET' => true, - 'ERROR' => !empty($errors) ? implode('
', array_map([$this->language, 'lang'], $errors)) : '', - 'S_PROFILE_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), - 'S_HIDDEN_FIELDS' => build_hidden_fields([ + 'S_IS_PASSWORD_RESET' => true, + 'ERROR' => !empty($errors) ? implode('
', array_map([$this->language, 'lang'], $errors)) : '', + 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), + 'S_HIDDEN_FIELDS' => build_hidden_fields([ 'u' => $user_id, 'token' => $reset_token, ]), -- cgit v1.2.1 From 8048d817ca0198b214457066a549db6f92b85bc0 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Fri, 30 Aug 2019 09:44:10 +0200 Subject: [ticket/11327] Move html output to reset password html file PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 9d736b26b8..fb66ea1b99 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -206,7 +206,7 @@ class reset_password { $message = $this->language->lang('PASSWORD_RESET_LINK_SENT') . '

' . $this->language->lang('RETURN_INDEX', 'root_path}index.{$this->php_ext}") . '">', ''); - if ($rowset === false) + if (empty($rowset)) { return $this->helper->message($message); } @@ -420,9 +420,13 @@ class reset_password } } + 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, - 'ERROR' => !empty($errors) ? implode('
', array_map([$this->language, 'lang'], $errors)) : '', 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), 'S_HIDDEN_FIELDS' => build_hidden_fields([ 'u' => $user_id, -- cgit v1.2.1 From f920336be4dcb3ae2df43c10dc8ef9ff1346ceb8 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Sun, 1 Sep 2019 11:36:57 +0200 Subject: [ticket/11327] Use http_exception instead of trigger_error PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index fb66ea1b99..d7b96c51c4 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -116,7 +116,10 @@ class reset_password if (!$this->config['allow_password_reset']) { - trigger_error($this->language->lang('UCP_PASSWORD_RESET_DISABLED', '', '')); + throw new http_exception(Response::HTTP_OK, 'UCP_PASSWORD_RESET_DISABLED', [ + '', + '' + ]); } } -- cgit v1.2.1 From 3a443b56233c58df49d15861c1c4add996b7660b Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Thu, 3 Oct 2019 16:56:17 +0200 Subject: [ticket/11327] Adjust code per review comments PHPBB3-11327 --- phpBB/phpbb/ucp/controller/reset_password.php | 35 ++++++++++++++------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index d7b96c51c4..666957b0dc 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -63,7 +63,7 @@ class reset_password protected $user; /** @var array phpBB DB table names */ - protected $tables; + protected $users_table; /** @var string phpBB root path */ protected $root_path; @@ -84,13 +84,14 @@ class reset_password * @param request_interface $request * @param template $template * @param user $user - * @param array $tables - * @param $root_path - * @param $php_ext + * @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, $tables, $root_path, $php_ext) + request_interface $request, template $template, user $user, string $users_table, + string $root_path, string $php_ext) { $this->config = $config; $this->db = $db; @@ -102,7 +103,7 @@ class reset_password $this->request = $request; $this->template = $template; $this->user = $user; - $this->tables = $tables; + $this->users_table = $users_table; $this->root_path = $root_path; $this->php_ext = $php_ext; } @@ -135,7 +136,7 @@ class reset_password 'reset_token_expiration' => 0, ]; - $sql = 'UPDATE ' . $this->tables['users'] . ' + $sql = 'UPDATE ' . $this->users_table . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $user_id; $this->db->sql_query($sql); @@ -171,7 +172,7 @@ class 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->tables['users'] => 'u'], + '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)) . "'" : ''), ]; @@ -228,10 +229,10 @@ class reset_password } // Check users permissions - $auth2 = new auth(); - $auth2->acl($user_row); + $auth = new auth(); + $auth->acl($user_row); - if (!$auth2->acl_get('u_chgpasswd')) + if (!$auth->acl_get('u_chgpasswd')) { return $this->helper->message($message); } @@ -244,7 +245,7 @@ class reset_password 'reset_token_expiration' => strtotime('+1 day'), ]; - $sql = 'UPDATE ' . $this->tables['users'] . ' + $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); @@ -314,7 +315,7 @@ class 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->tables['users'] => 'u'], + 'FROM' => [$this->users_table => 'u'], 'WHERE' => 'user_id = ' . $user_id, ]; @@ -373,10 +374,10 @@ class reset_password } // Check users permissions - $auth2 = new auth(); - $auth2->acl($user_row); + $auth = new auth(); + $auth->acl($user_row); - if (!$auth2->acl_get('u_chgpasswd')) + if (!$auth->acl_get('u_chgpasswd')) { return $this->helper->message($message); } @@ -410,7 +411,7 @@ class reset_password 'reset_token' => '', 'reset_token_expiration' => 0, ]; - $sql = 'UPDATE ' . $this->tables['users'] . ' + $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); -- cgit v1.2.1 From 60bc949ba1d5a6851e525868f69e997d4c8a2075 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Thu, 3 Oct 2019 23:05:02 +0200 Subject: [ticket/14465] Remove setting for maximum password length PHPBB3-14465 --- phpBB/phpbb/ucp/controller/reset_password.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 666957b0dc..7bd1b20cb3 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -393,10 +393,10 @@ class reset_password ]; $check_data = [ 'new_password' => [ - ['string', false, $this->config['min_pass_chars'], $this->config['max_pass_chars']], + ['string', false, $this->config['min_pass_chars'], 0], ['password'], ], - 'password_confirm' => ['string', true, $this->config['min_pass_chars'], $this->config['max_pass_chars']], + 'password_confirm' => ['string', true, $this->config['min_pass_chars'], 0], ]; $errors = array_merge($errors, validate_data($data, $check_data)); if (strcmp($data['new_password'], $data['password_confirm']) !== 0) -- cgit v1.2.1 From 9872316cac4df4987fdabc9512ca6ebeb7e5e04f Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Mon, 18 Nov 2019 21:06:00 +0100 Subject: [ticket/16167] Remove uses of user_email_hash PHPBB3-16167 --- phpBB/phpbb/ucp/controller/reset_password.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'phpBB/phpbb/ucp/controller/reset_password.php') diff --git a/phpBB/phpbb/ucp/controller/reset_password.php b/phpBB/phpbb/ucp/controller/reset_password.php index 7bd1b20cb3..5c27c4f414 100644 --- a/phpBB/phpbb/ucp/controller/reset_password.php +++ b/phpBB/phpbb/ucp/controller/reset_password.php @@ -173,7 +173,7 @@ class reset_password '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)) . "'" . + 'WHERE' => "user_email = '" . $this->db->sql_escape($email) . "'" . (!empty($username) ? " AND username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'" : ''), ]; -- cgit v1.2.1