MediaWiki
REL1_23
|
00001 <?php 00029 class SpecialChangePassword extends FormSpecialPage { 00030 00031 protected $mUserName, $mDomain; 00032 00033 // Optional Wikitext Message to show above the password change form 00034 protected $mPreTextMessage = null; 00035 00036 // label for old password input 00037 protected $mOldPassMsg = null; 00038 00039 public function __construct() { 00040 parent::__construct( 'ChangePassword', 'editmyprivateinfo' ); 00041 $this->listed( false ); 00042 } 00043 00047 function execute( $par ) { 00048 $this->getOutput()->disallowUserJs(); 00049 00050 parent::execute( $par ); 00051 } 00052 00053 protected function checkExecutePermissions( User $user ) { 00054 parent::checkExecutePermissions( $user ); 00055 00056 if ( !$this->getRequest()->wasPosted() ) { 00057 $this->requireLogin( 'resetpass-no-info' ); 00058 } 00059 } 00060 00066 public function setChangeMessage( Message $msg ) { 00067 $this->mPreTextMessage = $msg; 00068 } 00069 00075 public function setOldPasswordMessage( $msg ) { 00076 $this->mOldPassMsg = $msg; 00077 } 00078 00079 protected function getFormFields() { 00080 global $wgCookieExpiration; 00081 00082 $user = $this->getUser(); 00083 $request = $this->getRequest(); 00084 00085 $oldpassMsg = $this->mOldPassMsg; 00086 if ( !isset( $oldpassMsg ) ) { 00087 $oldpassMsg = $user->isLoggedIn() ? 'oldpassword' : 'resetpass-temp-password'; 00088 } 00089 00090 $fields = array( 00091 'Name' => array( 00092 'type' => 'info', 00093 'label-message' => 'username', 00094 'default' => $request->getVal( 'wpName', $user->getName() ), 00095 ), 00096 'Password' => array( 00097 'type' => 'password', 00098 'label-message' => $oldpassMsg, 00099 ), 00100 'NewPassword' => array( 00101 'type' => 'password', 00102 'label-message' => 'newpassword', 00103 ), 00104 'Retype' => array( 00105 'type' => 'password', 00106 'label-message' => 'retypenew', 00107 ), 00108 ); 00109 00110 if ( !$this->getUser()->isLoggedIn() ) { 00111 if ( !LoginForm::getLoginToken() ) { 00112 LoginForm::setLoginToken(); 00113 } 00114 $fields['LoginOnChangeToken'] = array( 00115 'type' => 'hidden', 00116 'label' => 'Change Password Token', 00117 'default' => LoginForm::getLoginToken(), 00118 ); 00119 } 00120 00121 $extraFields = array(); 00122 wfRunHooks( 'ChangePasswordForm', array( &$extraFields ) ); 00123 foreach ( $extraFields as $extra ) { 00124 list( $name, $label, $type, $default ) = $extra; 00125 $fields[$name] = array( 00126 'type' => $type, 00127 'name' => $name, 00128 'label-message' => $label, 00129 'default' => $default, 00130 ); 00131 } 00132 00133 if ( !$user->isLoggedIn() ) { 00134 $fields['Remember'] = array( 00135 'type' => 'check', 00136 'label' => $this->msg( 'remembermypassword' ) 00137 ->numParams( ceil( $wgCookieExpiration / ( 3600 * 24 ) ) ) 00138 ->text(), 00139 'default' => $request->getVal( 'wpRemember' ), 00140 ); 00141 } 00142 00143 return $fields; 00144 } 00145 00146 protected function alterForm( HTMLForm $form ) { 00147 $form->setId( 'mw-resetpass-form' ); 00148 $form->setTableId( 'mw-resetpass-table' ); 00149 $form->setWrapperLegendMsg( 'resetpass_header' ); 00150 $form->setSubmitTextMsg( 00151 $this->getUser()->isLoggedIn() 00152 ? 'resetpass-submit-loggedin' 00153 : 'resetpass_submit' 00154 ); 00155 $form->addButton( 'wpCancel', $this->msg( 'resetpass-submit-cancel' )->text() ); 00156 $form->setHeaderText( $this->msg( 'resetpass_text' )->parseAsBlock() ); 00157 if ( $this->mPreTextMessage instanceof Message ) { 00158 $form->addPreText( $this->mPreTextMessage->parseAsBlock() ); 00159 } 00160 $form->addHiddenFields( 00161 $this->getRequest()->getValues( 'wpName', 'wpDomain', 'returnto', 'returntoquery' ) ); 00162 } 00163 00164 public function onSubmit( array $data ) { 00165 global $wgAuth; 00166 00167 $request = $this->getRequest(); 00168 00169 if ( $request->getCheck( 'wpLoginToken' ) ) { 00170 // This comes from Special:Userlogin when logging in with a temporary password 00171 return false; 00172 } 00173 00174 if ( !$this->getUser()->isLoggedIn() 00175 && $request->getVal( 'wpLoginOnChangeToken' ) !== LoginForm::getLoginToken() 00176 ) { 00177 // Potential CSRF (bug 62497) 00178 return false; 00179 } 00180 00181 00182 if ( $request->getCheck( 'wpCancel' ) ) { 00183 $titleObj = Title::newFromText( $request->getVal( 'returnto' ) ); 00184 if ( !$titleObj instanceof Title ) { 00185 $titleObj = Title::newMainPage(); 00186 } 00187 $query = $request->getVal( 'returntoquery' ); 00188 $this->getOutput()->redirect( $titleObj->getFullURL( $query ) ); 00189 00190 return true; 00191 } 00192 00193 try { 00194 $this->mUserName = $request->getVal( 'wpName', $this->getUser()->getName() ); 00195 $this->mDomain = $wgAuth->getDomain(); 00196 00197 if ( !$wgAuth->allowPasswordChange() ) { 00198 throw new ErrorPageError( 'changepassword', 'resetpass_forbidden' ); 00199 } 00200 00201 $this->attemptReset( $data['Password'], $data['NewPassword'], $data['Retype'] ); 00202 00203 return true; 00204 } catch ( PasswordError $e ) { 00205 return $e->getMessage(); 00206 } 00207 } 00208 00209 public function onSuccess() { 00210 if ( $this->getUser()->isLoggedIn() ) { 00211 $this->getOutput()->wrapWikiMsg( 00212 "<div class=\"successbox\">\n$1\n</div>", 00213 'changepassword-success' 00214 ); 00215 $this->getOutput()->returnToMain(); 00216 } else { 00217 $request = $this->getRequest(); 00218 LoginForm::setLoginToken(); 00219 $token = LoginForm::getLoginToken(); 00220 $data = array( 00221 'action' => 'submitlogin', 00222 'wpName' => $this->mUserName, 00223 'wpDomain' => $this->mDomain, 00224 'wpLoginToken' => $token, 00225 'wpPassword' => $request->getVal( 'wpNewPassword' ), 00226 ) + $request->getValues( 'wpRemember', 'returnto', 'returntoquery' ); 00227 $login = new LoginForm( new DerivativeRequest( $request, $data, true ) ); 00228 $login->setContext( $this->getContext() ); 00229 $login->execute( null ); 00230 } 00231 } 00232 00236 protected function attemptReset( $oldpass, $newpass, $retype ) { 00237 global $wgPasswordAttemptThrottle; 00238 00239 $isSelf = ( $this->mUserName === $this->getUser()->getName() ); 00240 if ( $isSelf ) { 00241 $user = $this->getUser(); 00242 } else { 00243 $user = User::newFromName( $this->mUserName ); 00244 } 00245 00246 if ( !$user || $user->isAnon() ) { 00247 throw new PasswordError( $this->msg( 'nosuchusershort', $this->mUserName )->text() ); 00248 } 00249 00250 if ( $newpass !== $retype ) { 00251 wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) ); 00252 throw new PasswordError( $this->msg( 'badretype' )->text() ); 00253 } 00254 00255 $throttleCount = LoginForm::incLoginThrottle( $this->mUserName ); 00256 if ( $throttleCount === true ) { 00257 $lang = $this->getLanguage(); 00258 throw new PasswordError( $this->msg( 'changepassword-throttled' ) 00259 ->params( $lang->formatDuration( $wgPasswordAttemptThrottle['seconds'] ) ) 00260 ->text() 00261 ); 00262 } 00263 00264 // @TODO Make these separate messages, since the message is written for both cases 00265 if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) { 00266 wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) ); 00267 throw new PasswordError( $this->msg( 'resetpass-wrong-oldpass' )->text() ); 00268 } 00269 00270 // User is resetting their password to their old password 00271 if ( $oldpass === $newpass ) { 00272 throw new PasswordError( $this->msg( 'resetpass-recycled' )->text() ); 00273 } 00274 00275 // Do AbortChangePassword after checking mOldpass, so we don't leak information 00276 // by possibly aborting a new password before verifying the old password. 00277 $abortMsg = 'resetpass-abort-generic'; 00278 if ( !wfRunHooks( 'AbortChangePassword', array( $user, $oldpass, $newpass, &$abortMsg ) ) ) { 00279 wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'abortreset' ) ); 00280 throw new PasswordError( $this->msg( $abortMsg )->text() ); 00281 } 00282 00283 // Please reset throttle for successful logins, thanks! 00284 if ( $throttleCount ) { 00285 LoginForm::clearLoginThrottle( $this->mUserName ); 00286 } 00287 00288 try { 00289 $user->setPassword( $newpass ); 00290 wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) ); 00291 } catch ( PasswordError $e ) { 00292 wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) ); 00293 throw new PasswordError( $e->getMessage() ); 00294 } 00295 00296 if ( $isSelf ) { 00297 // This is needed to keep the user connected since 00298 // changing the password also modifies the user's token. 00299 $user->setCookies(); 00300 } 00301 $user->resetPasswordExpiration(); 00302 $user->saveSettings(); 00303 } 00304 00305 public function requiresUnblock() { 00306 return false; 00307 } 00308 00309 protected function getGroupName() { 00310 return 'users'; 00311 } 00312 }