8 * Let users recover their password.
11 class SpecialResetpass
extends SpecialPage
{
13 private $mSelfChange = true; // Usually, but sometimes not :)
14 private $mUser = null; // The user requesting the reset
16 public function __construct() {
17 parent
::__construct( 'Resetpass' );
21 * Sometimes the user requesting the password change is not $wgUser
25 public function setUser( $usr ) {
30 * Main execution point
32 function execute( $par ) {
33 global $wgUser, $wgAuth, $wgOut, $wgRequest;
35 $this->mUserName
= $wgRequest->getVal( 'wpName', $par );
36 $this->mOldpass
= $wgRequest->getVal( 'wpPassword' );
37 $this->mNewpass
= $wgRequest->getVal( 'wpNewPassword' );
38 $this->mRetype
= $wgRequest->getVal( 'wpRetype' );
39 $this->mComment
= $wgRequest->getVal( 'wpComment' );
41 if ( is_null( $this->mUser
) ) {
42 $this->mUser
= $wgUser;
46 $this->outputHeader();
48 if( !$wgAuth->allowPasswordChange() ) {
49 $this->error( wfMsg( 'resetpass_forbidden' ) );
53 // Default to our own username when not given one
54 if ( !$this->mUserName
) {
55 $this->mUserName
= $this->mUser
->getName();
58 // Are we changing our own?
59 if ( $this->mUser
->getName() != $this->mUserName
) {
60 $this->mSelfChange
= false; // We're changing someone else
63 if( !$wgRequest->wasPosted() && !$this->mUser
->isLoggedIn() ) {
64 $this->error( wfMsg( 'resetpass-no-info' ) );
68 if ( !$this->mSelfChange
&& !$this->mUser
->isAllowed( 'reset-passwords' ) ) {
69 $this->error( wfMsg( 'resetpass-no-others' ) );
73 if( $wgRequest->wasPosted() && $this->mUser
->matchEditToken( $wgRequest->getVal('token') ) ) {
75 $this->attemptReset( $this->mNewpass
, $this->mRetype
);
76 $wgOut->addWikiMsg( 'resetpass_success' );
77 // Only attempt this login session if we're changing our own password
78 if( $this->mSelfChange
&& !$wgUser->isLoggedIn() ) {
80 'action' => 'submitlogin',
81 'wpName' => $this->mUserName
,
82 'wpPassword' => $this->mNewpass
,
83 'returnto' => $wgRequest->getVal( 'returnto' ),
85 if( $wgRequest->getCheck( 'wpRemember' ) ) {
86 $data['wpRemember'] = 1;
88 $login = new LoginForm( new FauxRequest( $data, true ) );
91 $titleObj = Title
::newFromText( $wgRequest->getVal( 'returnto' ) );
92 if ( !$titleObj instanceof Title
) {
93 $titleObj = Title
::newMainPage();
95 $wgOut->redirect( $titleObj->getFullURL() );
96 } catch( PasswordError
$e ) {
97 $this->error( $e->getMessage() );
103 function error( $msg ) {
105 $wgOut->addHTML( Xml
::element('p', array( 'class' => 'error' ), $msg ) );
108 function showForm() {
109 global $wgOut, $wgUser, $wgRequest;
111 $wgOut->disallowUserJs();
113 if ( $this->mUser
->isAllowed( 'reset-passwords') ) {
114 $wgOut->addScriptFile( 'changepassword.js' );
117 $self = SpecialPage
::getTitleFor( 'Resetpass' );
120 if ( !$this->mUser
->isLoggedIn() ) {
121 $rememberMe = '<tr>' .
123 '<td class="mw-input">' .
124 Xml
::checkLabel( wfMsg( 'remembermypassword' ),
125 'wpRemember', 'wpRemember',
126 $wgRequest->getCheck( 'wpRemember' ) ) .
129 $submitMsg = 'resetpass_submit';
130 $oldpassMsg = 'resetpass-temp-password';
132 $oldpassMsg = 'oldpassword';
133 $submitMsg = 'resetpass-submit-loggedin';
135 $s = Xml
::fieldset( wfMsg( 'resetpass_header' ) ) .
136 Xml
::openElement( 'form',
139 'action' => $self->getLocalUrl(),
140 'id' => 'mw-resetpass-form' ) ) .
141 Xml
::hidden( 'token', $this->mUser
->editToken() ) .
142 Xml
::hidden( 'returnto', $wgRequest->getVal( 'returnto' ) ) .
143 wfMsgExt( 'resetpass_text', array( 'parse' ) ) .
144 Xml
::openElement( 'table', array( 'id' => 'mw-resetpass-table' ) );
145 $formElements = array(
146 array( 'wpName', 'username', 'text', $this->mUserName
, $this->mUser
->isAllowed( 'reset-passwords' ) ),
147 array( 'wpPassword', $oldpassMsg, 'password', $this->mOldpass
, $this->mSelfChange
),
148 array( 'wpNewPassword', 'newpassword', 'password', '', true ),
149 array( 'wpRetype', 'retypenew', 'password', '', true ) );
150 if ( $this->mUser
->isAllowed( 'reset-passwords' ) && $this->mSelfChange
)
151 $formElements[] = array( 'wpComment', 'resetpass-comment', 'text', $this->mComment
, true );
152 $s .= $this->pretty( $formElements ) .
156 '<td class="mw-input">' .
157 Xml
::submitButton( wfMsg( $submitMsg ) ) .
160 Xml
::closeElement( 'table' ) .
161 Xml
::closeElement( 'form' ) .
162 Xml
::closeElement( 'fieldset' );
163 $wgOut->addHtml( $s );
166 function pretty( $fields ) {
168 foreach( $fields as $list ) {
169 list( $name, $label, $type, $value, $enabled ) = $list;
170 $params = array( 'id' => $name, 'type' => $type );
172 $params['disabled'] = 'disabled';
173 $field = Xml
::input( $name, 20, $value, $params );
175 $out .= '<td class="mw-label">';
176 $out .= Xml
::label( wfMsg( $label ), $name );
178 $out .= '<td class="mw-input">';
187 * @throws PasswordError when cannot set the new password because requirements not met.
189 protected function attemptReset( $newpass, $retype ) {
190 $user = User
::newFromName( $this->mUserName
);
191 if( !$user ||
$user->isAnon() ) {
192 throw new PasswordError( 'no such user' );
195 if( $newpass !== $retype ) {
196 wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
197 throw new PasswordError( wfMsg( 'badretype' ) );
200 if ( $this->mSelfChange
) {
201 if( !$user->checkTemporaryPassword($this->mOldpass
) && !$user->checkPassword($this->mOldpass
) ) {
202 wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
203 throw new PasswordError( wfMsg( 'resetpass-wrong-oldpass' ) );
208 $user->setPassword( $this->mNewpass
);
209 wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
210 $this->mNewpass
= $this->mOldpass
= $this->mRetypePass
= '';
211 } catch( PasswordError
$e ) {
212 wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
213 throw new PasswordError( $e->getMessage() );
217 if ( !$this->mSelfChange
) {
218 $log = new LogPage( 'password' );
219 $log->addEntry( 'reset', $user->getUserPage(), $this->mComment
);
221 // Only set cookies if it was a self-change
225 $user->saveSettings();