[ Index ]

PHP Cross Reference of phpBB-3.3.0-deutsch

title

Body

[close]

/phpbb/ucp/controller/ -> reset_password.php (source)

   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']) . '">',
 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'    => strtotime('+1 day'),
 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'            => htmlspecialchars_decode($user_row['username']),
 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_login_attempts'        => 0,
 411                      'reset_token'                => '',
 412                      'reset_token_expiration'    => 0,
 413                  ];
 414                  $sql = 'UPDATE ' . $this->users_table . '
 415                              SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . '
 416                              WHERE user_id = ' . (int) $user_row['user_id'];
 417                  $this->db->sql_query($sql);
 418                  $this->log->add('user', $user_row['user_id'], $this->user->ip, 'LOG_USER_NEW_PASSWORD', false, [
 419                      'reportee_id' => $user_row['user_id'],
 420                      $user_row['username']
 421                  ]);
 422                  meta_refresh(3, append_sid("{$this->root_path}index.{$this->php_ext}"));
 423                  return $this->helper->message($this->language->lang('PASSWORD_RESET'));
 424              }
 425          }
 426  
 427          if (!empty($errors))
 428          {
 429              $this->template->assign_block_vars_array('PASSWORD_RESET_ERRORS', array_map([$this->language, 'lang'], $errors));
 430          }
 431  
 432          $this->template->assign_vars([
 433              'S_IS_PASSWORD_RESET'        => true,
 434              'U_RESET_PASSWORD_ACTION'    => $this->helper->route('phpbb_ucp_reset_password_controller'),
 435              'S_HIDDEN_FIELDS'            => build_hidden_fields([
 436                  'u'        => $user_id,
 437                  'token'    => $reset_token,
 438              ]),
 439          ]);
 440  
 441          return $this->helper->render('ucp_reset_password.html', $this->language->lang('RESET_PASSWORD'));
 442      }
 443  }


Generated: Tue Apr 7 19:44:41 2020 Cross-referenced by PHPXref 0.7.1