Completed
Branch master (1b8556)
by
unknown
26:56
created

TemporaryPasswordPrimaryAuthenticationProvider   F

Complexity

Total Complexity 79

Size/Duplication

Total Lines 418
Duplicated Lines 7.89 %

Coupling/Cohesion

Components 2
Dependencies 20

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 33
loc 418
rs 2.0547
wmc 79
lcom 2
cbo 20

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 4
A setConfig() 0 13 4
A getPasswordResetData() 0 7 1
C getAuthenticationRequests() 0 25 7
D beginPrimaryAuthentication() 0 43 9
B testUserCanAuthenticate() 0 27 5
A testUserExists() 15 15 2
C providerAllowsAuthenticationDataChange() 0 67 15
B providerChangeAuthenticationData() 0 35 6
A accountCreationType() 0 3 1
B testForAccountCreation() 0 22 6
B beginPrimaryAccountCreation() 18 25 6
A finishAccountCreation() 0 15 3
A isTimestampValid() 0 10 3
B sendNewAccountEmail() 0 29 3
A sendPasswordResetEmail() 0 18 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like TemporaryPasswordPrimaryAuthenticationProvider often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TemporaryPasswordPrimaryAuthenticationProvider, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * This program is free software; you can redistribute it and/or modify
4
 * it under the terms of the GNU General Public License as published by
5
 * the Free Software Foundation; either version 2 of the License, or
6
 * (at your option) any later version.
7
 *
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
 * GNU General Public License for more details.
12
 *
13
 * You should have received a copy of the GNU General Public License along
14
 * with this program; if not, write to the Free Software Foundation, Inc.,
15
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
 * http://www.gnu.org/copyleft/gpl.html
17
 *
18
 * @file
19
 * @ingroup Auth
20
 */
21
22
namespace MediaWiki\Auth;
23
24
use User;
25
26
/**
27
 * A primary authentication provider that uses the temporary password field in
28
 * the 'user' table.
29
 *
30
 * A successful login will force a password reset.
31
 *
32
 * @note For proper operation, this should generally come before any other
33
 *  password-based authentication providers.
34
 * @ingroup Auth
35
 * @since 1.27
36
 */
37
class TemporaryPasswordPrimaryAuthenticationProvider
38
	extends AbstractPasswordPrimaryAuthenticationProvider
