[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/specials/ -> SpecialChangePassword.php (source)

   1  <?php
   2  /**
   3   * Implements Special:ChangePassword
   4   *
   5   * This program is free software; you can redistribute it and/or modify
   6   * it under the terms of the GNU General Public License as published by
   7   * the Free Software Foundation; either version 2 of the License, or
   8   * (at your option) any later version.
   9   *
  10   * This program is distributed in the hope that it will be useful,
  11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13   * GNU General Public License for more details.
  14   *
  15   * You should have received a copy of the GNU General Public License along
  16   * with this program; if not, write to the Free Software Foundation, Inc.,
  17   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18   * http://www.gnu.org/copyleft/gpl.html
  19   *
  20   * @file
  21   * @ingroup SpecialPage
  22   */
  23  
  24  /**
  25   * Let users recover their password.
  26   *
  27   * @ingroup SpecialPage
  28   */
  29  class SpecialChangePassword extends FormSpecialPage {
  30      protected $mUserName;
  31      protected $mDomain;
  32  
  33      // Optional Wikitext Message to show above the password change form
  34      protected $mPreTextMessage = null;
  35  
  36      // label for old password input
  37      protected $mOldPassMsg = null;
  38  
  39  	public function __construct() {
  40          parent::__construct( 'ChangePassword', 'editmyprivateinfo' );
  41          $this->listed( false );
  42      }
  43  
  44      /**
  45       * Main execution point
  46       * @param string|null $par
  47       */
  48  	function execute( $par ) {
  49          $this->getOutput()->disallowUserJs();
  50  
  51          parent::execute( $par );
  52      }
  53  
  54  	protected function checkExecutePermissions( User $user ) {
  55          parent::checkExecutePermissions( $user );
  56  
  57          if ( !$this->getRequest()->wasPosted() ) {
  58              $this->requireLogin( 'resetpass-no-info' );
  59          }
  60      }
  61  
  62      /**
  63       * Set a message at the top of the Change Password form
  64       * @since 1.23
  65       * @param Message $msg Message to parse and add to the form header
  66       */
  67  	public function setChangeMessage( Message $msg ) {
  68          $this->mPreTextMessage = $msg;
  69      }
  70  
  71      /**
  72       * Set a message at the top of the Change Password form
  73       * @since 1.23
  74       * @param string $msg Message label for old/temp password field
  75       */
  76  	public function setOldPasswordMessage( $msg ) {
  77          $this->mOldPassMsg = $msg;
  78      }
  79  
  80  	protected function getFormFields() {
  81          $user = $this->getUser();
  82          $request = $this->getRequest();
  83  
  84          $oldpassMsg = $this->mOldPassMsg;
  85          if ( $oldpassMsg === null ) {
  86              $oldpassMsg = $user->isLoggedIn() ? 'oldpassword' : 'resetpass-temp-password';
  87          }
  88  
  89          $fields = array(
  90              'Name' => array(
  91                  'type' => 'info',
  92                  'label-message' => 'username',
  93                  'default' => $request->getVal( 'wpName', $user->getName() ),
  94              ),
  95              'Password' => array(
  96                  'type' => 'password',
  97                  'label-message' => $oldpassMsg,
  98              ),
  99              'NewPassword' => array(
 100                  'type' => 'password',
 101                  'label-message' => 'newpassword',
 102              ),
 103              'Retype' => array(
 104                  'type' => 'password',
 105                  'label-message' => 'retypenew',
 106              ),
 107          );
 108  
 109          if ( !$this->getUser()->isLoggedIn() ) {
 110              if ( !LoginForm::getLoginToken() ) {
 111                  LoginForm::setLoginToken();
 112              }
 113              $fields['LoginOnChangeToken'] = array(
 114                  'type' => 'hidden',
 115                  'label' => 'Change Password Token',
 116                  'default' => LoginForm::getLoginToken(),
 117              );
 118          }
 119  
 120          $extraFields = array();
 121          wfRunHooks( 'ChangePasswordForm', array( &$extraFields ) );
 122          foreach ( $extraFields as $extra ) {
 123              list( $name, $label, $type, $default ) = $extra;
 124              $fields[$name] = array(
 125                  'type' => $type,
 126                  'name' => $name,
 127                  'label-message' => $label,
 128                  'default' => $default,
 129              );
 130          }
 131  
 132          if ( !$user->isLoggedIn() ) {
 133              $fields['Remember'] = array(
 134                  'type' => 'check',
 135                  'label' => $this->msg( 'remembermypassword' )
 136                          ->numParams(
 137                              ceil( $this->getConfig()->get( 'CookieExpiration' ) / ( 3600 * 24 ) )
 138                          )->text(),
 139                  'default' => $request->getVal( 'wpRemember' ),
 140              );
 141          }
 142  
 143          return $fields;
 144      }
 145  
 146  	protected function alterForm( HTMLForm $form ) {
 147          $form->setId( 'mw-resetpass-form' );
 148          $form->setTableId( 'mw-resetpass-table' );
 149          $form->setWrapperLegendMsg( 'resetpass_header' );
 150          $form->setSubmitTextMsg(
 151              $this->getUser()->isLoggedIn()
 152                  ? 'resetpass-submit-loggedin'
 153                  : 'resetpass_submit'
 154          );
 155          $form->addButton( 'wpCancel', $this->msg( 'resetpass-submit-cancel' )->text() );
 156          $form->setHeaderText( $this->msg( 'resetpass_text' )->parseAsBlock() );
 157          if ( $this->mPreTextMessage instanceof Message ) {
 158              $form->addPreText( $this->mPreTextMessage->parseAsBlock() );
 159          }
 160          $form->addHiddenFields(
 161              $this->getRequest()->getValues( 'wpName', 'wpDomain', 'returnto', 'returntoquery' ) );
 162      }
 163  
 164  	public function onSubmit( array $data ) {
 165          global $wgAuth;
 166  
 167          $request = $this->getRequest();
 168  
 169          if ( $request->getCheck( 'wpLoginToken' ) ) {
 170              // This comes from Special:Userlogin when logging in with a temporary password
 171              return false;
 172          }
 173  
 174          if ( !$this->getUser()->isLoggedIn()
 175              && $request->getVal( 'wpLoginOnChangeToken' ) !== LoginForm::getLoginToken()
 176          ) {
 177              // Potential CSRF (bug 62497)
 178              return false;
 179          }
 180  
 181          if ( $request->getCheck( 'wpCancel' ) ) {
 182              $titleObj = Title::newFromText( $request->getVal( 'returnto' ) );
 183              if ( !$titleObj instanceof Title ) {
 184                  $titleObj = Title::newMainPage();
 185              }
 186              $query = $request->getVal( 'returntoquery' );
 187              $this->getOutput()->redirect( $titleObj->getFullURL( $query ) );
 188  
 189              return true;
 190          }
 191  
 192          try {
 193              $this->mUserName = $request->getVal( 'wpName', $this->getUser()->getName() );
 194              $this->mDomain = $wgAuth->getDomain();
 195  
 196              if ( !$wgAuth->allowPasswordChange() ) {
 197                  throw new ErrorPageError( 'changepassword', 'resetpass_forbidden' );
 198              }
 199  
 200              $this->attemptReset( $data['Password'], $data['NewPassword'], $data['Retype'] );
 201  
 202              return true;
 203          } catch ( PasswordError $e ) {
 204              return $e->getMessage();
 205          }
 206      }
 207  
 208  	public function onSuccess() {
 209          if ( $this->getUser()->isLoggedIn() ) {
 210              $this->getOutput()->wrapWikiMsg(
 211                  "<div class=\"successbox\">\n$1\n</div>",
 212                  'changepassword-success'
 213              );
 214              $this->getOutput()->returnToMain();
 215          } else {
 216              $request = $this->getRequest();
 217              LoginForm::setLoginToken();
 218              $token = LoginForm::getLoginToken();
 219              $data = array(
 220                  'action' => 'submitlogin',
 221                  'wpName' => $this->mUserName,
 222                  'wpDomain' => $this->mDomain,
 223                  'wpLoginToken' => $token,
 224                  'wpPassword' => $request->getVal( 'wpNewPassword' ),
 225              ) + $request->getValues( 'wpRemember', 'returnto', 'returntoquery' );
 226              $login = new LoginForm( new DerivativeRequest( $request, $data, true ) );
 227              $login->setContext( $this->getContext() );
 228              $login->execute( null );
 229          }
 230      }
 231  
 232      /**
 233       * @param string $oldpass
 234       * @param string $newpass
 235       * @param string $retype
 236       * @throws PasswordError When cannot set the new password because requirements not met.
 237       */
 238  	protected function attemptReset( $oldpass, $newpass, $retype ) {
 239          $isSelf = ( $this->mUserName === $this->getUser()->getName() );
 240          if ( $isSelf ) {
 241              $user = $this->getUser();
 242          } else {
 243              $user = User::newFromName( $this->mUserName );
 244          }
 245  
 246          if ( !$user || $user->isAnon() ) {
 247              throw new PasswordError( $this->msg( 'nosuchusershort', $this->mUserName )->text() );
 248          }
 249  
 250          if ( $newpass !== $retype ) {
 251              wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
 252              throw new PasswordError( $this->msg( 'badretype' )->text() );
 253          }
 254  
 255          $throttleCount = LoginForm::incLoginThrottle( $this->mUserName );
 256          if ( $throttleCount === true ) {
 257              $lang = $this->getLanguage();
 258              $throttleInfo = $this->getConfig()->get( 'PasswordAttemptThrottle' );
 259              throw new PasswordError( $this->msg( 'changepassword-throttled' )
 260                  ->params( $lang->formatDuration( $throttleInfo['seconds'] ) )
 261                  ->text()
 262              );
 263          }
 264  
 265          // @todo Make these separate messages, since the message is written for both cases
 266          if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) {
 267              wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
 268              throw new PasswordError( $this->msg( 'resetpass-wrong-oldpass' )->text() );
 269          }
 270  
 271          // User is resetting their password to their old password
 272          if ( $oldpass === $newpass ) {
 273              throw new PasswordError( $this->msg( 'resetpass-recycled' )->text() );
 274          }
 275  
 276          // Do AbortChangePassword after checking mOldpass, so we don't leak information
 277          // by possibly aborting a new password before verifying the old password.
 278          $abortMsg = 'resetpass-abort-generic';
 279          if ( !wfRunHooks( 'AbortChangePassword', array( $user, $oldpass, $newpass, &$abortMsg ) ) ) {
 280              wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'abortreset' ) );
 281              throw new PasswordError( $this->msg( $abortMsg )->text() );
 282          }
 283  
 284          // Please reset throttle for successful logins, thanks!
 285          if ( $throttleCount ) {
 286              LoginForm::clearLoginThrottle( $this->mUserName );
 287          }
 288  
 289          try {
 290              $user->setPassword( $newpass );
 291              wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
 292          } catch ( PasswordError $e ) {
 293              wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
 294              throw new PasswordError( $e->getMessage() );
 295          }
 296  
 297          if ( $isSelf ) {
 298              // This is needed to keep the user connected since
 299              // changing the password also modifies the user's token.
 300              $remember = $this->getRequest()->getCookie( 'Token' ) !== null;
 301              $user->setCookies( null, null, $remember );
 302          }
 303          $user->resetPasswordExpiration();
 304          $user->saveSettings();
 305      }
 306  
 307  	public function requiresUnblock() {
 308          return false;
 309      }
 310  
 311  	protected function getGroupName() {
 312          return 'users';
 313      }
 314  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1