Completed
Branch master (2b1da7)
by
unknown
23:13
created

SpecialPasswordReset   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 184
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Importance

Changes 0
Metric Value
dl 0
loc 184
rs 7.6254
c 0
b 0
f 0
wmc 39
lcom 1
cbo 15

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getPasswordReset() 0 6 2
A doesWrites() 0 3 1
A userCanExecute() 0 3 1
A checkExecutePermissions() 0 8 2
C getFormFields() 0 31 7
A getDisplayFormat() 0 3 1
B alterForm() 0 18 6
C onSubmit() 0 24 9
B onSuccess() 0 31 6
A isListed() 0 7 2
A getGroupName() 0 3 1
1
<?php
2
/**
3
 * Implements Special:PasswordReset
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
use MediaWiki\Auth\AuthManager;
25
26
/**
27
 * Special page for requesting a password reset email.
28
 *
29
 * Requires the TemporaryPasswordPrimaryAuthenticationProvider and the
30
 * EmailNotificationSecondaryAuthenticationProvider (or something providing equivalent
31
 * functionality) to be enabled.
32
 *
33
 * @ingroup SpecialPage
34
 */
35
class SpecialPasswordReset extends FormSpecialPage {
36
	/** @var PasswordReset */
37
	private $passwordReset = null;
38
39
	/**
40
	 * @var string[] Temporary storage for the passwords which have been sent out, keyed by username.
41
	 */
42
	private $passwords = [];
43
44
	/**
45
	 * @var Status
46
	 */
47
	private $result;
48
49
	/**
50
	 * @var string $method Identifies which password reset field was specified by the user.
51
	 */
52
	private $method;
53
54
	public function __construct() {
55
		parent::__construct( 'PasswordReset', 'editmyprivateinfo' );
56
	}
57
58
	private function getPasswordReset() {
59
		if ( $this->passwordReset === null ) {
60
			$this->passwordReset = new PasswordReset( $this->getConfig(), AuthManager::singleton() );
61
		}
62
		return $this->passwordReset;
63
	}
64
65
	public function doesWrites() {
66
		return true;
67
	}
68
69
	public function userCanExecute( User $user ) {
70
		return $this->getPasswordReset()->isAllowed( $user )->isGood();
71
	}
72
73
	public function checkExecutePermissions( User $user ) {
74
		$status = Status::wrap( $this->getPasswordReset()->isAllowed( $user ) );
75
		if ( !$status->isGood() ) {
76
			throw new ErrorPageError( 'internalerror', $status->getMessage() );
77
		}
78
79
		parent::checkExecutePermissions( $user );
80
	}
81
82
	protected function getFormFields() {
83
		$resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
84
		$a = [];
85
		if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) {
86
			$a['Username'] = [
87
				'type' => 'text',
88
				'label-message' => 'passwordreset-username',
89
			];
90
91
			if ( $this->getUser()->isLoggedIn() ) {
92
				$a['Username']['default'] = $this->getUser()->getName();
93
			}
94
		}
95
96
		if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) {
97
			$a['Email'] = [
98
				'type' => 'email',
99
				'label-message' => 'passwordreset-email',
100
			];
101
		}
102
103
		if ( $this->getUser()->isAllowed( 'passwordreset' ) ) {
104
			$a['Capture'] = [
105
				'type' => 'check',
106
				'label-message' => 'passwordreset-capture',
107
				'help-message' => 'passwordreset-capture-help',
108
			];
109
		}
110
111
		return $a;
112
	}
113
114
	protected function getDisplayFormat() {
115
		return 'ooui';
116
	}
117
118
	public function alterForm( HTMLForm $form ) {
119
		$resetRoutes = $this->getConfig()->get( 'PasswordResetRoutes' );
120
121
		$form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
122
123
		$i = 0;
124
		if ( isset( $resetRoutes['username'] ) && $resetRoutes['username'] ) {
125
			$i++;
126
		}
127
		if ( isset( $resetRoutes['email'] ) && $resetRoutes['email'] ) {
128
			$i++;
129
		}
130
131
		$message = ( $i > 1 ) ? 'passwordreset-text-many' : 'passwordreset-text-one';
132
133
		$form->setHeaderText( $this->msg( $message, $i )->parseAsBlock() );
134
		$form->setSubmitTextMsg( 'mailmypassword' );
135
	}
136
137
	/**
138
	 * Process the form.  At this point we know that the user passes all the criteria in
139
	 * userCanExecute(), and if the data array contains 'Username', etc, then Username
140
	 * resets are allowed.
141
	 * @param array $data
142
	 * @throws MWException
143
	 * @throws ThrottledError|PermissionsError
144
	 * @return Status
145
	 */
146
	public function onSubmit( array $data ) {
147
		if ( isset( $data['Capture'] ) && !$this->getUser()->isAllowed( 'passwordreset' ) ) {
148
			// The user knows they don't have the passwordreset permission,
149
			// but they tried to spoof the form. That's naughty
150
			throw new PermissionsError( 'passwordreset' );
151
		}
152
153
		$username = isset( $data['Username'] ) ? $data['Username'] : null;
154
		$email = isset( $data['Email'] ) ? $data['Email'] : null;
155
		$capture = !empty( $data['Capture'] );
156
157
		$this->method = $username ? 'username' : 'email';
158
		$this->result = Status::wrap(
159
			$this->getPasswordReset()->execute( $this->getUser(), $username, $email, $capture ) );
160
		if ( $capture && $this->result->isOK() ) {
161
			$this->passwords = $this->result->getValue();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->result->getValue() of type * is incompatible with the declared type array<integer,string> of property $passwords.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
162
		}
163
164
		if ( $this->result->hasMessage( 'actionthrottledtext' ) ) {
165
			throw new ThrottledError;
166
		}
167
168
		return $this->result;
169
	}
170
171
	public function onSuccess() {
172
		if ( $this->getUser()->isAllowed( 'passwordreset' ) && $this->passwords ) {
173
			// @todo Logging
174
175
			if ( $this->result->isGood() ) {
176
				$this->getOutput()->addWikiMsg( 'passwordreset-emailsent-capture2',
177
					count( $this->passwords ) );
178
			} else {
179
				$this->getOutput()->addWikiMsg( 'passwordreset-emailerror-capture2',
180
					$this->result->getMessage(), key( $this->passwords ), count( $this->passwords ) );
181
			}
182
183
			$this->getOutput()->addHTML( Html::openElement( 'ul' ) );
184
			foreach ( $this->passwords as $username => $pwd ) {
185
				$this->getOutput()->addHTML( Html::rawElement( 'li', [],
186
					htmlspecialchars( $username, ENT_QUOTES )
187
					. $this->msg( 'colon-separator' )->text()
188
					. htmlspecialchars( $pwd, ENT_QUOTES )
189
				) );
190
			}
191
			$this->getOutput()->addHTML( Html::closeElement( 'ul' ) );
192
		}
193
194
		if ( $this->method === 'email' ) {
195
			$this->getOutput()->addWikiMsg( 'passwordreset-emailsentemail' );
196
		} else {
197
			$this->getOutput()->addWikiMsg( 'passwordreset-emailsentusername' );
198
		}
199
200
		$this->getOutput()->returnToMain();
201
	}
202
203
	/**
204
	 * Hide the password reset page if resets are disabled.
205
	 * @return bool
206
	 */
207
	public function isListed() {
208
		if ( $this->getPasswordReset()->isAllowed( $this->getUser() )->isGood() ) {
209
			return parent::isListed();
210
		}
211
212
		return false;
213
	}
214
215
	protected function getGroupName() {
216
		return 'users';
217
	}
218
}
219