62 private $userOptionsLookup;
80 if ( isset(
$params[
'emailEnabled'] ) ) {
81 $this->emailEnabled = (bool)
$params[
'emailEnabled'];
83 if ( isset(
$params[
'newPasswordExpiry'] ) ) {
84 $this->newPasswordExpiry = (int)
$params[
'newPasswordExpiry'];
86 if ( isset(
$params[
'passwordReminderResendTime'] ) ) {
87 $this->passwordReminderResendTime =
$params[
'passwordReminderResendTime'];
89 $this->dbProvider = $dbProvider;
90 $this->userOptionsLookup = $userOptionsLookup;
96 $this->passwordReminderResendTime ??=
103 'msg' =>
wfMessage(
'resetpass-temp-emailed' ),
122 isset( $options[
'username'] ) &&
123 !$this->userNameUtils->isTemp( $options[
'username'] ) &&
141 if ( !$req || $req->username ===
null || $req->password ===
null ) {
145 $username = $this->userNameUtils->getCanonical(
146 $req->username, UserRigorOptions::RIGOR_USABLE );
147 if ( $username ===
false ) {
151 $row = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
152 ->select( [
'user_id',
'user_newpassword',
'user_newpass_time' ] )
154 ->where( [
'user_name' => $username ] )
155 ->caller( __METHOD__ )->fetchRow();
161 if ( !$status->isOK() ) {
165 $pwhash = $this->
getPassword( $row->user_newpassword );
166 if ( !$pwhash->verify( $req->password ) ||
167 !$this->isTimestampValid( $row->user_newpass_time )
175 $this->logger->info(
"{user} successfully logged in using temp password",
178 'requestIP' => $this->manager->getRequest()->getIP()
188 $username = $this->userNameUtils->getCanonical( $username, UserRigorOptions::RIGOR_USABLE );
189 if ( $username ===
false ) {
193 $row = $this->dbProvider->getReplicaDatabase()->newSelectQueryBuilder()
194 ->select( [
'user_newpassword',
'user_newpass_time' ] )
196 ->where( [
'user_name' => $username ] )
197 ->caller( __METHOD__ )->fetchRow();
203 public function testUserExists( $username, $flags = IDBAccessObject::READ_NORMAL ) {
204 $username = $this->userNameUtils->getCanonical( $username, UserRigorOptions::RIGOR_USABLE );
205 if ( $username ===
false ) {
209 $db = \DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $flags );
210 return (
bool)$db->newSelectQueryBuilder()
211 ->select( [
'user_id' ] )
213 ->where( [
'user_name' => $username ] )
215 ->caller( __METHOD__ )->fetchField();
221 if ( get_class( $req ) !== TemporaryPasswordAuthenticationRequest::class ) {
223 return \StatusValue::newGood(
'ignored' );
227 return \StatusValue::newGood();
230 $username = $this->userNameUtils->getCanonical(
231 $req->username, UserRigorOptions::RIGOR_USABLE );
232 if ( $username ===
false ) {
233 return \StatusValue::newGood(
'ignored' );
236 $row = $this->dbProvider->getPrimaryDatabase()->newSelectQueryBuilder()
237 ->select( [
'user_id',
'user_newpass_time' ] )
239 ->where( [
'user_name' => $username ] )
240 ->caller( __METHOD__ )->fetchRow();
242 return \StatusValue::newGood(
'ignored' );
245 $sv = \StatusValue::newGood();
246 if ( $req->password !==
null ) {
249 if ( $req->mailpassword ) {
250 if ( !$this->emailEnabled ) {
251 return \StatusValue::newFatal(
'passwordreset-emaildisabled' );
260 $this->passwordReminderResendTime
261 && $row->user_newpass_time
262 && time() < (
int)
wfTimestamp( TS_UNIX, $row->user_newpass_time )
263 + $this->passwordReminderResendTime * 3600
267 return \StatusValue::newFatal(
'throttled-mailpassword',
268 round( $this->passwordReminderResendTime, 3 ) );
271 if ( !$req->caller ) {
272 return \StatusValue::newFatal(
'passwordreset-nocaller' );
274 if ( !IPUtils::isValid( $req->caller ) ) {
275 $caller = User::newFromName( $req->caller );
277 return \StatusValue::newFatal(
'passwordreset-nosuchcaller', $req->caller );
286 $username = $req->username !==
null ?
287 $this->userNameUtils->getCanonical( $req->username, UserRigorOptions::RIGOR_USABLE ) :
false;
288 if ( $username ===
false ) {
292 $dbw = $this->dbProvider->getPrimaryDatabase();
296 get_class( $req ) === TemporaryPasswordAuthenticationRequest::class
299 $newpassTime = $dbw->timestamp();
300 $sendMail = $req->mailpassword;
307 $dbw->newUpdateQueryBuilder()
310 'user_newpassword' => $pwhash->toString(),
311 'user_newpass_time' => $newpassTime,
313 ->where( [
'user_name' => $username ] )
314 ->caller( __METHOD__ )->execute();
318 $dbw->onTransactionCommitOrIdle(
319 function () use ( $req ) {
335 $reqs, TemporaryPasswordAuthenticationRequest::class
338 $ret = \StatusValue::newGood();
340 if ( $req->mailpassword ) {
341 if ( !$this->emailEnabled ) {
342 $ret->merge( \StatusValue::newFatal(
'emaildisabled' ) );
343 } elseif ( !$user->getEmail() ) {
344 $ret->merge( \StatusValue::newFatal(
'noemailcreate' ) );
358 $reqs, TemporaryPasswordAuthenticationRequest::class
360 if ( $req && $req->username !==
null && $req->password !==
null ) {
362 if ( $req->username !== $user->getName() ) {
364 $req->username = $user->getName();
367 if ( $req->mailpassword ) {
369 $this->manager->setAuthenticationSessionData(
'no-email',
true );
373 $ret->createRequest = $req;
381 $req = $res->createRequest;
382 $mailpassword = $req->mailpassword;
383 $req->mailpassword =
false;
388 if ( $mailpassword ) {
390 $this->dbProvider->getPrimaryDatabase()->onTransactionCommitOrIdle(
391 function () use ( $user, $creator, $req ) {
398 return $mailpassword ?
'byemail' :
null;
408 if ( $time !==
null ) {
410 if ( time() >= $expiry ) {
428 return \MediaWiki\Status\Status::newFatal(
'badipaddress' );
432 $this->
getHookRunner()->onUser__mailPasswordInternal( $creatingUser, $ip, $user );
434 $mainPageUrl = Title::newMainPage()->getCanonicalURL();
435 $userLanguage = $this->userOptionsLookup->getOption( $user,
'language' );
436 $subjectMessage =
wfMessage(
'createaccount-title' )->inLanguage( $userLanguage );
437 $bodyMessage =
wfMessage(
'createaccount-text', $ip, $user->
getName(), $password,
438 '<' . $mainPageUrl .
'>', round( $this->newPasswordExpiry / 86400 ) )
439 ->inLanguage( $userLanguage );
441 $status = $user->
sendMail( $subjectMessage->text(), $bodyMessage->text() );
445 if ( !$status->isGood() ) {
446 $this->logger->warning(
'Could not send account creation email: ' .
447 $status->getWikiText(
false,
false,
'en' ) );
459 $user = User::newFromName( $req->username );
461 return \MediaWiki\Status\Status::newFatal(
'noname' );
463 $userLanguage = $this->userOptionsLookup->getOption( $user,
'language' );
464 $callerIsAnon = IPUtils::isValid( $req->caller );
465 $callerName = $callerIsAnon ? $req->caller : User::newFromName( $req->caller )->getName();
466 $passwordMessage =
wfMessage(
'passwordreset-emailelement', $user->getName(),
467 $req->password )->inLanguage( $userLanguage );
468 $emailMessage =
wfMessage( $callerIsAnon ?
'passwordreset-emailtext-ip'
469 :
'passwordreset-emailtext-user' )->inLanguage( $userLanguage );
470 $body = $emailMessage->params( $callerName, $passwordMessage->text(), 1,
471 '<' . Title::newMainPage()->getCanonicalURL() .
'>',
472 round( $this->newPasswordExpiry / 86400 ) )->text();
474 if ( !$this->userOptionsLookup->getBoolOption( $user,
'requireemail' ) ) {
478 $body .=
wfMessage(
'passwordreset-emailtext-require-email' )
479 ->inLanguage( $userLanguage )
484 $emailTitle =
wfMessage(
'passwordreset-emailtitle' )->inLanguage( $userLanguage );
485 return $user->sendMail( $emailTitle->text(), $body );
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
array $params
The job parameters.
A class containing constants representing the names of configuration variables.
const PasswordReminderResendTime
Name constant for the PasswordReminderResendTime setting, for use with Config::get()
const EnableEmail
Name constant for the EnableEmail setting, for use with Config::get()
const NewPasswordExpiry
Name constant for the NewPasswordExpiry setting, for use with Config::get()
Parent class for all special pages.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Interface for database access objects.