[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 namespace phpbb\ucp\controller; 15 16 use phpbb\auth\auth; 17 use phpbb\config\config; 18 use phpbb\controller\helper; 19 use phpbb\db\driver\driver_interface; 20 use phpbb\event\dispatcher; 21 use phpbb\exception\http_exception; 22 use phpbb\language\language; 23 use phpbb\log\log_interface; 24 use phpbb\passwords\manager; 25 use phpbb\request\request_interface; 26 use phpbb\template\template; 27 use phpbb\user; 28 use Symfony\Component\HttpFoundation\Response; 29 30 /** 31 * Handling forgotten passwords via reset password functionality 32 */ 33 class reset_password 34 { 35 /** @var config */ 36 protected $config; 37 38 /** @var driver_interface */ 39 protected $db; 40 41 /** @var dispatcher */ 42 protected $dispatcher; 43 44 /** @var helper */ 45 protected $helper; 46 47 /** @var language */ 48 protected $language; 49 50 /** @var log_interface */ 51 protected $log; 52 53 /** @var manager */ 54 protected $passwords_manager; 55 56 /** @var request_interface */ 57 protected $request; 58 59 /** @var template */ 60 protected $template; 61 62 /** @var user */ 63 protected $user; 64 65 /** @var array phpBB DB table names */ 66 protected $users_table; 67 68 /** @var string phpBB root path */ 69 protected $root_path; 70 71 /** @var string PHP extension */ 72 protected $php_ext; 73 74 /** 75 * Reset password controller constructor. 76 * 77 * @param config $config 78 * @param driver_interface $db 79 * @param dispatcher $dispatcher 80 * @param helper $helper 81 * @param language $language 82 * @param log_interface $log 83 * @param manager $passwords_manager 84 * @param request_interface $request 85 * @param template $template 86 * @param user $user 87 * @param string $users_table 88 * @param string $root_path 89 * @param string $php_ext 90 */ 91 public function __construct(config $config, driver_interface $db, dispatcher $dispatcher, helper $helper, 92 language $language, log_interface $log, manager $passwords_manager, 93 request_interface $request, template $template, user $user, string $users_table, 94 string $root_path, string $php_ext) 95 { 96 $this->config = $config; 97 $this->db = $db; 98 $this->dispatcher = $dispatcher; 99 $this->helper = $helper; 100 $this->language = $language; 101 $this->log = $log; 102 $this->passwords_manager = $passwords_manager; 103 $this->request = $request; 104 $this->template = $template; 105 $this->user = $user; 106 $this->users_table = $users_table; 107 $this->root_path = $root_path; 108 $this->php_ext = $php_ext; 109 } 110 111 /** 112 * Init controller 113 */ 114 protected function init_controller() 115 { 116 $this->language->add_lang('ucp'); 117 118 if (!$this->config['allow_password_reset']) 119 { 120 throw new http_exception(Response::HTTP_OK, 'UCP_PASSWORD_RESET_DISABLED', [ 121 '<a href="mailto:' . htmlspecialchars($this->config['board_contact'], ENT_COMPAT) . '">', 122 '</a>' 123 ]); 124 } 125 } 126 127 /** 128 * Remove reset token for specified user 129 * 130 * @param int $user_id User ID 131 */ 132 protected function remove_reset_token(int $user_id) 133 { 134 $sql_ary = [ 135 'reset_token' => '', 136 'reset_token_expiration' => 0, 137 ]; 138 139 $sql = 'UPDATE ' . $this->users_table . ' 140 SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' 141 WHERE user_id = ' . $user_id; 142 $this->db->sql_query($sql); 143 } 144 145 /** 146 * Handle password reset request 147 * 148 * @return Response 149 */ 150 public function request() 151 { 152 $this->init_controller(); 153 154 $submit = $this->request->is_set_post('submit'); 155 $username = $this->request->variable('username', '', true); 156 $email = strtolower($this->request->variable('email', '')); 157 158 add_form_key('ucp_reset_password'); 159 160 if ($submit) 161 { 162 if (!check_form_key('ucp_reset_password')) 163 { 164 throw new http_exception(Response::HTTP_UNAUTHORIZED, 'FORM_INVALID'); 165 } 166 167 if (empty($email)) 168 { 169 return $this->helper->message('NO_EMAIL_USER'); 170 } 171 172 $sql_array = [ 173 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type,' 174 . ' user_lang, user_inactive_reason, reset_token, reset_token_expiration', 175 'FROM' => [$this->users_table => 'u'], 176 'WHERE' => "user_email = '" . $this->db->sql_escape($email) . "'" . 177 (!empty($username) ? " AND username_clean = '" . $this->db->sql_escape(utf8_clean_string($username)) . "'" : ''), 178 ]; 179 180 /** 181 * Change SQL query for fetching user data 182 * 183 * @event core.ucp_remind_modify_select_sql 184 * @var string email User's email from the form 185 * @var string username User's username from the form 186 * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE 187 * @since 3.1.11-RC1 188 * @changed 3.3.0-b1 Moved to reset password controller 189 */ 190 $vars = [ 191 'email', 192 'username', 193 'sql_array', 194 ]; 195 extract($this->dispatcher->trigger_event('core.ucp_remind_modify_select_sql', compact($vars))); 196 197 $sql = $this->db->sql_build_query('SELECT', $sql_array); 198 $result = $this->db->sql_query_limit($sql, 2); // don't waste resources on more rows than we need 199 $rowset = $this->db->sql_fetchrowset($result); 200 $this->db->sql_freeresult($result); 201 202 if (count($rowset) > 1) 203 { 204 $this->template->assign_vars([ 205 'USERNAME_REQUIRED' => true, 206 'EMAIL' => $email, 207 ]); 208 } 209 else 210 { 211 $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>'); 212 213 if (empty($rowset)) 214 { 215 return $this->helper->message($message); 216 } 217 218 $user_row = $rowset[0]; 219 220 if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) 221 { 222 return $this->helper->message($message); 223 } 224 225 // Do not create multiple valid reset tokens 226 if (!empty($user_row['reset_token']) && (int) $user_row['reset_token_expiration'] >= time()) 227 { 228 return $this->helper->message($message); 229 } 230 231 // Check users permissions 232 $auth = new auth(); 233 $auth->acl($user_row); 234 235 if (!$auth->acl_get('u_chgpasswd')) 236 { 237 return $this->helper->message($message); 238 } 239 240 // Generate reset token 241 $reset_token = strtolower(gen_rand_string(32)); 242 243 $sql_ary = [ 244 'reset_token' => $reset_token, 245 'reset_token_expiration' => $this->user::get_token_expiration(), 246 ]; 247 248 $sql = 'UPDATE ' . $this->users_table . ' 249 SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' 250 WHERE user_id = ' . $user_row['user_id']; 251 $this->db->sql_query($sql); 252 253 if (!class_exists('messenger')) 254 { 255 include($this->root_path . 'includes/functions_messenger.' . $this->php_ext); 256 } 257 258 /** @var \messenger $messenger */ 259 $messenger = new \messenger(false); 260 261 $messenger->template('user_forgot_password', $user_row['user_lang']); 262 263 $messenger->set_addresses($user_row); 264 265 $messenger->anti_abuse_headers($this->config, $this->user); 266 267 $messenger->assign_vars([ 268 'USERNAME' => html_entity_decode($user_row['username'], ENT_COMPAT), 269 'U_RESET_PASSWORD' => generate_board_url(true) . $this->helper->route('phpbb_ucp_reset_password_controller', [ 270 'u' => $user_row['user_id'], 271 'token' => $reset_token, 272 ], false) 273 ]); 274 275 $messenger->send($user_row['user_notify_type']); 276 277 return $this->helper->message($message); 278 } 279 } 280 281 $this->template->assign_vars([ 282 'USERNAME' => $username, 283 'EMAIL' => $email, 284 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_forgot_password_controller'), 285 ]); 286 287 return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); 288 } 289 290 /** 291 * Handle controller requests 292 * 293 * @return Response 294 */ 295 public function reset() 296 { 297 $this->init_controller(); 298 299 $submit = $this->request->is_set_post('submit'); 300 $reset_token = $this->request->variable('token', ''); 301 $user_id = $this->request->variable('u', 0); 302 303 if (empty($reset_token)) 304 { 305 return $this->helper->message('NO_RESET_TOKEN'); 306 } 307 308 if (!$user_id) 309 { 310 return $this->helper->message('NO_USER'); 311 } 312 313 add_form_key('ucp_reset_password'); 314 315 $sql_array = [ 316 'SELECT' => 'user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type,' 317 . ' user_lang, user_inactive_reason, reset_token, reset_token_expiration', 318 'FROM' => [$this->users_table => 'u'], 319 'WHERE' => 'user_id = ' . $user_id, 320 ]; 321 322 /** 323 * Change SQL query for fetching user data 324 * 325 * @event core.ucp_reset_password_modify_select_sql 326 * @var int user_id User ID from the form 327 * @var string reset_token Reset token 328 * @var array sql_array Fully assembled SQL query with keys SELECT, FROM, WHERE 329 * @since 3.3.0-b1 330 */ 331 $vars = [ 332 'user_id', 333 'reset_token', 334 'sql_array', 335 ]; 336 extract($this->dispatcher->trigger_event('core.ucp_reset_password_modify_select_sql', compact($vars))); 337 338 $sql = $this->db->sql_build_query('SELECT', $sql_array); 339 $result = $this->db->sql_query_limit($sql, 1); 340 $user_row = $this->db->sql_fetchrow($result); 341 $this->db->sql_freeresult($result); 342 343 $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>'); 344 345 if (empty($user_row)) 346 { 347 return $this->helper->message($message); 348 } 349 350 if (!hash_equals($reset_token, $user_row['reset_token'])) 351 { 352 return $this->helper->message($message); 353 } 354 355 if ($user_row['reset_token_expiration'] < time()) 356 { 357 $this->remove_reset_token($user_id); 358 359 return $this->helper->message($message); 360 } 361 362 $errors = []; 363 364 if ($submit) 365 { 366 if (!check_form_key('ucp_reset_password')) 367 { 368 return $this->helper->message('FORM_INVALID'); 369 } 370 371 if ($user_row['user_type'] == USER_IGNORE || $user_row['user_type'] == USER_INACTIVE) 372 { 373 return $this->helper->message($message); 374 } 375 376 // Check users permissions 377 $auth = new auth(); 378 $auth->acl($user_row); 379 380 if (!$auth->acl_get('u_chgpasswd')) 381 { 382 return $this->helper->message($message); 383 } 384 385 if (!function_exists('validate_data')) 386 { 387 include($this->root_path . 'includes/functions_user.' . $this->php_ext); 388 } 389 390 $data = [ 391 'new_password' => $this->request->untrimmed_variable('new_password', '', true), 392 'password_confirm' => $this->request->untrimmed_variable('new_password_confirm', '', true), 393 ]; 394 $check_data = [ 395 'new_password' => [ 396 ['string', false, $this->config['min_pass_chars'], 0], 397 ['password'], 398 ], 399 'password_confirm' => ['string', true, $this->config['min_pass_chars'], 0], 400 ]; 401 $errors = array_merge($errors, validate_data($data, $check_data)); 402 if (strcmp($data['new_password'], $data['password_confirm']) !== 0) 403 { 404 $errors[] = $data['password_confirm'] ? 'NEW_PASSWORD_ERROR' : 'NEW_PASSWORD_CONFIRM_EMPTY'; 405 } 406 if (empty($errors)) 407 { 408 $sql_ary = [ 409 'user_password' => $this->passwords_manager->hash($data['new_password']), 410 'user_passchg' => time(), 411 'user_login_attempts' => 0, 412 'reset_token' => '', 413 'reset_token_expiration' => 0, 414 ]; 415 $sql = 'UPDATE ' . $this->users_table . ' 416 SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' 417 WHERE user_id = ' . (int) $user_row['user_id']; 418 $this->db->sql_query($sql); 419 $this->user->reset_login_keys($user_row['user_id']); 420 $this->log->add('user', $user_row['user_id'], $this->user->ip, 'LOG_USER_NEW_PASSWORD', false, [ 421 'reportee_id' => $user_row['user_id'], 422 $user_row['username'] 423 ]); 424 meta_refresh(3, append_sid("{$this->root_path}index.{$this->php_ext}")); 425 return $this->helper->message($this->language->lang('PASSWORD_RESET')); 426 } 427 } 428 429 $this->template->assign_vars([ 430 'PASSWORD_RESET_ERRORS' => !empty($errors) ? array_map([$this->language, 'lang'], $errors) : '', 431 'S_IS_PASSWORD_RESET' => true, 432 'U_RESET_PASSWORD_ACTION' => $this->helper->route('phpbb_ucp_reset_password_controller'), 433 'L_CHANGE_PASSWORD_EXPLAIN' => $this->language->lang($this->config['pass_complex'] . '_EXPLAIN', $this->language->lang('CHARACTERS', (int) $this->config['min_pass_chars'])), 434 'S_HIDDEN_FIELDS' => build_hidden_fields([ 435 'u' => $user_id, 436 'token' => $reset_token, 437 ]), 438 ]); 439 440 return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD')); 441 } 442 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |