36 use Psr\Log\LoggerAwareInterface;
37 use Psr\Log\LoggerAwareTrait;
38 use Psr\Log\LoggerInterface;
69 private $userNameUtils;
72 private $userOptionsLookup;
79 private $permissionCache;
104 LoggerInterface $logger,
114 $this->config = $config;
115 $this->logger = $logger;
117 $this->authManager = $authManager;
118 $this->hookRunner =
new HookRunner( $hookContainer );
119 $this->dbProvider = $dbProvider;
120 $this->userFactory = $userFactory;
121 $this->userNameUtils = $userNameUtils;
122 $this->userOptionsLookup = $userOptionsLookup;
134 return $this->permissionCache->getWithSetCallback(
136 function () use ( $user ) {
137 return $this->computeIsAllowed( $user );
147 $resetRoutes = $this->config->get(
MainConfigNames::PasswordResetRoutes );
150 if ( !is_array( $resetRoutes ) || !in_array(
true, $resetRoutes,
true ) ) {
154 ( $providerStatus = $this->authManager->allowsAuthenticationDataChange(
155 new TemporaryPasswordAuthenticationRequest(),
false ) )
156 && !$providerStatus->isGood()
160 $providerStatus->getMessage() );
164 } elseif ( !$user->
isAllowed(
'editmyprivateinfo' ) ) {
167 } elseif ( $this->isBlocked( $user ) ) {
190 User $performingUser,
194 if ( !$this->isAllowed( $performingUser )->isGood() ) {
195 throw new LogicException(
196 'User ' . $performingUser->
getName() .
' is not allowed to reset passwords'
202 if ( $performingUser->
pingLimiter(
'mailpassword' ) ) {
217 + [
'username' =>
false,
'email' => false ];
218 if ( $resetRoutes[
'username'] && $username ) {
219 $method =
'username';
220 $users = [ $this->userFactory->newFromName( $username ) ];
221 } elseif ( $resetRoutes[
'email'] && $email ) {
228 $users = $this->getUsersByEmail( $email );
232 $optionsLookup = $this->userOptionsLookup;
233 foreach ( $users as $index => $user ) {
234 if ( $optionsLookup->getBoolOption( $user,
'requireemail' ) ) {
235 unset( $users[$index] );
245 if ( $username && !$this->userNameUtils->getCanonical( $username ) ) {
252 'Username' => $username,
254 'Email' => $method ===
'email' ? $email :
null,
260 $users = array_values( $users );
262 if ( !$this->hookRunner->onSpecialPasswordResetOnSubmit( $users, $data, $error ) ) {
268 $firstUser = reset( $users );
271 && $method ===
'username'
273 && $this->userOptionsLookup->getBoolOption( $firstUser,
'requireemail' );
280 if ( $method ===
'email' ) {
292 if ( !$firstUser instanceof
User || !$firstUser->
getId() || !$firstUser->getEmail() ) {
297 if ( $requireEmail && $firstUser->getEmail() !== $email ) {
301 $this->hookRunner->onUser__mailPasswordInternal( $performingUser, $ip, $firstUser );
305 foreach ( $users as $user ) {
307 $req->username = $user->getName();
308 $req->mailpassword =
true;
309 $req->caller = $performingUser->
getName();
311 $status = $this->authManager->allowsAuthenticationDataChange( $req,
true );
315 if ( $status->isGood() && $status->getValue() ===
'throttled-mailpassword' ) {
319 if ( $status->isGood() && $status->getValue() !==
'ignored' ) {
321 } elseif ( $result->isGood() ) {
324 if ( $status->getValue() ===
'ignored' ) {
327 $result->merge( $status );
332 'requestingIp' => $ip,
333 'requestingUser' => $performingUser->
getName(),
334 'targetUsername' => $username,
335 'targetEmail' => $email,
338 if ( !$result->isGood() ) {
340 "{requestingUser} attempted password reset of {actualUser} but failed",
341 $logContext + [
'errors' => $result->getErrors() ]
348 DeferredUpdates::POSTSEND
361 private function isBlocked(
User $user ) {
363 return $block && $block->appliesToPasswordReset();
373 $res = User::newQueryBuilder( $this->dbProvider->getReplicaDatabase() )
374 ->where( [
'user_email' => $email ] )
375 ->caller( __METHOD__ )
379 foreach ( $res as $row ) {
380 $users[] = $this->userFactory->newFromRow( $row );
391 class_alias( PasswordReset::class,
'PasswordReset' );
Defer callable updates to run later in the PHP process.
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the pending update queue for execution at the appropriate time.
Store key-value entries in a size-limited in-memory LRU cache.
A class containing constants representing the names of configuration variables.
const EnableEmail
Name constant for the EnableEmail setting, for use with Config::get()
const PasswordResetRoutes
Name constant for the PasswordResetRoutes setting, for use with Config::get()
const AllowRequiringEmailForResets
Name constant for the AllowRequiringEmailForResets setting, for use with Config::get()
The Message class deals with fetching and processing of interface message into a variety of formats.
static newFromSpecifier( $value)
Transform a MessageSpecifier or a primitive value used interchangeably with specifiers (a message key...
Sends emails to all accounts associated with that email to reset the password.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
static newFatal( $message,... $parameters)
Factory function for fatal errors.
static newGood( $value=null)
Factory function for good results.