[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |