X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fuser%2FPasswordReset.php;h=4ee256c495bf84f77cdf216daddead8c46c3a5b9;hb=7babd362babcbf7f20adb8e12edb4f4bc1d4249f;hp=bceb8652ef22d8dfcb235f51e20a88014bb4bf4c;hpb=cf5c36ccfd8dce53ea8d3631b1902050e93d4acd;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/user/PasswordReset.php b/includes/user/PasswordReset.php index bceb8652ef..faf09eefef 100644 --- a/includes/user/PasswordReset.php +++ b/includes/user/PasswordReset.php @@ -44,8 +44,8 @@ class PasswordReset implements LoggerAwareInterface { protected $logger; /** - * In-process cache for isAllowed lookups, by username. Contains pairs of StatusValue objects - * (for false and true value of $displayPassword, respectively). + * In-process cache for isAllowed lookups, by username. + * Contains a StatusValue object * @var HashBagOStuff */ private $permissionCache; @@ -72,13 +72,12 @@ class PasswordReset implements LoggerAwareInterface { * @param User $user * @param bool $displayPassword If set, also check whether the user is allowed to reset the * password of another user and see the temporary password. + * @since 1.29 Second argument for displayPassword removed. * @return StatusValue */ - public function isAllowed( User $user, $displayPassword = false ) { - $statuses = $this->permissionCache->get( $user->getName() ); - if ( $statuses ) { - list ( $status, $status2 ) = $statuses; - } else { + public function isAllowed( User $user ) { + $status = $this->permissionCache->get( $user->getName() ); + if ( !$status ) { $resetRoutes = $this->config->get( 'PasswordResetRoutes' ); $status = StatusValue::newGood(); @@ -101,25 +100,17 @@ class PasswordReset implements LoggerAwareInterface { } elseif ( !$user->isAllowed( 'editmyprivateinfo' ) ) { // Maybe not all users have permission to change private data $status = StatusValue::newFatal( 'badaccess' ); - } elseif ( $user->isBlocked() ) { + } elseif ( $this->isBlocked( $user ) ) { // Maybe the user is blocked (check this here rather than relying on the parent - // method as we have a more specific error message to use here + // method as we have a more specific error message to use here and we want to + // ignore some types of blocks) $status = StatusValue::newFatal( 'blocked-mailpassword' ); } - $status2 = StatusValue::newGood(); - if ( !$user->isAllowed( 'passwordreset' ) ) { - $status2 = StatusValue::newFatal( 'badaccess' ); - } - - $this->permissionCache->set( $user->getName(), [ $status, $status2 ] ); + $this->permissionCache->set( $user->getName(), $status ); } - if ( !$displayPassword || !$status->isGood() ) { - return $status; - } else { - return $status2; - } + return $status; } /** @@ -128,22 +119,22 @@ class PasswordReset implements LoggerAwareInterface { * Process the form. At this point we know that the user passes all the criteria in * userCanExecute(), and if the data array contains 'Username', etc, then Username * resets are allowed. + * + * @since 1.29 Fourth argument for displayPassword removed. * @param User $performingUser The user that does the password reset * @param string $username The user whose password is reset * @param string $email Alternative way to specify the user - * @param bool $displayPassword Whether to display the password * @return StatusValue Will contain the passwords as a username => password array if the * $displayPassword flag was set * @throws LogicException When the user is not allowed to perform the action * @throws MWException On unexpected DB errors */ public function execute( - User $performingUser, $username = null, $email = null, $displayPassword = false + User $performingUser, $username = null, $email = null ) { - if ( !$this->isAllowed( $performingUser, $displayPassword )->isGood() ) { - $action = $this->isAllowed( $performingUser )->isGood() ? 'display' : 'reset'; + if ( !$this->isAllowed( $performingUser )->isGood() ) { throw new LogicException( 'User ' . $performingUser->getName() - . ' is not allowed to ' . $action . ' passwords' ); + . ' is not allowed to reset passwords' ); } $resetRoutes = $this->config->get( 'PasswordResetRoutes' ) @@ -151,12 +142,14 @@ class PasswordReset implements LoggerAwareInterface { if ( $resetRoutes['username'] && $username ) { $method = 'username'; $users = [ User::newFromName( $username ) ]; + $email = null; } elseif ( $resetRoutes['email'] && $email ) { if ( !Sanitizer::validateEmail( $email ) ) { return StatusValue::newFatal( 'passwordreset-invalidemail' ); } $method = 'email'; $users = $this->getUsersByEmail( $email ); + $username = null; } else { // The user didn't supply any data return StatusValue::newFatal( 'passwordreset-nodata' ); @@ -167,7 +160,6 @@ class PasswordReset implements LoggerAwareInterface { $data = [ 'Username' => $username, 'Email' => $email, - 'Capture' => $displayPassword ? '1' : null, ]; if ( !Hooks::run( 'SpecialPasswordResetOnSubmit', [ &$users, $data, &$error ] ) ) { return StatusValue::newFatal( Message::newFromSpecifier( $error ) ); @@ -185,7 +177,7 @@ class PasswordReset implements LoggerAwareInterface { $firstUser = $users[0]; if ( !$firstUser instanceof User || !$firstUser->getId() ) { - // Don't parse username as wikitext (bug 65501) + // Don't parse username as wikitext (T67501) return StatusValue::newFatal( wfMessage( 'nosuchuser', wfEscapeWikiText( $username ) ) ); } @@ -201,7 +193,7 @@ class PasswordReset implements LoggerAwareInterface { wfEscapeWikiText( $firstUser->getName() ) ) ); } - // We need to have a valid IP address for the hook, but per bug 18347, we should + // We need to have a valid IP address for the hook, but per T20347, we should // send the user's name if they're logged in. $ip = $performingUser->getRequest()->getIP(); if ( !$ip ) { @@ -216,7 +208,6 @@ class PasswordReset implements LoggerAwareInterface { $req = TemporaryPasswordAuthenticationRequest::newRandom(); $req->username = $user->getName(); $req->mailpassword = true; - $req->hasBackchannel = $displayPassword; $req->caller = $performingUser->getName(); $status = $this->authManager->allowsAuthenticationDataChange( $req, true ); if ( $status->isGood() && $status->getValue() !== 'ignored' ) { @@ -237,7 +228,6 @@ class PasswordReset implements LoggerAwareInterface { 'targetUsername' => $username, 'targetEmail' => $email, 'actualUser' => $firstUser->getName(), - 'capture' => $displayPassword, ]; if ( !$result->isGood() ) { @@ -251,40 +241,61 @@ class PasswordReset implements LoggerAwareInterface { $passwords = []; foreach ( $reqs as $req ) { $this->authManager->changeAuthenticationData( $req ); - // TODO record mail sending errors - if ( $displayPassword ) { - $passwords[$req->username] = $req->password; - } } - if ( $displayPassword ) { - // The password capture thing is scary, so log - // at a higher warning level. - $this->logger->warning( - "{requestingUser} did password reset of {actualUser} with password capturing!", - $logContext - ); - } else { - $this->logger->info( - "{requestingUser} did password reset of {actualUser}", - $logContext - ); - } + $this->logger->info( + "{requestingUser} did password reset of {actualUser}", + $logContext + ); return StatusValue::newGood( $passwords ); } + /** + * Check whether the user is blocked. + * Ignores certain types of system blocks that are only meant to force users to log in. + * @param User $user + * @return bool + * @since 1.30 + */ + protected function isBlocked( User $user ) { + $block = $user->getBlock() ?: $user->getGlobalBlock(); + if ( !$block ) { + return false; + } + $type = $block->getSystemBlockType(); + if ( in_array( $type, [ null, 'global-block' ], true ) ) { + // Normal block. Maybe it was meant for someone else and the user just needs to log in; + // or maybe it was issued specifically to prevent some IP from messing with password + // reset? Go out on a limb and use the registration allowed flag to decide. + return $block->prevents( 'createaccount' ); + } elseif ( $type === 'proxy' ) { + // we disallow actions through proxy even if the user is logged in + // so it makes sense to disallow password resets as well + return true; + } elseif ( in_array( $type, [ 'dnsbl', 'wgSoftBlockRanges' ], true ) ) { + // these are just meant to force login so let's not prevent that + return false; + } else { + // some extension - we'll have to guess + return true; + } + } + /** * @param string $email * @return User[] * @throws MWException On unexpected database errors */ protected function getUsersByEmail( $email ) { + $userQuery = User::getQueryInfo(); $res = wfGetDB( DB_REPLICA )->select( - 'user', - User::selectFields(), + $userQuery['tables'], + $userQuery['fields'], [ 'user_email' => $email ], - __METHOD__ + __METHOD__, + [], + $userQuery['joins'] ); if ( !$res ) {