0 ignored issues
show
Coding Style introduced by
The extends keyword must be on the same line as the class name
Loading history...
39
{
40
	/** @var bool */
41
	protected $emailEnabled = null;
42
43
	/** @var int */
44
	protected $newPasswordExpiry = null;
45
46
	/** @var int */
47
	protected $passwordReminderResendTime = null;
48
49
	/**
50
	 * @param array $params
51
	 *  - emailEnabled: (bool) must be true for the option to email passwords to be present
52
	 *  - newPasswordExpiry: (int) expiraton time of temporary passwords, in seconds
53
	 *  - passwordReminderResendTime: (int) cooldown period in hours until a password reminder can
54
	 *    be sent to the same user again,
55
	 */
56
	public function __construct( $params = [] ) {
57
		parent::__construct( $params );
58
59
		if ( isset( $params['emailEnabled'] ) ) {
60
			$this->emailEnabled = (bool)$params['emailEnabled'];
61
		}
62
		if ( isset( $params['newPasswordExpiry'] ) ) {
63
			$this->newPasswordExpiry = (int)$params['newPasswordExpiry'];
64
		}
65
		if ( isset( $params['passwordReminderResendTime'] ) ) {
66
			$this->passwordReminderResendTime = $params['passwordReminderResendTime'];
67
		}
68
	}
69
70
	public function setConfig( \Config $config ) {
71
		parent::setConfig( $config );
72
73
		if ( $this->emailEnabled === null ) {
74
			$this->emailEnabled = $this->config->get( 'EnableEmail' );
75
		}
76
		if ( $this->newPasswordExpiry === null ) {
77
			$this->newPasswordExpiry = $this->config->get( 'NewPasswordExpiry' );
78
		}
79
		if ( $this->passwordReminderResendTime === null ) {
80
			$this->passwordReminderResendTime = $this->config->get( 'PasswordReminderResendTime' );
81
		}
82
	}
83
84
	protected function getPasswordResetData( $username, $data ) {
85
		// Always reset
86
		return (object)[
87
			'msg' => wfMessage( 'resetpass-temp-emailed' ),
88
			'hard' => true,
89
		];
90
	}
91
92
	public function getAuthenticationRequests( $action, array $options ) {
93
		switch ( $action ) {
94
			case AuthManager::ACTION_LOGIN:
95
				return [ new PasswordAuthenticationRequest() ];
96
97
			case AuthManager::ACTION_CHANGE:
98
				return [ TemporaryPasswordAuthenticationRequest::newRandom() ];
99
100
			case AuthManager::ACTION_CREATE:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
101
				if ( isset( $options['username'] ) && $this->emailEnabled ) {
102
					// Creating an account for someone else
103
					return [ TemporaryPasswordAuthenticationRequest::newRandom() ];
104
				} else {
105
					// It's not terribly likely that an anonymous user will
106
					// be creating an account for someone else.
107
					return [];
108
				}
109
110
			case AuthManager::ACTION_REMOVE:
111
				return [ new TemporaryPasswordAuthenticationRequest ];
112
113
			default:
114
				return [];
115
		}
116
	}
117
118
	public function beginPrimaryAuthentication( array $reqs ) {
119
		$req = AuthenticationRequest::getRequestByClass( $reqs, PasswordAuthenticationRequest::class );
120
		if ( !$req || $req->username === null || $req->password === null ) {
0 ignored issues
show
Bug introduced by
The property password does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
121
			return AuthenticationResponse::newAbstain();
122
		}
123
124
		$username = User::getCanonicalName( $req->username, 'usable' );
125
		if ( $username === false ) {
126
			return AuthenticationResponse::newAbstain();
127
		}
128
129
		$dbw = wfGetDB( DB_MASTER );
130
		$row = $dbw->selectRow(
131
			'user',
132
			[
133
				'user_id', 'user_newpassword', 'user_newpass_time',
134
			],
135
			[ 'user_name' => $username ],
136
			__METHOD__
137
		);
138
		if ( !$row ) {
139
			return AuthenticationResponse::newAbstain();
140
		}
141
142
		$status = $this->checkPasswordValidity( $username, $req->password );
0 ignored issues
show
Bug introduced by
It seems like $username defined by \User::getCanonicalName($req->username, 'usable') on line 124 can also be of type boolean; however, MediaWiki\Auth\AbstractP...checkPasswordValidity() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
143
		if ( !$status->isOk() ) {
144
			// Fatal, can't log in
145
			return AuthenticationResponse::newFail( $status->getMessage() );
146
		}
147
148
		$pwhash = $this->getPassword( $row->user_newpassword );
149
		if ( !$pwhash->equals( $req->password ) ) {
150
			return $this->failResponse( $req );
0 ignored issues
show
Compatibility introduced by
$req of type object<MediaWiki\Auth\AuthenticationRequest> is not a sub-type of object<MediaWiki\Auth\Pa...dAuthenticationRequest>. It seems like you assume a child class of the class MediaWiki\Auth\AuthenticationRequest to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
151
		}
152
153
		if ( !$this->isTimestampValid( $row->user_newpass_time ) ) {
154
			return $this->failResponse( $req );
0 ignored issues
show
Compatibility introduced by
$req of type object<MediaWiki\Auth\AuthenticationRequest> is not a sub-type of object<MediaWiki\Auth\Pa...dAuthenticationRequest>. It seems like you assume a child class of the class MediaWiki\Auth\AuthenticationRequest to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
155
		}
156
157
		$this->setPasswordResetFlag( $username, $status );
0 ignored issues
show
Bug introduced by
It seems like $username defined by \User::getCanonicalName($req->username, 'usable') on line 124 can also be of type boolean; however, MediaWiki\Auth\AbstractP...:setPasswordResetFlag() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
158
159
		return AuthenticationResponse::newPass( $username );
0 ignored issues
show
Bug introduced by
It seems like $username defined by \User::getCanonicalName($req->username, 'usable') on line 124 can also be of type boolean; however, MediaWiki\Auth\AuthenticationResponse::newPass() does only seem to accept string|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
160
	}
161
162
	public function testUserCanAuthenticate( $username ) {
163
		$username = User::getCanonicalName( $username, 'usable' );
164
		if ( $username === false ) {
165
			return false;
166
		}
167
168
		$dbw = wfGetDB( DB_MASTER );
169
		$row = $dbw->selectRow(
170
			'user',
171
			[ 'user_newpassword', 'user_newpass_time' ],
172
			[ 'user_name' => $username ],
173
			__METHOD__
174
		);
175
		if ( !$row ) {
176
			return false;
177
		}
178
179
		if ( $this->getPassword( $row->user_newpassword ) instanceof \InvalidPassword ) {
180
			return false;
181
		}
182
183
		if ( !$this->isTimestampValid( $row->user_newpass_time ) ) {
184
			return false;
185
		}
186
187
		return true;
188
	}
189
190 View Code Duplication
	public function testUserExists( $username, $flags = User::READ_NORMAL ) {
191
		$username = User::getCanonicalName( $username, 'usable' );
192
		if ( $username === false ) {
193
			return false;
194
		}
195
196
		list( $db, $options ) = \DBAccessObjectUtils::getDBOptions( $flags );
197
		return (bool)wfGetDB( $db )->selectField(
198
			[ 'user' ],
199
			[ 'user_id' ],
200
			[ 'user_name' => $username ],
201
			__METHOD__,
202
			$options
203
		);
204
	}
205
206
	public function providerAllowsAuthenticationDataChange(
207
		AuthenticationRequest $req, $checkData = true
208
	) {
209
		if ( get_class( $req ) !== TemporaryPasswordAuthenticationRequest::class ) {
210
			// We don't really ignore it, but this is what the caller expects.
211
			return \StatusValue::newGood( 'ignored' );
212
		}
213
214
		if ( !$checkData ) {
215
			return \StatusValue::newGood();
216
		}
217
218
		$username = User::getCanonicalName( $req->username, 'usable' );
219
		if ( $username === false ) {
220
			return \StatusValue::newGood( 'ignored' );
221
		}
222
223
		$row = wfGetDB( DB_MASTER )->selectRow(
224
			'user',
225
			[ 'user_id', 'user_newpass_time' ],
226
			[ 'user_name' => $username ],
227
			__METHOD__
228
		);
229
230
		if ( !$row ) {
231
			return \StatusValue::newGood( 'ignored' );
232
		}
233
234
		$sv = \StatusValue::newGood();
235
		if ( $req->password !== null ) {
236
			$sv->merge( $this->checkPasswordValidity( $username, $req->password ) );
0 ignored issues
show
Bug introduced by
The property password does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
It seems like $username defined by \User::getCanonicalName($req->username, 'usable') on line 218 can also be of type boolean; however, MediaWiki\Auth\AbstractP...checkPasswordValidity() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
237
238
			if ( $req->mailpassword ) {
0 ignored issues
show
Bug introduced by
The property mailpassword does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
239
				if ( !$this->emailEnabled && !$req->hasBackchannel ) {
0 ignored issues
show
Bug introduced by
The property hasBackchannel does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
240
					return \StatusValue::newFatal( 'passwordreset-emaildisabled' );
241
				}
242
243
				// We don't check whether the user has an email address;
244
				// that information should not be exposed to the caller.
245
246
				// do not allow temporary password creation within
247
				// $wgPasswordReminderResendTime from the last attempt
248
				if (
249
					$this->passwordReminderResendTime
250
					&& $row->user_newpass_time
251
					&& time() < wfTimestamp( TS_UNIX, $row->user_newpass_time )
252
						+ $this->passwordReminderResendTime * 3600
253
				) {
254
					// Round the time in hours to 3 d.p., in case someone is specifying
255
					// minutes or seconds.
256
					return \StatusValue::newFatal( 'throttled-mailpassword',
257
						round( $this->passwordReminderResendTime, 3 ) );
258
				}
259
260
				if ( !$req->caller ) {
0 ignored issues
show
Bug introduced by
The property caller does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
261
					return \StatusValue::newFatal( 'passwordreset-nocaller' );
262
				}
263
				if ( !\IP::isValid( $req->caller ) ) {
264
					$caller = User::newFromName( $req->caller );
265
					if ( !$caller ) {
266
						return \StatusValue::newFatal( 'passwordreset-nosuchcaller', $req->caller );
267
					}
268
				}
269
			}
270
		}
271
		return $sv;
272
	}
273
274
	public function providerChangeAuthenticationData( AuthenticationRequest $req ) {
275
		$username = $req->username !== null ? User::getCanonicalName( $req->username, 'usable' ) : false;
276
		if ( $username === false ) {
277
			return;
278
		}
279
280
		$dbw = wfGetDB( DB_MASTER );
281
282
		$sendMail = false;
283
		if ( $req->action !== AuthManager::ACTION_REMOVE &&
284
			get_class( $req ) === TemporaryPasswordAuthenticationRequest::class
285
		) {
286
			$pwhash = $this->getPasswordFactory()->newFromPlaintext( $req->password );
0 ignored issues
show
Bug introduced by
The property password does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
287
			$newpassTime = $dbw->timestamp();
288
			$sendMail = $req->mailpassword;
0 ignored issues
show
Bug introduced by
The property mailpassword does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
289
		} else {
290
			// Invalidate the temporary password when any other auth is reset, or when removing
291
			$pwhash = $this->getPasswordFactory()->newFromCiphertext( null );
292
			$newpassTime = null;
293
		}
294
295
		$dbw->update(
296
			'user',
297
			[
298
				'user_newpassword' => $pwhash->toString(),
299
				'user_newpass_time' => $newpassTime,
300
			],
301
			[ 'user_name' => $username ],
302
			__METHOD__
303
		);
304
305
		if ( $sendMail ) {
306
			$this->sendPasswordResetEmail( $req );
0 ignored issues
show
Compatibility introduced by
$req of type object<MediaWiki\Auth\AuthenticationRequest> is not a sub-type of object<MediaWiki\Auth\Te...dAuthenticationRequest>. It seems like you assume a child class of the class MediaWiki\Auth\AuthenticationRequest to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
307
		}
308
	}
309
310
	public function accountCreationType() {
311
		return self::TYPE_CREATE;
312
	}
313
314
	public function testForAccountCreation( $user, $creator, array $reqs ) {
315
		/** @var TemporaryPasswordAuthenticationRequest $req */
316
		$req = AuthenticationRequest::getRequestByClass(
317
			$reqs, TemporaryPasswordAuthenticationRequest::class
318
		);
319
320
		$ret = \StatusValue::newGood();
321
		if ( $req ) {
322
			if ( $req->mailpassword && !$req->hasBackchannel ) {
323
				if ( !$this->emailEnabled ) {
324
					$ret->merge( \StatusValue::newFatal( 'emaildisabled' ) );
325
				} elseif ( !$user->getEmail() ) {
326
					$ret->merge( \StatusValue::newFatal( 'noemailcreate' ) );
327
				}
328
			}
329
330
			$ret->merge(
331
				$this->checkPasswordValidity( $user->getName(), $req->password )
332
			);
333
		}
334
		return $ret;
335
	}
336
337
	public function beginPrimaryAccountCreation( $user, $creator, array $reqs ) {
338
		/** @var TemporaryPasswordAuthenticationRequest $req */
339
		$req = AuthenticationRequest::getRequestByClass(
340
			$reqs, TemporaryPasswordAuthenticationRequest::class
341
		);
342 View Code Duplication
		if ( $req ) {
343
			if ( $req->username !== null && $req->password !== null ) {
344
				// Nothing we can do yet, because the user isn't in the DB yet
345
				if ( $req->username !== $user->getName() ) {
346
					$req = clone( $req );
347
					$req->username = $user->getName();
348
				}
349
350
				if ( $req->mailpassword ) {
351
					// prevent EmailNotificationSecondaryAuthenticationProvider from sending another mail
352
					$this->manager->setAuthenticationSessionData( 'no-email', true );
353
				}
354
355
				$ret = AuthenticationResponse::newPass( $req->username );
356
				$ret->createRequest = $req;
357
				return $ret;
358
			}
359
		}
360
		return AuthenticationResponse::newAbstain();
361
	}
362
363
	public function finishAccountCreation( $user, $creator, AuthenticationResponse $res ) {
364
		/** @var TemporaryPasswordAuthenticationRequest $req */
365
		$req = $res->createRequest;
366
		$mailpassword = $req->mailpassword;
367
		$req->mailpassword = false; // providerChangeAuthenticationData would send the wrong email
368
369
		// Now that the user is in the DB, set the password on it.
370
		$this->providerChangeAuthenticationData( $req );
371
372
		if ( $mailpassword ) {
373
			$this->sendNewAccountEmail( $user, $creator, $req->password );
374
		}
375
376
		return $mailpassword ? 'byemail' : null;
377
	}
378
379
	/**
380
	 * Check that a temporary password is still valid (hasn't expired).
381
	 * @param string $timestamp A timestamp in MediaWiki (TS_MW) format
382
	 * @return bool
383
	 */
384
	protected function isTimestampValid( $timestamp ) {
385
		$time = wfTimestampOrNull( TS_MW, $timestamp );
386
		if ( $time !== null ) {
387
			$expiry = wfTimestamp( TS_UNIX, $time ) + $this->newPasswordExpiry;
388
			if ( time() >= $expiry ) {
389
				return false;
390
			}
391
		}
392
		return true;
393
	}
394
395
	/**
396
	 * Send an email about the new account creation and the temporary password.
397
	 * @param User $user The new user account
398
	 * @param User $creatingUser The user who created the account (can be anonymous)
399
	 * @param string $password The temporary password
400
	 * @return \Status
401
	 */
402
	protected function sendNewAccountEmail( User $user, User $creatingUser, $password ) {
403
		$ip = $creatingUser->getRequest()->getIP();
404
		// @codeCoverageIgnoreStart
405
		if ( !$ip ) {
406
			return \Status::newFatal( 'badipaddress' );
407
		}
408
		// @codeCoverageIgnoreEnd
409
410
		\Hooks::run( 'User::mailPasswordInternal', [ &$creatingUser, &$ip, &$user ] );
411
412
		$mainPageUrl = \Title::newMainPage()->getCanonicalURL();
413
		$userLanguage = $user->getOption( 'language' );
414
		$subjectMessage = wfMessage( 'createaccount-title' )->inLanguage( $userLanguage );
415
		$bodyMessage = wfMessage( 'createaccount-text', $ip, $user->getName(), $password,
416
			'<' . $mainPageUrl . '>', round( $this->newPasswordExpiry / 86400 ) )
417
			->inLanguage( $userLanguage );
418
419
		$status = $user->sendMail( $subjectMessage->text(), $bodyMessage->text() );
420
421
		// TODO show 'mailerror' message on error, 'accmailtext' success message otherwise?
422
		// @codeCoverageIgnoreStart
423
		if ( !$status->isGood() ) {
424
			$this->logger->warning( 'Could not send account creation email: ' .
425
				$status->getWikiText( false, false, 'en' ) );
426
		}
427
		// @codeCoverageIgnoreEnd
428
429
		return $status;
430
	}
431
432
	/**
433
	 * @param TemporaryPasswordAuthenticationRequest $req
434
	 * @return \Status
435
	 */
436
	protected function sendPasswordResetEmail( TemporaryPasswordAuthenticationRequest $req ) {
437
			$user = User::newFromName( $req->username );
438
			if ( !$user ) {
439
				return \Status::newFatal( 'noname' );
440
			}
441
			$userLanguage = $user->getOption( 'language' );
442
			$callerIsAnon = \IP::isValid( $req->caller );
443
			$callerName = $callerIsAnon ? $req->caller : User::newFromName( $req->caller )->getName();
444
			$passwordMessage = wfMessage( 'passwordreset-emailelement', $user->getName(),
445
				$req->password )->inLanguage( $userLanguage );
446
			$emailMessage = wfMessage( $callerIsAnon ? 'passwordreset-emailtext-ip'
447
				: 'passwordreset-emailtext-user' )->inLanguage( $userLanguage );
448
			$emailMessage->params( $callerName, $passwordMessage->text(), 1,
449
				'<' . \Title::newMainPage()->getCanonicalURL() . '>',
450
				round( $this->newPasswordExpiry / 86400 ) );
451
			$emailTitle = wfMessage( 'passwordreset-emailtitle' )->inLanguage( $userLanguage );
452
			return $user->sendMail( $emailTitle->text(), $emailMessage->text() );
453
	}
454
}
455