X-Git-Url: http://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2Fuser%2FUser.php;h=d0a2f9213fcf6225b5f80250012e98024b422790;hb=6f96aa3bf78c7618412b6b5b9f2f6c784f0064b3;hp=4e8a5ffcd9a391ee4ea3cc44e7dd7d9d2ddaece7;hpb=01a3b2b0bf6519922c4e13f5b68cf7cfb3547a21;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/user/User.php b/includes/user/User.php index 4e8a5ffcd9..d0a2f9213f 100644 --- a/includes/user/User.php +++ b/includes/user/User.php @@ -66,7 +66,7 @@ class User implements IDBAccessObject { /** * @const int Serialized record version. */ - const VERSION = 10; + const VERSION = 11; /** * Exclude user options that are set to their default value. @@ -104,7 +104,7 @@ class User implements IDBAccessObject { 'mRegistration', 'mEditCount', // user_groups table - 'mGroups', + 'mGroupMemberships', // user_properties table 'mOptionOverrides', ]; @@ -225,8 +225,13 @@ class User implements IDBAccessObject { protected $mRegistration; /** @var int */ protected $mEditCount; - /** @var array */ - public $mGroups; + /** + * @var array No longer used since 1.29; use User::getGroups() instead + * @deprecated since 1.29 + */ + private $mGroups; + /** @var array Associative array of (group name => UserGroupMembership object) */ + protected $mGroupMemberships; /** @var array */ protected $mOptionOverrides; // @} @@ -283,9 +288,7 @@ class User implements IDBAccessObject { /** @var array */ public $mOptions; - /** - * @var WebRequest - */ + /** @var WebRequest */ private $mRequest; /** @var Block */ @@ -301,7 +304,8 @@ class User implements IDBAccessObject { protected $queryFlagsUsed = self::READ_NORMAL; /** @var string Indicates type of block (used for eventlogging) - * Permitted values: 'cookie-block', 'proxy-block', 'openproxy-block', 'xff-block' + * Permitted values: 'cookie-block', 'proxy-block', 'openproxy-block', 'xff-block', + * 'config-block' */ public $blockTrigger = false; @@ -467,6 +471,17 @@ class User implements IDBAccessObject { return $cache->makeGlobalKey( 'user', 'id', wfWikiID(), $this->mId ); } + /** + * @param WANObjectCache $cache + * @return string[] + * @since 1.28 + */ + public function getMutableCacheKeys( WANObjectCache $cache ) { + $id = $this->getId(); + + return $id ? [ $this->getCacheKey( $cache ) ] : []; + } + /** * Load user data from shared cache, given mId has already been set. * @@ -1137,7 +1152,7 @@ class User implements IDBAccessObject { $this->mEmailToken = ''; $this->mEmailTokenExpires = null; $this->mRegistration = wfTimestamp( TS_MW ); - $this->mGroups = []; + $this->mGroupMemberships = []; Hooks::run( 'UserLoadDefaults', [ $this, $name ] ); } @@ -1249,7 +1264,7 @@ class User implements IDBAccessObject { if ( $s !== false ) { // Initialise user table data $this->loadFromRow( $s ); - $this->mGroups = null; // deferred + $this->mGroupMemberships = null; // deferred $this->getEditCount(); // revalidation for nulls return true; } else { @@ -1266,13 +1281,16 @@ class User implements IDBAccessObject { * @param stdClass $row Row from the user table to load. * @param array $data Further user data to load into the object * - * user_groups Array with groups out of the user_groups table - * user_properties Array with properties out of the user_properties table + * user_groups Array of arrays or stdClass result rows out of the user_groups + * table. Previously you were supposed to pass an array of strings + * here, but we also need expiry info nowadays, so an array of + * strings is ignored. + * user_properties Array with properties out of the user_properties table */ protected function loadFromRow( $row, $data = null ) { $all = true; - $this->mGroups = null; // deferred + $this->mGroupMemberships = null; // deferred if ( isset( $row->user_name ) ) { $this->mName = $row->user_name; @@ -1341,7 +1359,18 @@ class User implements IDBAccessObject { if ( is_array( $data ) ) { if ( isset( $data['user_groups'] ) && is_array( $data['user_groups'] ) ) { - $this->mGroups = $data['user_groups']; + if ( !count( $data['user_groups'] ) ) { + $this->mGroupMemberships = []; + } else { + $firstGroup = reset( $data['user_groups'] ); + if ( is_array( $firstGroup ) || is_object( $firstGroup ) ) { + $this->mGroupMemberships = []; + foreach ( $data['user_groups'] as $row ) { + $ugm = UserGroupMembership::newFromRow( (object)$row ); + $this->mGroupMemberships[$ugm->getGroup()] = $ugm; + } + } + } } if ( isset( $data['user_properties'] ) && is_array( $data['user_properties'] ) ) { $this->loadOptions( $data['user_properties'] ); @@ -1365,18 +1394,12 @@ class User implements IDBAccessObject { * Load the groups from the database if they aren't already loaded. */ private function loadGroups() { - if ( is_null( $this->mGroups ) ) { + if ( is_null( $this->mGroupMemberships ) ) { $db = ( $this->queryFlagsUsed & self::READ_LATEST ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA ); - $res = $db->select( 'user_groups', - [ 'ug_group' ], - [ 'ug_user' => $this->mId ], - __METHOD__ ); - $this->mGroups = []; - foreach ( $res as $row ) { - $this->mGroups[] = $row->ug_group; - } + $this->mGroupMemberships = UserGroupMembership::getMembershipsForUser( + $this->mId, $db ); } } @@ -1508,7 +1531,7 @@ class User implements IDBAccessObject { $this->mRights = null; $this->mEffectiveGroups = null; $this->mImplicitGroups = null; - $this->mGroups = null; + $this->mGroupMemberships = null; $this->mOptions = null; $this->mOptionsLoaded = false; $this->mEditCount = null; @@ -1581,7 +1604,7 @@ class User implements IDBAccessObject { * Check when actually saving should be done against master. */ private function getBlockedStatus( $bFromSlave = true ) { - global $wgProxyWhitelist, $wgUser, $wgApplyIpBlocksToXff; + global $wgProxyWhitelist, $wgUser, $wgApplyIpBlocksToXff, $wgSoftBlockRanges; if ( -1 != $this->mBlockedby ) { return; @@ -1614,29 +1637,9 @@ class User implements IDBAccessObject { // User/IP blocking $block = Block::newFromTarget( $this, $ip, !$bFromSlave ); - // If no block has been found, check for a cookie indicating that the user is blocked. - $blockCookieVal = (int)$this->getRequest()->getCookie( 'BlockID' ); - if ( !$block instanceof Block && $blockCookieVal > 0 ) { - // Load the Block from the ID in the cookie. - $tmpBlock = Block::newFromID( $blockCookieVal ); - if ( $tmpBlock instanceof Block ) { - // Check the validity of the block. - $blockIsValid = $tmpBlock->getType() == Block::TYPE_USER - && !$tmpBlock->isExpired() - && $tmpBlock->isAutoblocking(); - $config = RequestContext::getMain()->getConfig(); - $useBlockCookie = ( $config->get( 'CookieSetOnAutoblock' ) === true ); - if ( $blockIsValid && $useBlockCookie ) { - // Use the block. - $block = $tmpBlock; - $this->blockTrigger = 'cookie-block'; - } else { - // If the block is not valid, clear the block cookie (but don't delete it, - // because it needs to be cleared from LocalStorage as well and an empty string - // value is checked for in the mediawiki.user.blockcookie module). - $tmpBlock->setCookie( $this->getRequest()->response(), true ); - } - } + // Cookie blocking + if ( !$block instanceof Block ) { + $block = $this->getBlockFromCookieValue( $this->getRequest()->getCookie( 'BlockID' ) ); } // Proxy blocking @@ -1680,6 +1683,21 @@ class User implements IDBAccessObject { } } + if ( !$block instanceof Block + && $ip !== null + && $this->isAnon() + && IP::isInRanges( $ip, $wgSoftBlockRanges ) + ) { + $block = new Block( [ + 'address' => $ip, + 'byText' => 'MediaWiki default', + 'reason' => wfMessage( 'softblockrangesreason', $ip )->text(), + 'anonOnly' => true, + 'systemBlock' => 'wgSoftBlockRanges', + ] ); + $this->blockTrigger = 'config-block'; + } + if ( $block instanceof Block ) { wfDebug( __METHOD__ . ": Found block.\n" ); $this->mBlock = $block; @@ -1694,8 +1712,47 @@ class User implements IDBAccessObject { $this->blockTrigger = false; } + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; // Extensions - Hooks::run( 'GetBlockedStatus', [ &$this ] ); + Hooks::run( 'GetBlockedStatus', [ &$user ] ); + } + + /** + * Try to load a Block from an ID given in a cookie value. + * @param string|null $blockCookieVal The cookie value to check. + * @return Block|bool The Block object, or false if none could be loaded. + */ + protected function getBlockFromCookieValue( $blockCookieVal ) { + // Make sure there's something to check. The cookie value must start with a number. + if ( strlen( $blockCookieVal ) < 1 || !is_numeric( substr( $blockCookieVal, 0, 1 ) ) ) { + return false; + } + // Load the Block from the ID in the cookie. + $blockCookieId = Block::getIdFromCookieValue( $blockCookieVal ); + if ( $blockCookieId !== null ) { + // An ID was found in the cookie. + $tmpBlock = Block::newFromID( $blockCookieId ); + if ( $tmpBlock instanceof Block ) { + // Check the validity of the block. + $blockIsValid = $tmpBlock->getType() == Block::TYPE_USER + && !$tmpBlock->isExpired() + && $tmpBlock->isAutoblocking(); + $config = RequestContext::getMain()->getConfig(); + $useBlockCookie = ( $config->get( 'CookieSetOnAutoblock' ) === true ); + if ( $blockIsValid && $useBlockCookie ) { + // Use the block. + $this->blockTrigger = 'cookie-block'; + return $tmpBlock; + } else { + // If the block is not valid, clear the block cookie (but don't delete it, + // because it needs to be cleared from LocalStorage as well and an empty string + // value is checked for in the mediawiki.user.blockcookie module). + $tmpBlock->setCookie( $this->getRequest()->response(), true ); + } + } + } + return false; } /** @@ -1780,21 +1837,22 @@ class User implements IDBAccessObject { } if ( !is_array( $wgProxyList ) ) { - // Load from the specified file + // Load values from the specified file $wgProxyList = array_map( 'trim', file( $wgProxyList ) ); } - if ( !is_array( $wgProxyList ) ) { - $ret = false; - } elseif ( array_search( $ip, $wgProxyList ) !== false ) { - $ret = true; - } elseif ( array_key_exists( $ip, $wgProxyList ) ) { - // Old-style flipped proxy list - $ret = true; - } else { - $ret = false; + if ( is_array( $wgProxyList ) ) { + if ( + // Look for IP as value + array_search( $ip, $wgProxyList ) !== false || + // Look for IP as key (for backwards-compatility) + array_key_exists( $ip, $wgProxyList ) + ) { + return true; + } } - return $ret; + + return false; } /** @@ -1828,9 +1886,11 @@ class User implements IDBAccessObject { * @return bool True if a rate limiter was tripped */ public function pingLimiter( $action = 'edit', $incrBy = 1 ) { + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; // Call the 'PingLimiter' hook $result = false; - if ( !Hooks::run( 'PingLimiter', [ &$this, $action, &$result, $incrBy ] ) ) { + if ( !Hooks::run( 'PingLimiter', [ &$user, $action, &$result, $incrBy ] ) ) { return $result; } @@ -2065,9 +2125,11 @@ class User implements IDBAccessObject { } elseif ( !$ip ) { $ip = $this->getRequest()->getIP(); } + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; $blocked = false; $block = null; - Hooks::run( 'UserIsBlockedGlobally', [ &$this, $ip, &$blocked, &$block ] ); + Hooks::run( 'UserIsBlockedGlobally', [ &$user, $ip, &$blocked, &$block ] ); if ( $blocked && $block === null ) { // back-compat: UserIsBlockedGlobally didn't have $block param first @@ -2090,7 +2152,9 @@ class User implements IDBAccessObject { if ( $this->mLocked !== null ) { return $this->mLocked; } - $authUser = AuthManager::callLegacyAuthPlugin( 'getUserInstance', [ &$this ], null ); + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; + $authUser = AuthManager::callLegacyAuthPlugin( 'getUserInstance', [ &$user ], null ); $this->mLocked = $authUser && $authUser->isLocked(); Hooks::run( 'UserIsLocked', [ $this, &$this->mLocked ] ); return $this->mLocked; @@ -2107,7 +2171,9 @@ class User implements IDBAccessObject { } $this->getBlockedStatus(); if ( !$this->mHideName ) { - $authUser = AuthManager::callLegacyAuthPlugin( 'getUserInstance', [ &$this ], null ); + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; + $authUser = AuthManager::callLegacyAuthPlugin( 'getUserInstance', [ &$user ], null ); $this->mHideName = $authUser && $authUser->isHidden(); Hooks::run( 'UserIsHidden', [ $this, &$this->mHideName ] ); } @@ -2226,8 +2292,10 @@ class User implements IDBAccessObject { * @return array */ public function getNewMessageLinks() { + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; $talks = []; - if ( !Hooks::run( 'UserRetrieveNewTalks', [ &$this, &$talks ] ) ) { + if ( !Hooks::run( 'UserRetrieveNewTalks', [ &$user, &$talks ] ) ) { return $talks; } elseif ( !$this->getNewtalk() ) { return []; @@ -2483,24 +2551,6 @@ class User implements IDBAccessObject { return $this->mTouched; } - /** - * @deprecated Removed in 1.27. - * @return Password - * @since 1.24 - */ - public function getPassword() { - throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' ); - } - - /** - * @deprecated Removed in 1.27. - * @return Password - * @since 1.24 - */ - public function getTemporaryPassword() { - throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' ); - } - /** * Set the password and reset the random token. * Calls through to authentication plugin if necessary; @@ -2668,16 +2718,6 @@ class User implements IDBAccessObject { throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' ); } - /** - * Has password reminder email been sent within the last - * $wgPasswordReminderResendTime hours? - * @deprecated Removed in 1.27. See above. - * @return bool - */ - public function isPasswordReminderThrottled() { - throw new BadMethodCallException( __METHOD__ . ' has been removed in 1.27' ); - } - /** * Get the user's e-mail address * @return string User's email address @@ -3221,7 +3261,20 @@ class User implements IDBAccessObject { public function getGroups() { $this->load(); $this->loadGroups(); - return $this->mGroups; + return array_keys( $this->mGroupMemberships ); + } + + /** + * Get the list of explicit group memberships this user has, stored as + * UserGroupMembership objects. Implicit groups are not included. + * + * @return array Associative array of (group name as string => UserGroupMembership object) + * @since 1.29 + */ + public function getGroupMemberships() { + $this->load(); + $this->loadGroups(); + return $this->mGroupMemberships; } /** @@ -3237,8 +3290,10 @@ class User implements IDBAccessObject { $this->getGroups(), // explicit groups $this->getAutomaticGroups( $recache ) // implicit groups ) ); + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; // Hook for additional groups - Hooks::run( 'UserEffectiveGroups', [ &$this, &$this->mEffectiveGroups ] ); + Hooks::run( 'UserEffectiveGroups', [ &$user, &$this->mEffectiveGroups ] ); // Force reindexation of groups when a hook has unset one of them $this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) ); } @@ -3330,34 +3385,35 @@ class User implements IDBAccessObject { } /** - * Add the user to the given group. - * This takes immediate effect. + * Add the user to the given group. This takes immediate effect. + * If the user is already in the group, the expiry time will be updated to the new + * expiry time. (If $expiry is omitted or null, the membership will be altered to + * never expire.) + * * @param string $group Name of the group to add + * @param string $expiry Optional expiry timestamp in any format acceptable to + * wfTimestamp(), or null if the group assignment should not expire * @return bool */ - public function addGroup( $group ) { + public function addGroup( $group, $expiry = null ) { $this->load(); + $this->loadGroups(); - if ( !Hooks::run( 'UserAddGroup', [ $this, &$group ] ) ) { + if ( $expiry ) { + $expiry = wfTimestamp( TS_MW, $expiry ); + } + + if ( !Hooks::run( 'UserAddGroup', [ $this, &$group, &$expiry ] ) ) { return false; } - $dbw = wfGetDB( DB_MASTER ); - if ( $this->getId() ) { - $dbw->insert( 'user_groups', - [ - 'ug_user' => $this->getId(), - 'ug_group' => $group, - ], - __METHOD__, - [ 'IGNORE' ] ); + // create the new UserGroupMembership and put it in the DB + $ugm = new UserGroupMembership( $this->mId, $group, $expiry ); + if ( !$ugm->insert( true ) ) { + return false; } - $this->loadGroups(); - $this->mGroups[] = $group; - // In case loadGroups was not called before, we now have the right twice. - // Get rid of the duplicate. - $this->mGroups = array_unique( $this->mGroups ); + $this->mGroupMemberships[$group] = $ugm; // Refresh the groups caches, and clear the rights cache so it will be // refreshed on the next call to $this->getRights(). @@ -3377,29 +3433,19 @@ class User implements IDBAccessObject { */ public function removeGroup( $group ) { $this->load(); + if ( !Hooks::run( 'UserRemoveGroup', [ $this, &$group ] ) ) { return false; } - $dbw = wfGetDB( DB_MASTER ); - $dbw->delete( 'user_groups', - [ - 'ug_user' => $this->getId(), - 'ug_group' => $group, - ], __METHOD__ - ); - // Remember that the user was in this group - $dbw->insert( 'user_former_groups', - [ - 'ufg_user' => $this->getId(), - 'ufg_group' => $group, - ], - __METHOD__, - [ 'IGNORE' ] - ); + $ugm = UserGroupMembership::getMembership( $this->mId, $group ); + // delete the membership entry + if ( !$ugm || !$ugm->delete() ) { + return false; + } $this->loadGroups(); - $this->mGroups = array_diff( $this->mGroups, [ $group ] ); + unset( $this->mGroupMemberships[$group] ); // Refresh the groups caches, and clear the rights cache so it will be // refreshed on the next call to $this->getRights(). @@ -3605,7 +3651,9 @@ class User implements IDBAccessObject { // If we're working on user's talk page, we should update the talk page message indicator if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) { - if ( !Hooks::run( 'UserClearNewTalkNotification', [ &$this, $oldid ] ) ) { + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; + if ( !Hooks::run( 'UserClearNewTalkNotification', [ &$user, $oldid ] ) ) { return; } @@ -3837,7 +3885,9 @@ class User implements IDBAccessObject { * Log this user out. */ public function logout() { - if ( Hooks::run( 'UserLogout', [ &$this ] ) ) { + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; + if ( Hooks::run( 'UserLogout', [ &$user ] ) ) { $this->doLogout(); } } @@ -4512,7 +4562,9 @@ class User implements IDBAccessObject { return false; } $canSend = $this->isEmailConfirmed(); - Hooks::run( 'UserCanSendEmail', [ &$this, &$canSend ] ); + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; + Hooks::run( 'UserCanSendEmail', [ &$user, &$canSend ] ); return $canSend; } @@ -4538,8 +4590,10 @@ class User implements IDBAccessObject { public function isEmailConfirmed() { global $wgEmailAuthentication; $this->load(); + // Avoid PHP 7.1 warning of passing $this by reference + $user = $this; $confirmed = true; - if ( Hooks::run( 'EmailConfirmed', [ &$this, &$confirmed ] ) ) { + if ( Hooks::run( 'EmailConfirmed', [ &$user, &$confirmed ] ) ) { if ( $this->isAnon() ) { return false; } @@ -4725,25 +4779,27 @@ class User implements IDBAccessObject { /** * Get the localized descriptive name for a group, if it exists + * @deprecated since 1.29 Use UserGroupMembership::getGroupName instead * * @param string $group Internal group name * @return string Localized descriptive group name */ public static function getGroupName( $group ) { - $msg = wfMessage( "group-$group" ); - return $msg->isBlank() ? $group : $msg->text(); + wfDeprecated( __METHOD__, '1.29' ); + return UserGroupMembership::getGroupName( $group ); } /** * Get the localized descriptive name for a member of a group, if it exists + * @deprecated since 1.29 Use UserGroupMembership::getGroupMemberName instead * * @param string $group Internal group name * @param string $username Username for gender (since 1.19) * @return string Localized name for group member */ public static function getGroupMember( $group, $username = '#' ) { - $msg = wfMessage( "group-$group-member", $username ); - return $msg->isBlank() ? $group : $msg->text(); + wfDeprecated( __METHOD__, '1.29' ); + return UserGroupMembership::getGroupMemberName( $group, $username ); } /** @@ -4793,34 +4849,33 @@ class User implements IDBAccessObject { /** * Get the title of a page describing a particular group + * @deprecated since 1.29 Use UserGroupMembership::getGroupPage instead * * @param string $group Internal group name * @return Title|bool Title of the page if it exists, false otherwise */ public static function getGroupPage( $group ) { - $msg = wfMessage( 'grouppage-' . $group )->inContentLanguage(); - if ( $msg->exists() ) { - $title = Title::newFromText( $msg->text() ); - if ( is_object( $title ) ) { - return $title; - } - } - return false; + wfDeprecated( __METHOD__, '1.29' ); + return UserGroupMembership::getGroupPage( $group ); } /** * Create a link to the group in HTML, if available; * else return the group name. + * @deprecated since 1.29 Use UserGroupMembership::getLink instead, or + * make the link yourself if you need custom text * * @param string $group Internal name of the group * @param string $text The text of the link * @return string HTML link to the group */ public static function makeGroupLinkHTML( $group, $text = '' ) { + wfDeprecated( __METHOD__, '1.29' ); + if ( $text == '' ) { - $text = self::getGroupName( $group ); + $text = UserGroupMembership::getGroupName( $group ); } - $title = self::getGroupPage( $group ); + $title = UserGroupMembership::getGroupPage( $group ); if ( $title ) { return Linker::link( $title, htmlspecialchars( $text ) ); } else { @@ -4831,16 +4886,20 @@ class User implements IDBAccessObject { /** * Create a link to the group in Wikitext, if available; * else return the group name. + * @deprecated since 1.29 Use UserGroupMembership::getLink instead, or + * make the link yourself if you need custom text * * @param string $group Internal name of the group * @param string $text The text of the link * @return string Wikilink to the group */ public static function makeGroupLinkWiki( $group, $text = '' ) { + wfDeprecated( __METHOD__, '1.29' ); + if ( $text == '' ) { - $text = self::getGroupName( $group ); + $text = UserGroupMembership::getGroupName( $group ); } - $title = self::getGroupPage( $group ); + $title = UserGroupMembership::getGroupPage( $group ); if ( $title ) { $page = $title->getFullText(); return "[[$page|$text]]"; @@ -5080,54 +5139,6 @@ class User implements IDBAccessObject { return $msg->isDisabled() ? $grant : $msg->text(); } - /** - * Make a new-style password hash - * - * @param string $password Plain-text password - * @param bool|string $salt Optional salt, may be random or the user ID. - * If unspecified or false, will generate one automatically - * @return string Password hash - * @deprecated since 1.24, use Password class - */ - public static function crypt( $password, $salt = false ) { - wfDeprecated( __METHOD__, '1.24' ); - $passwordFactory = new PasswordFactory(); - $passwordFactory->init( RequestContext::getMain()->getConfig() ); - $hash = $passwordFactory->newFromPlaintext( $password ); - return $hash->toString(); - } - - /** - * Compare a password hash with a plain-text password. Requires the user - * ID if there's a chance that the hash is an old-style hash. - * - * @param string $hash Password hash - * @param string $password Plain-text password to compare - * @param string|bool $userId User ID for old-style password salt - * - * @return bool - * @deprecated since 1.24, use Password class - */ - public static function comparePasswords( $hash, $password, $userId = false ) { - wfDeprecated( __METHOD__, '1.24' ); - - // Check for *really* old password hashes that don't even have a type - // The old hash format was just an md5 hex hash, with no type information - if ( preg_match( '/^[0-9a-f]{32}$/', $hash ) ) { - global $wgPasswordSalt; - if ( $wgPasswordSalt ) { - $password = ":B:{$userId}:{$hash}"; - } else { - $password = ":A:{$hash}"; - } - } - - $passwordFactory = new PasswordFactory(); - $passwordFactory->init( RequestContext::getMain()->getConfig() ); - $hash = $passwordFactory->newFromCiphertext( $hash ); - return $hash->equals( $password ); - } - /** * Add a newuser log entry for this user. * Before 1.19 the return value was always true. @@ -5400,10 +5411,10 @@ class User implements IDBAccessObject { static function newFatalPermissionDeniedStatus( $permission ) { global $wgLang; - $groups = array_map( - [ 'User', 'makeGroupLinkWiki' ], - User::getGroupsWithPermission( $permission ) - ); + $groups = []; + foreach ( User::getGroupsWithPermission( $permission ) as $group ) { + $groups[] = UserGroupMembership::getLink( $group, RequestContext::getMain(), 'wiki' ); + } if ( $groups ) { return Status::newFatal( 'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );