148 User $performingUser,
152 if ( !$this->isAllowed( $performingUser )->isGood() ) {
153 throw new LogicException(
154 'User ' . $performingUser->
getName() .
' is not allowed to reset passwords'
160 if ( $performingUser->
pingLimiter(
'mailpassword' ) ) {
161 return StatusValue::newGood();
168 return StatusValue::newFatal(
'badipaddress' );
171 $resetRoutes = $this->config->get( MainConfigNames::PasswordResetRoutes )
172 + [
'username' =>
false,
'email' => false ];
173 if ( !$resetRoutes[
'username'] || $username ===
'' ) {
176 if ( !$resetRoutes[
'email'] || $email ===
'' ) {
180 if ( $username !==
null && !$this->userNameUtils->getCanonical( $username ) ) {
181 return StatusValue::newFatal(
'noname' );
183 if ( $email !==
null && !Sanitizer::validateEmail( $email ) ) {
184 return StatusValue::newFatal(
'passwordreset-invalidemail' );
191 if ( $username !==
null ) {
192 $user = $this->userFactory->newFromName( $username );
194 if ( $user && $user->isRegistered() && $user->getEmail() && (
195 !$this->userOptionsLookup->getBoolOption( $user,
'requireemail' ) ||
196 $user->getEmail() === $email
203 } elseif ( $email !==
null ) {
204 foreach ( $this->getUsersByEmail( $email ) as $userIdent ) {
206 if ( $this->userOptionsLookup->getBoolOption( $userIdent,
'requireemail' ) ) {
209 $users[] = $this->userFactory->newFromUserIdentity( $userIdent );
214 return StatusValue::newFatal(
'passwordreset-nodata' );
219 'Username' => $username,
224 if ( !$this->hookRunner->onSpecialPasswordResetOnSubmit( $users, $data, $error ) ) {
225 return StatusValue::newFatal( Message::newFromSpecifier( $error ) );
230 return StatusValue::newGood();
235 $firstUser = reset( $users );
237 $this->hookRunner->onUser__mailPasswordInternal( $performingUser, $ip, $firstUser );
239 $result = StatusValue::newGood();
241 foreach ( $users as $user ) {
242 $req = TemporaryPasswordAuthenticationRequest::newRandom();
243 $req->username = $user->getName();
244 $req->mailpassword =
true;
245 $req->caller = $performingUser->
getName();
247 $status = $this->authManager->allowsAuthenticationDataChange( $req,
true );
251 if ( $status->isGood() && $status->getValue() ===
'throttled-mailpassword' ) {
252 return StatusValue::newGood();
255 if ( $status->isGood() && $status->getValue() !==
'ignored' ) {
257 } elseif ( $result->isGood() ) {
260 if ( $status->getValue() ===
'ignored' ) {
261 $status = StatusValue::newFatal(
'passwordreset-ignored' );
263 $result->merge( $status );
268 'requestingIp' => $ip,
269 'requestingUser' => $performingUser->
getName(),
270 'targetUsername' => $username,
271 'targetEmail' => $email,
272 ] + $performingUser->
getRequest()->getSecurityLogContext();
274 if ( !$result->isGood() ) {
276 "{requestingUser} attempted password reset of {targetUsername} but failed",
277 $logContext + [
'errors' => $result->getErrors() ]
282 DeferredUpdates::addUpdate(
284 DeferredUpdates::POSTSEND
287 return StatusValue::newGood();