* @file
*/
+use MediaWiki\Block\AbstractBlock;
+use MediaWiki\Block\DatabaseBlock;
+use MediaWiki\Block\SystemBlock;
use MediaWiki\MediaWikiServices;
use MediaWiki\Session\SessionManager;
use MediaWiki\Session\Token;
protected $mImplicitGroups;
/** @var array */
protected $mFormerGroups;
- /** @var Block */
+ /** @var AbstractBlock */
protected $mGlobalBlock;
/** @var bool */
protected $mLocked;
/** @var WebRequest */
private $mRequest;
- /** @var Block */
+ /** @var AbstractBlock */
public $mBlock;
/** @var bool */
protected $mAllowUsertalk;
- /** @var Block */
+ /** @var AbstractBlock */
private $mBlockedFromCreateAccount = false;
/** @var int User::READ_* constant bitfield used to load data */
* @param int|null $userId User ID, if known
* @param string|null $userName User name, if known
* @param int|null $actorId Actor ID, if known
+ * @param bool|string $wikiId remote wiki to which the User/Actor ID applies, or false if none
* @return User
*/
- public static function newFromAnyId( $userId, $userName, $actorId ) {
+ public static function newFromAnyId( $userId, $userName, $actorId, $wikiId = false ) {
global $wgActorTableSchemaMigrationStage;
+ // Stop-gap solution for the problem described in T222212.
+ // Force the User ID and Actor ID to zero for users loaded from the database
+ // of another wiki, to prevent subtle data corruption and confusing failure modes.
+ if ( $wikiId !== false ) {
+ $userId = 0;
+ $actorId = 0;
+ }
+
$user = new User;
$user->mFrom = 'defaults';
}
if ( !( $flags & self::READ_LATEST ) && array_key_exists( $name, self::$idCacheByName ) ) {
- return self::$idCacheByName[$name];
+ return is_null( self::$idCacheByName[$name] ) ? null : (int)self::$idCacheByName[$name];
}
list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
return $this->checkPasswordValidity( $password )->isGood();
}
- /**
- * Given unvalidated password input, return error message on failure.
- *
- * @param string $password Desired password
- * @return bool|string|array True on success, string or array of error message on failure
- * @deprecated since 1.33, use checkPasswordValidity
- */
- public function getPasswordValidity( $password ) {
- wfDeprecated( __METHOD__, '1.33' );
-
- $result = $this->checkPasswordValidity( $password );
- if ( $result->isGood() ) {
- return true;
- }
-
- $messages = [];
- foreach ( $result->getErrorsByType( 'error' ) as $error ) {
- $messages[] = $error['message'];
- }
- foreach ( $result->getErrorsByType( 'warning' ) as $warning ) {
- $messages[] = $warning['message'];
- }
- if ( count( $messages ) === 1 ) {
- return $messages[0];
- }
-
- return $messages;
- }
-
/**
* Check if this is a valid password for this user
*
if ( $user->isLoggedIn() ) {
$this->loadFromUserObject( $user );
if ( $user->getBlock() ) {
- // If this user is autoblocked, set a cookie to track the Block. This has to be done on
+ // If this user is autoblocked, set a cookie to track the block. This has to be done on
// every session load, because an autoblocked editor might not edit again from the same
// IP address after being blocked.
$this->trackBlockWithCookie();
/**
* Get blocking information
+ *
+ * TODO: Move this into the BlockManager, along with block-related properties.
+ *
* @param bool $fromReplica Whether to check the replica DB first.
* To improve performance, non-critical checks are done against replica DBs.
* Check when actually saving should be done against master.
*/
private function getBlockedStatus( $fromReplica = true ) {
- global $wgProxyWhitelist, $wgApplyIpBlocksToXff, $wgSoftBlockRanges;
-
if ( $this->mBlockedby != -1 ) {
return;
}
// overwriting mBlockedby, surely?
$this->load();
- # We only need to worry about passing the IP address to the Block generator if the
- # user is not immune to autoblocks/hardblocks, and they are the current user so we
- # know which IP address they're actually coming from
- $ip = null;
- $sessionUser = RequestContext::getMain()->getUser();
- // the session user is set up towards the end of Setup.php. Until then,
- // assume it's a logged-out user.
- $globalUserName = $sessionUser->isSafeToLoad()
- ? $sessionUser->getName()
- : IP::sanitizeIP( $sessionUser->getRequest()->getIP() );
- if ( $this->getName() === $globalUserName && !$this->isAllowed( 'ipblock-exempt' ) ) {
- $ip = $this->getRequest()->getIP();
- }
-
- // User/IP blocking
- $block = Block::newFromTarget( $this, $ip, !$fromReplica );
-
- // Cookie blocking
- if ( !$block instanceof Block ) {
- $block = $this->getBlockFromCookieValue( $this->getRequest()->getCookie( 'BlockID' ) );
- }
-
- // Proxy blocking
- if ( !$block instanceof Block && $ip !== null && !in_array( $ip, $wgProxyWhitelist ) ) {
- // Local list
- if ( self::isLocallyBlockedProxy( $ip ) ) {
- $block = new Block( [
- 'byText' => wfMessage( 'proxyblocker' )->text(),
- 'reason' => wfMessage( 'proxyblockreason' )->plain(),
- 'address' => $ip,
- 'systemBlock' => 'proxy',
- ] );
- } elseif ( $this->isAnon() && $this->isDnsBlacklisted( $ip ) ) {
- $block = new Block( [
- 'byText' => wfMessage( 'sorbs' )->text(),
- 'reason' => wfMessage( 'sorbsreason' )->plain(),
- 'address' => $ip,
- 'systemBlock' => 'dnsbl',
- ] );
- }
- }
-
- // (T25343) Apply IP blocks to the contents of XFF headers, if enabled
- if ( !$block instanceof Block
- && $wgApplyIpBlocksToXff
- && $ip !== null
- && !in_array( $ip, $wgProxyWhitelist )
- ) {
- $xff = $this->getRequest()->getHeader( 'X-Forwarded-For' );
- $xff = array_map( 'trim', explode( ',', $xff ) );
- $xff = array_diff( $xff, [ $ip ] );
- $xffblocks = Block::getBlocksForIPList( $xff, $this->isAnon(), !$fromReplica );
- $block = Block::chooseBlock( $xffblocks, $xff );
- if ( $block instanceof Block ) {
- # Mangle the reason to alert the user that the block
- # originated from matching the X-Forwarded-For header.
- $block->setReason( wfMessage( 'xffblockreason', $block->getReason() )->plain() );
- }
- }
-
- if ( !$block instanceof Block
- && $ip !== null
- && $this->isAnon()
- && IP::isInRanges( $ip, $wgSoftBlockRanges )
- ) {
- $block = new Block( [
- 'address' => $ip,
- 'byText' => 'MediaWiki default',
- 'reason' => wfMessage( 'softblockrangesreason', $ip )->plain(),
- 'anonOnly' => true,
- 'systemBlock' => 'wgSoftBlockRanges',
- ] );
- }
+ $block = MediaWikiServices::getInstance()->getBlockManager()->getUserBlock(
+ $this,
+ $fromReplica
+ );
- if ( $block instanceof Block ) {
+ if ( $block instanceof AbstractBlock ) {
wfDebug( __METHOD__ . ": Found block.\n" );
$this->mBlock = $block;
$this->mBlockedby = $block->getByName();
Hooks::run( 'GetBlockedStatus', [ &$thisUser ] );
}
- /**
- * 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 ) {
- $config = RequestContext::getMain()->getConfig();
-
- switch ( $tmpBlock->getType() ) {
- case Block::TYPE_USER:
- $blockIsValid = !$tmpBlock->isExpired() && $tmpBlock->isAutoblocking();
- $useBlockCookie = ( $config->get( 'CookieSetOnAutoblock' ) === true );
- break;
- case Block::TYPE_IP:
- case Block::TYPE_RANGE:
- // If block is type IP or IP range, load only if user is not logged in (T152462)
- $blockIsValid = !$tmpBlock->isExpired() && !$this->isLoggedIn();
- $useBlockCookie = ( $config->get( 'CookieSetOnIpBlock' ) === true );
- break;
- default:
- $blockIsValid = false;
- $useBlockCookie = false;
- }
-
- if ( $blockIsValid && $useBlockCookie ) {
- // Use the block.
- return $tmpBlock;
- }
-
- // If the block is not valid, remove the cookie.
- Block::clearCookie( $this->getRequest()->response() );
- } else {
- // If the block doesn't exist, remove the cookie.
- Block::clearCookie( $this->getRequest()->response() );
- }
- }
- return false;
- }
-
/**
* Whether the given IP is in a DNS blacklist.
*
+ * @deprecated since 1.34 Use BlockManager::isDnsBlacklisted.
* @param string $ip IP to check
* @param bool $checkWhitelist Whether to check the whitelist first
* @return bool True if blacklisted.
*/
public function isDnsBlacklisted( $ip, $checkWhitelist = false ) {
- global $wgEnableDnsBlacklist, $wgDnsBlacklistUrls, $wgProxyWhitelist;
-
- if ( !$wgEnableDnsBlacklist ||
- ( $checkWhitelist && in_array( $ip, $wgProxyWhitelist ) )
- ) {
- return false;
- }
-
- return $this->inDnsBlacklist( $ip, $wgDnsBlacklistUrls );
+ return MediaWikiServices::getInstance()->getBlockManager()
+ ->isDnsBlacklisted( $ip, $checkWhitelist );
}
/**
* Whether the given IP is in a given DNS blacklist.
*
+ * @deprecated since 1.34 Check via BlockManager::isDnsBlacklisted instead.
* @param string $ip IP to check
* @param string|array $bases Array of Strings: URL of the DNS blacklist
* @return bool True if blacklisted.
*/
public function inDnsBlacklist( $ip, $bases ) {
+ wfDeprecated( __METHOD__, '1.34' );
+
$found = false;
// @todo FIXME: IPv6 ??? (https://bugs.php.net/bug.php?id=33170)
if ( IP::isIPv4( $ip ) ) {
/**
* Check if an IP address is in the local proxy list
*
+ * @deprecated since 1.34 Use BlockManager::getUserBlock instead.
* @param string $ip
- *
* @return bool
*/
public static function isLocallyBlockedProxy( $ip ) {
+ wfDeprecated( __METHOD__, '1.34' );
+
global $wgProxyList;
if ( !$wgProxyList ) {
* @return bool True if blocked, false otherwise
*/
public function isBlocked( $fromReplica = true ) {
- return $this->getBlock( $fromReplica ) instanceof Block &&
+ return $this->getBlock( $fromReplica ) instanceof AbstractBlock &&
$this->getBlock()->appliesToRight( 'edit' );
}
* Get the block affecting the user, or null if the user is not blocked
*
* @param bool $fromReplica Whether to check the replica DB instead of the master
- * @return Block|null
+ * @return AbstractBlock|null
*/
public function getBlock( $fromReplica = true ) {
$this->getBlockedStatus( $fromReplica );
- return $this->mBlock instanceof Block ? $this->mBlock : null;
+ return $this->mBlock instanceof AbstractBlock ? $this->mBlock : null;
}
/**
* @return bool True if blocked, false otherwise
*/
public function isBlockedGlobally( $ip = '' ) {
- return $this->getGlobalBlock( $ip ) instanceof Block;
+ return $this->getGlobalBlock( $ip ) instanceof AbstractBlock;
}
/**
* This is intended for quick UI checks.
*
* @param string $ip IP address, uses current client if none given
- * @return Block|null Block object if blocked, null otherwise
+ * @return AbstractBlock|null Block object if blocked, null otherwise
* @throws FatalError
* @throws MWException
*/
if ( $blocked && $block === null ) {
// back-compat: UserIsBlockedGlobally didn't have $block param first
- $block = new Block( [
+ $block = new SystemBlock( [
'address' => $ip,
'systemBlock' => 'global-block'
] );
return true;
}
+ /**
+ * Alias of isLoggedIn() with a name that describes its actual functionality. UserIdentity has
+ * only this new name and not the old isLoggedIn() variant.
+ *
+ * @return bool True if user is registered on this wiki, i.e., has a user ID. False if user is
+ * anonymous or has no local account (which can happen when importing). This is equivalent to
+ * getId() != 0 and is provided for code readability.
+ * @since 1.34
+ */
+ public function isRegistered() {
+ return $this->getId() != 0;
+ }
+
/**
* Get whether the user is logged in
* @return bool
*/
public function isLoggedIn() {
- return $this->getId() != 0;
+ return $this->isRegistered();
}
/**
* @return bool
*/
public function isAnon() {
- return !$this->isLoggedIn();
+ return !$this->isRegistered();
}
/**
return false;
}
- $userblock = Block::newFromTarget( $this->getName() );
+ $userblock = DatabaseBlock::newFromTarget( $this->getName() );
if ( !$userblock ) {
return false;
}
/**
* Get whether the user is explicitly blocked from account creation.
- * @return bool|Block
+ * @return bool|AbstractBlock
*/
public function isBlockedFromCreateAccount() {
$this->getBlockedStatus();
# blocked with createaccount disabled, prevent new account creation there even
# when the user is logged in
if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
- $this->mBlockedFromCreateAccount = Block::newFromTarget( null, $this->getRequest()->getIP() );
+ $this->mBlockedFromCreateAccount = DatabaseBlock::newFromTarget(
+ null, $this->getRequest()->getIP()
+ );
}
- return $this->mBlockedFromCreateAccount instanceof Block
+ return $this->mBlockedFromCreateAccount instanceof AbstractBlock
&& $this->mBlockedFromCreateAccount->appliesToRight( 'createaccount' )
? $this->mBlockedFromCreateAccount
: false;