<?php
/**
- * Blocks and bans object
+ * Class for blocks stored in the database.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
use MediaWiki\Block\Restriction\PageRestriction;
use MediaWiki\MediaWikiServices;
+/**
+ * Blocks (as opposed to system blocks) are stored in the database, may
+ * give rise to autoblocks and may be tracked with cookies. Blocks are
+ * more customizable than system blocks: they may be hardblocks, and
+ * they may be sitewide or partial.
+ */
class Block extends AbstractBlock {
- /** @var string */
- public $mReason;
-
- /** @var string */
- public $mTimestamp;
-
/** @var bool */
public $mAuto;
- /** @var string */
- public $mExpiry;
-
- /** @var bool */
- public $mHideName;
-
/** @var int */
public $mParentBlockId;
/** @var bool */
private $mFromMaster;
- /** @var bool */
- private $mBlockEmail;
-
- /** @var bool */
- private $allowUsertalk;
-
- /** @var bool */
- private $blockCreateAccount;
-
- /** @var User|string */
- private $target;
-
/** @var int Hack for foreign blocking (CentralAuth) */
private $forcedTargetID;
- /**
- * @var int Block::TYPE_ constant. After the block has been loaded
- * from the database, this can only be USER, IP or RANGE.
- */
- private $type;
-
- /** @var User */
- private $blocker;
-
/** @var bool */
private $isHardblock;
/** @var bool */
private $isAutoblocking;
- /** @var string|null */
- private $systemBlockType;
-
- /** @var bool */
- private $isSitewide;
-
/** @var Restriction[] */
private $restrictions;
- # TYPE constants
- const TYPE_USER = 1;
- const TYPE_IP = 2;
- const TYPE_RANGE = 3;
- const TYPE_AUTO = 4;
- const TYPE_ID = 5;
-
/**
* Create a new block with specified option parameters on a user, IP or IP range.
*
* @param array $options Parameters of the block:
- * address string|User Target user name, User object, IP address or IP range
* user int Override target user ID (for foreign users)
- * by int User ID of the blocker
- * reason string Reason of the block
- * timestamp string The time at which the block comes into effect
* auto bool Is this an automatic block?
* expiry string Timestamp of expiration of the block or 'infinity'
* anonOnly bool Only disallow anonymous actions
* hideName bool Hide the target user name
* blockEmail bool Disallow sending emails
* allowUsertalk bool Allow the target to edit its own talk page
- * byText string Username of the blocker (for foreign users)
- * systemBlock string Indicate that this block is automatically
- * created by MediaWiki rather than being stored
- * in the database. Value is a string to return
- * from self::getSystemBlockType().
* sitewide bool Disallow editing all pages and all contribution
* actions, except those specifically allowed by
* other block flags
* @since 1.26 $options array
*/
public function __construct( array $options = [] ) {
+ parent::__construct( $options );
+
$defaults = [
- 'address' => '',
'user' => null,
- 'by' => null,
- 'reason' => '',
- 'timestamp' => '',
'auto' => false,
'expiry' => '',
'anonOnly' => false,
'hideName' => false,
'blockEmail' => false,
'allowUsertalk' => false,
- 'byText' => '',
- 'systemBlock' => null,
'sitewide' => true,
];
$options += $defaults;
- $this->setTarget( $options['address'] );
-
if ( $this->target instanceof User && $options['user'] ) {
# Needed for foreign users
$this->forcedTargetID = $options['user'];
}
- if ( $options['by'] ) {
- # Local user
- $this->setBlocker( User::newFromId( $options['by'] ) );
- } else {
- # Foreign user
- $this->setBlocker( $options['byText'] );
- }
-
- $this->setReason( $options['reason'] );
- $this->setTimestamp( wfTimestamp( TS_MW, $options['timestamp'] ) );
$this->setExpiry( wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] ) );
# Boolean settings
$this->isUsertalkEditAllowed( (bool)$options['allowUsertalk'] );
$this->mFromMaster = false;
- $this->systemBlockType = $options['systemBlock'];
}
/**
public function insert( $dbw = null ) {
global $wgBlockDisablesLogin;
- if ( $this->getSystemBlockType() !== null ) {
- throw new MWException( 'Cannot insert a system block into the database' );
- }
if ( !$this->getBlocker() || $this->getBlocker()->getName() === '' ) {
throw new MWException( 'Cannot insert a block without a blocker set' );
}
return false;
}
- # Don't autoblock for system blocks
- if ( $this->getSystemBlockType() !== null ) {
- throw new MWException( 'Cannot autoblock from a system block' );
- }
-
# Check for presence on the autoblock whitelist.
if ( self::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
return false;
}
/**
- * Get the user id of the blocking sysop
- *
- * @return int (0 for foreign users)
- */
- public function getBy() {
- return $this->getBlocker()->getId();
- }
-
- /**
- * Get the username of the blocking sysop
- *
- * @return string
- */
- public function getByName() {
- return $this->getBlocker()->getName();
- }
-
- /**
- * Get the block ID
- * @return int
+ * @inheritDoc
*/
public function getId() {
return $this->mId;
return $this;
}
- /**
- * Get the reason given for creating the block
- *
- * @since 1.33
- * @return string
- */
- public function getReason() {
- return $this->mReason;
- }
-
- /**
- * Set the reason for creating the block
- *
- * @since 1.33
- * @param string $reason
- */
- public function setReason( $reason ) {
- $this->mReason = $reason;
- }
-
- /**
- * Get whether the block hides the target's username
- *
- * @since 1.33
- * @return bool The block hides the username
- */
- public function getHideName() {
- return $this->mHideName;
- }
-
- /**
- * Set whether ths block hides the target's username
- *
- * @since 1.33
- * @param bool $hideName The block hides the username
- */
- public function setHideName( $hideName ) {
- $this->mHideName = $hideName;
- }
-
- /**
- * Get the system block type, if any
- * @since 1.29
- * @return string|null
- */
- public function getSystemBlockType() {
- return $this->systemBlockType;
- }
-
/**
* Get/set a flag determining whether the master is used for reads
*
: false;
}
- /**
- * Indicates that the block is a sitewide block. This means the user is
- * prohibited from editing any page on the site (other than their own talk
- * page).
- *
- * @since 1.33
- * @param null|bool $x
- * @return bool
- */
- public function isSitewide( $x = null ) {
- return wfSetVar( $this->isSitewide, $x );
- }
-
- /**
- * Get or set the flag indicating whether this block blocks the target from
- * creating an account. (Note that the flag may be overridden depending on
- * global configs.)
- *
- * @since 1.33
- * @param null|bool $x Value to set (if null, just get the property value)
- * @return bool Value of the property
- */
- public function isCreateAccountBlocked( $x = null ) {
- return wfSetVar( $this->blockCreateAccount, $x );
- }
-
- /**
- * Get or set the flag indicating whether this block blocks the target from
- * sending emails. (Note that the flag may be overridden depending on
- * global configs.)
- *
- * @since 1.33
- * @param null|bool $x Value to set (if null, just get the property value)
- * @return bool Value of the property
- */
- public function isEmailBlocked( $x = null ) {
- return wfSetVar( $this->mBlockEmail, $x );
- }
-
- /**
- * Get or set the flag indicating whether this block blocks the target from
- * editing their own user talk page. (Note that the flag may be overridden
- * depending on global configs.)
- *
- * @since 1.33
- * @param null|bool $x Value to set (if null, just get the property value)
- * @return bool Value of the property
- */
- public function isUsertalkEditAllowed( $x = null ) {
- return wfSetVar( $this->allowUsertalk, $x );
- }
-
- /**
- * Determine whether the Block prevents a given right. A right
- * may be blacklisted or whitelisted, or determined from a
- * property on the Block object. For certain rights, the property
- * may be overridden according to global configs.
- *
- * @since 1.33
- * @param string $right Right to check
- * @return bool|null null if unrecognized right or unset property
- */
- public function appliesToRight( $right ) {
- $config = RequestContext::getMain()->getConfig();
- $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
-
- $res = null;
- switch ( $right ) {
- case 'edit':
- // TODO: fix this case to return proper value
- $res = true;
- break;
- case 'createaccount':
- $res = $this->isCreateAccountBlocked();
- break;
- case 'sendemail':
- $res = $this->isEmailBlocked();
- break;
- case 'upload':
- // Until T6995 is completed
- $res = $this->isSitewide();
- break;
- case 'read':
- $res = false;
- break;
- case 'purge':
- $res = false;
- break;
- }
- if ( !$res && $blockDisablesLogin ) {
- // If a block would disable login, then it should
- // prevent any right that all users cannot do
- $anon = new User;
- $res = $anon->isAllowed( $right ) ? $res : true;
- }
-
- return $res;
- }
-
- /**
- * Get/set whether the Block prevents a given action
- *
- * @deprecated since 1.33, use appliesToRight to determine block
- * behaviour, and specific methods to get/set properties
- * @param string $action Action to check
- * @param bool|null $x Value for set, or null to just get value
- * @return bool|null Null for unrecognized rights.
- */
- public function prevents( $action, $x = null ) {
- $config = RequestContext::getMain()->getConfig();
- $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
- $blockAllowsUTEdit = $config->get( 'BlockAllowsUTEdit' );
-
- $res = null;
- switch ( $action ) {
- case 'edit':
- # For now... <evil laugh>
- $res = true;
- break;
- case 'createaccount':
- $res = wfSetVar( $this->blockCreateAccount, $x );
- break;
- case 'sendemail':
- $res = wfSetVar( $this->mBlockEmail, $x );
- break;
- case 'upload':
- // Until T6995 is completed
- $res = $this->isSitewide();
- break;
- case 'editownusertalk':
- // NOTE: this check is not reliable on partial blocks
- // since partially blocked users are always allowed to edit
- // their own talk page unless a restriction exists on the
- // page or User_talk: namespace
- wfSetVar( $this->allowUsertalk, $x === null ? null : !$x );
- $res = !$this->isUsertalkEditAllowed();
-
- // edit own user talk can be disabled by config
- if ( !$blockAllowsUTEdit ) {
- $res = true;
- }
- break;
- case 'read':
- $res = false;
- break;
- case 'purge':
- $res = false;
- break;
- }
- if ( !$res && $blockDisablesLogin ) {
- // If a block would disable login, then it should
- // prevent any action that all users cannot do
- $anon = new User;
- $res = $anon->isAllowed( $action ) ? $res : true;
- }
-
- return $res;
- }
-
/**
* Get the block name, but with autoblocked IPs hidden as per standard privacy policy
* @return string Text is escaped
}
/**
- * From an existing Block, get the target and the type of target.
- * Note that, except for null, it is always safe to treat the target
- * as a string; for User objects this will return User::__toString()
- * which in turn gives User::getName().
+ * @inheritDoc
*
- * @param string|int|User|null $target
- * @return array [ User|String|null, Block::TYPE_ constant|null ]
- */
- public static function parseTarget( $target ) {
- # We may have been through this before
- if ( $target instanceof User ) {
- if ( IP::isValid( $target->getName() ) ) {
- return [ $target, self::TYPE_IP ];
- } else {
- return [ $target, self::TYPE_USER ];
- }
- } elseif ( $target === null ) {
- return [ null, null ];
- }
-
- $target = trim( $target );
-
- if ( IP::isValid( $target ) ) {
- # We can still create a User if it's an IP address, but we need to turn
- # off validation checking (which would exclude IP addresses)
- return [
- User::newFromName( IP::sanitizeIP( $target ), false ),
- self::TYPE_IP
- ];
-
- } elseif ( IP::isValidRange( $target ) ) {
- # Can't create a User from an IP range
- return [ IP::sanitizeRange( $target ), self::TYPE_RANGE ];
- }
-
- # Consider the possibility that this is not a username at all
- # but actually an old subpage (T31797)
- if ( strpos( $target, '/' ) !== false ) {
- # An old subpage, drill down to the user behind it
- $target = explode( '/', $target )[0];
- }
-
- $userObj = User::newFromName( $target );
- if ( $userObj instanceof User ) {
- # Note that since numbers are valid usernames, a $target of "12345" will be
- # considered a User. If you want to pass a block ID, prepend a hash "#12345",
- # since hash characters are not valid in usernames or titles generally.
- return [ $userObj, self::TYPE_USER ];
-
- } elseif ( preg_match( '/^#\d+$/', $target ) ) {
- # Autoblock reference in the form "#12345"
- return [ substr( $target, 1 ), self::TYPE_AUTO ];
-
- } else {
- # WTF?
- return [ null, null ];
- }
- }
-
- /**
- * Get the type of target for this particular block. Autoblocks have whichever type
- * corresponds to their target, so to detect if a block is an autoblock, we have to
- * check the mAuto property instead.
- * @return int Block::TYPE_ constant, will never be TYPE_ID
+ * Autoblocks have whichever type corresponds to their target, so to detect if a block is an
+ * autoblock, we have to check the mAuto property instead.
*/
public function getType() {
return $this->mAuto
? self::TYPE_AUTO
- : $this->type;
- }
-
- /**
- * Get the target and target type for this particular Block. Note that for autoblocks,
- * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
- * in this situation.
- * @return array [ User|String, Block::TYPE_ constant ]
- * @todo FIXME: This should be an integral part of the Block member variables
- */
- public function getTargetAndType() {
- return [ $this->getTarget(), $this->getType() ];
- }
-
- /**
- * Get the target for this particular Block. Note that for autoblocks,
- * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
- * in this situation.
- * @return User|string
- */
- public function getTarget() {
- return $this->target;
- }
-
- /**
- * Get the block expiry time
- *
- * @since 1.19
- * @return string
- */
- public function getExpiry() {
- return $this->mExpiry;
- }
-
- /**
- * Set the block expiry time
- *
- * @since 1.33
- * @param string $expiry
- */
- public function setExpiry( $expiry ) {
- $this->mExpiry = $expiry;
- }
-
- /**
- * Get the timestamp indicating when the block was created
- *
- * @since 1.33
- * @return string
- */
- public function getTimestamp() {
- return $this->mTimestamp;
- }
-
- /**
- * Set the timestamp indicating when the block was created
- *
- * @since 1.33
- * @param string $timestamp
- */
- public function setTimestamp( $timestamp ) {
- $this->mTimestamp = $timestamp;
- }
-
- /**
- * Set the target for this block, and update $this->type accordingly
- * @param mixed $target
- */
- public function setTarget( $target ) {
- list( $this->target, $this->type ) = self::parseTarget( $target );
- }
-
- /**
- * Get the user who implemented this block
- * @return User User object. May name a foreign user.
- */
- public function getBlocker() {
- return $this->blocker;
- }
-
- /**
- * Set the user who implemented (or will implement) this block
- * @param User|string $user Local User object or username string
- */
- public function setBlocker( $user ) {
- if ( is_string( $user ) ) {
- $user = User::newFromName( $user, false );
- }
-
- if ( $user->isAnon() && User::isUsableName( $user->getName() ) ) {
- throw new InvalidArgumentException(
- 'Blocker must be a local user or a name that cannot be a local user'
- );
- }
-
- $this->blocker = $user;
+ : parent::getType();
}
/**
}
/**
- * Get the key and parameters for the corresponding error message.
+ * @inheritDoc
*
- * @since 1.22
- * @param IContextSource $context
- * @return array
+ * Build different messages for autoblocks and partial blocks.
*/
public function getPermissionsError( IContextSource $context ) {
$params = $this->getBlockErrorParams( $context );
$msg = 'blockedtext';
- if ( $this->getSystemBlockType() !== null ) {
- $msg = 'systemblockedtext';
- } elseif ( $this->mAuto ) {
+ if ( $this->mAuto ) {
$msg = 'autoblockedtext';
} elseif ( !$this->isSitewide() ) {
$msg = 'blockedtext-partial';
return $params;
}
- /**
- * Get block information used in different block error messages
- *
- * @since 1.33
- * @param IContextSource $context
- * @return array
- */
- public function getBlockErrorParams( IContextSource $context ) {
- $blocker = $this->getBlocker();
- if ( $blocker instanceof User ) { // local user
- $blockerUserpage = $blocker->getUserPage();
- $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
- } else { // foreign user
- $link = $blocker;
- }
-
- $reason = $this->getReason();
- if ( $reason == '' ) {
- $reason = $context->msg( 'blockednoreason' )->text();
- }
-
- /* $ip returns who *is* being blocked, $intended contains who was meant to be blocked.
- * This could be a username, an IP range, or a single IP. */
- $intended = $this->getTarget();
- $systemBlockType = $this->getSystemBlockType();
- $lang = $context->getLanguage();
-
- return [
- $link,
- $reason,
- $context->getRequest()->getIP(),
- $this->getByName(),
- $systemBlockType ?? $this->getId(),
- $lang->formatExpiry( $this->getExpiry() ),
- (string)$intended,
- $lang->userTimeAndDate( $this->getTimestamp(), $context->getUser() ),
- ];
- }
-
/**
* Get Restrictions.
*
}
/**
- * Determine whether the block allows the user to edit their own
- * user talk page. This is done separately from Block::appliesToRight
- * because there is no right for editing one's own user talk page
- * and because the user's talk page needs to be passed into the
- * Block object, which is unaware of the user.
- *
- * The ipb_allow_usertalk flag (which corresponds to the property
- * allowUsertalk) is used on sitewide blocks and partial blocks
- * that contain a namespace restriction on the user talk namespace,
- * but do not contain a page restriction on the user's talk page.
- * For all other (i.e. most) partial blocks, the flag is ignored,
- * and the user can always edit their user talk page unless there
- * is a page restriction on their user talk page, in which case
- * they can never edit it. (Ideally the flag would be stored as
- * null in these cases, but the database field isn't nullable.)
- *
- * This method does not validate that the passed in talk page belongs to the
- * block target since the target (an IP) might not be the same as the user's
- * talk page (if they are logged in).
- *
- * @since 1.33
- * @param Title|null $usertalk The user's user talk page. If null,
- * and if the target is a User, the target's userpage is used
- * @return bool The user can edit their talk page
- */
- public function appliesToUsertalk( Title $usertalk = null ) {
- if ( !$usertalk ) {
- if ( $this->target instanceof User ) {
- $usertalk = $this->target->getTalkPage();
- } else {
- throw new InvalidArgumentException(
- '$usertalk must be provided if block target is not a user/IP'
- );
- }
- }
-
- if ( $usertalk->getNamespace() !== NS_USER_TALK ) {
- throw new InvalidArgumentException(
- '$usertalk must be a user talk page'
- );
- }
-
- if ( !$this->isSitewide() ) {
- if ( $this->appliesToPage( $usertalk->getArticleID() ) ) {
- return true;
- }
- if ( !$this->appliesToNamespace( NS_USER_TALK ) ) {
- return false;
- }
- }
-
- // This is a type of block which uses the ipb_allow_usertalk
- // flag. The flag can still be overridden by global configs.
- $config = RequestContext::getMain()->getConfig();
- if ( !$config->get( 'BlockAllowsUTEdit' ) ) {
- return true;
- }
- return !$this->isUsertalkEditAllowed();
- }
-
- /**
- * Checks if a block applies to a particular title
- *
- * This check does not consider whether `$this->isUsertalkEditAllowed`
- * returns false, as the identity of the user making the hypothetical edit
- * isn't known here (particularly in the case of IP hardblocks, range
- * blocks, and auto-blocks).
- *
- * @param Title $title
- * @return bool
+ * @inheritDoc
*/
public function appliesToTitle( Title $title ) {
if ( $this->isSitewide() ) {
}
/**
- * Checks if a block applies to a particular namespace
- *
- * @since 1.33
- *
- * @param int $ns
- * @return bool
+ * @inheritDoc
*/
public function appliesToNamespace( $ns ) {
if ( $this->isSitewide() ) {
}
/**
- * Checks if a block applies to a particular page
- *
- * This check does not consider whether `$this->isUsertalkEditAllowed`
- * returns false, as the identity of the user making the hypothetical edit
- * isn't known here (particularly in the case of IP hardblocks, range
- * blocks, and auto-blocks).
- *
- * @since 1.33
- *
- * @param int $pageId
- * @return bool
+ * @inheritDoc
*/
public function appliesToPage( $pageId ) {
if ( $this->isSitewide() ) {
}
/**
- * Check if the block should be tracked with a cookie.
- *
- * @since 1.33
- * @param bool $isAnon The user is logged out
- * @return bool The block should be tracked with a cookie
+ * @inheritDoc
*/
public function shouldTrackWithCookie( $isAnon ) {
$config = RequestContext::getMain()->getConfig();
}
}
- /**
- * Check if the block prevents a user from resetting their password
- *
- * @since 1.33
- * @return bool The block blocks password reset
- */
- public function appliesToPasswordReset() {
- switch ( $this->getSystemBlockType() ) {
- case null:
- case 'global-block':
- return $this->isCreateAccountBlocked();
- case 'proxy':
- return true;
- case 'dnsbl':
- case 'wgSoftBlockRanges':
- return false;
- default:
- return true;
- }
- }
-
/**
* Get a BlockRestrictionStore instance
*
* @file
*/
+use MediaWiki\Block\AbstractBlock;
use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\IDatabase;
* @param Block $block The block used to generate the ApiUsageException
* @throws ApiUsageException always
*/
- public function dieBlocked( Block $block ) {
+ public function dieBlocked( AbstractBlock $block ) {
// Die using the appropriate message depending on block type
if ( $block->getType() == Block::TYPE_AUTO ) {
$this->dieWithError(
* @file
*/
+use MediaWiki\Block\AbstractBlock;
+use MediaWiki\Block\SystemBlock;
+
/**
* @ingroup API
*/
* - blockexpiry - expiry time of the block
* - systemblocktype - system block type, if any
*/
- private function getBlockInfo( Block $block ) {
+ private function getBlockInfo( AbstractBlock $block ) {
$vals = [];
$vals['blockid'] = $block->getId();
$vals['blockedby'] = $block->getByName();
$vals['blockedtimestamp'] = wfTimestamp( TS_ISO_8601, $block->getTimestamp() );
$vals['blockexpiry'] = ApiResult::formatExpiry( $block->getExpiry(), 'infinite' );
$vals['blockpartial'] = !$block->isSitewide();
- if ( $block->getSystemBlockType() !== null ) {
+ if ( $block instanceof SystemBlock ) {
$vals['systemblocktype'] = $block->getSystemBlockType();
}
return $vals;
namespace MediaWiki\Block;
+use IContextSource;
+use InvalidArgumentException;
+use IP;
+use RequestContext;
+use Title;
+use User;
+
/**
- * @since 1.34
+ * @since 1.34 Factored out from Block.
*/
abstract class AbstractBlock {
+ /** @var string */
+ public $mReason;
+
+ /** @var string */
+ public $mTimestamp;
+
+ /** @var string */
+ public $mExpiry = '';
+
+ /** @var bool */
+ protected $mBlockEmail = false;
+
+ /** @var bool */
+ protected $allowUsertalk = false;
+
+ /** @var bool */
+ protected $blockCreateAccount = false;
+
+ /** @var bool */
+ public $mHideName = false;
+
+ /** @var User|string */
+ protected $target;
+
+ /**
+ * @var int Block::TYPE_ constant. After the block has been loaded
+ * from the database, this can only be USER, IP or RANGE.
+ */
+ protected $type;
+
+ /** @var User */
+ protected $blocker;
+
+ /** @var bool */
+ protected $isSitewide = true;
+
+ # TYPE constants
+ const TYPE_USER = 1;
+ const TYPE_IP = 2;
+ const TYPE_RANGE = 3;
+ const TYPE_AUTO = 4;
+ const TYPE_ID = 5;
+
+ /**
+ * Create a new block with specified parameters on a user, IP or IP range.
+ *
+ * @param array $options Parameters of the block:
+ * address string|User Target user name, User object, IP address or IP range
+ * by int User ID of the blocker
+ * reason string Reason of the block
+ * timestamp string The time at which the block comes into effect
+ * byText string Username of the blocker (for foreign users)
+ */
+ function __construct( $options = [] ) {
+ $defaults = [
+ 'address' => '',
+ 'by' => null,
+ 'reason' => '',
+ 'timestamp' => '',
+ 'byText' => '',
+ ];
+
+ $options += $defaults;
+
+ $this->setTarget( $options['address'] );
+
+ if ( $options['by'] ) {
+ # Local user
+ $this->setBlocker( User::newFromId( $options['by'] ) );
+ } else {
+ # Foreign user
+ $this->setBlocker( $options['byText'] );
+ }
+
+ $this->setReason( $options['reason'] );
+ $this->setTimestamp( wfTimestamp( TS_MW, $options['timestamp'] ) );
+ }
+
+ /**
+ * Get the user id of the blocking sysop
+ *
+ * @return int (0 for foreign users)
+ */
+ public function getBy() {
+ return $this->getBlocker()->getId();
+ }
+
+ /**
+ * Get the username of the blocking sysop
+ *
+ * @return string
+ */
+ public function getByName() {
+ return $this->getBlocker()->getName();
+ }
+
+ /**
+ * Get the block ID
+ * @return int|null
+ */
+ public function getId() {
+ return null;
+ }
+
+ /**
+ * Get the reason given for creating the block
+ *
+ * @since 1.33
+ * @return string
+ */
+ public function getReason() {
+ return $this->mReason;
+ }
+
+ /**
+ * Set the reason for creating the block
+ *
+ * @since 1.33
+ * @param string $reason
+ */
+ public function setReason( $reason ) {
+ $this->mReason = $reason;
+ }
+
+ /**
+ * Get whether the block hides the target's username
+ *
+ * @since 1.33
+ * @return bool The block hides the username
+ */
+ public function getHideName() {
+ return $this->mHideName;
+ }
+
+ /**
+ * Set whether ths block hides the target's username
+ *
+ * @since 1.33
+ * @param bool $hideName The block hides the username
+ */
+ public function setHideName( $hideName ) {
+ $this->mHideName = $hideName;
+ }
+
+ /**
+ * Indicates that the block is a sitewide block. This means the user is
+ * prohibited from editing any page on the site (other than their own talk
+ * page).
+ *
+ * @since 1.33
+ * @param null|bool $x
+ * @return bool
+ */
+ public function isSitewide( $x = null ) {
+ return wfSetVar( $this->isSitewide, $x );
+ }
+
+ /**
+ * Get or set the flag indicating whether this block blocks the target from
+ * creating an account. (Note that the flag may be overridden depending on
+ * global configs.)
+ *
+ * @since 1.33
+ * @param null|bool $x Value to set (if null, just get the property value)
+ * @return bool Value of the property
+ */
+ public function isCreateAccountBlocked( $x = null ) {
+ return wfSetVar( $this->blockCreateAccount, $x );
+ }
+
+ /**
+ * Get or set the flag indicating whether this block blocks the target from
+ * sending emails. (Note that the flag may be overridden depending on
+ * global configs.)
+ *
+ * @since 1.33
+ * @param null|bool $x Value to set (if null, just get the property value)
+ * @return bool Value of the property
+ */
+ public function isEmailBlocked( $x = null ) {
+ return wfSetVar( $this->mBlockEmail, $x );
+ }
+
+ /**
+ * Get or set the flag indicating whether this block blocks the target from
+ * editing their own user talk page. (Note that the flag may be overridden
+ * depending on global configs.)
+ *
+ * @since 1.33
+ * @param null|bool $x Value to set (if null, just get the property value)
+ * @return bool Value of the property
+ */
+ public function isUsertalkEditAllowed( $x = null ) {
+ return wfSetVar( $this->allowUsertalk, $x );
+ }
+
+ /**
+ * Determine whether the Block prevents a given right. A right
+ * may be blacklisted or whitelisted, or determined from a
+ * property on the Block object. For certain rights, the property
+ * may be overridden according to global configs.
+ *
+ * @since 1.33
+ * @param string $right Right to check
+ * @return bool|null null if unrecognized right or unset property
+ */
+ public function appliesToRight( $right ) {
+ $config = RequestContext::getMain()->getConfig();
+ $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
+
+ $res = null;
+ switch ( $right ) {
+ case 'edit':
+ // TODO: fix this case to return proper value
+ $res = true;
+ break;
+ case 'createaccount':
+ $res = $this->isCreateAccountBlocked();
+ break;
+ case 'sendemail':
+ $res = $this->isEmailBlocked();
+ break;
+ case 'upload':
+ // Until T6995 is completed
+ $res = $this->isSitewide();
+ break;
+ case 'read':
+ $res = false;
+ break;
+ case 'purge':
+ $res = false;
+ break;
+ }
+ if ( !$res && $blockDisablesLogin ) {
+ // If a block would disable login, then it should
+ // prevent any right that all users cannot do
+ $anon = new User;
+ $res = $anon->isAllowed( $right ) ? $res : true;
+ }
+
+ return $res;
+ }
+
+ /**
+ * Get/set whether the Block prevents a given action
+ *
+ * @deprecated since 1.33, use appliesToRight to determine block
+ * behaviour, and specific methods to get/set properties
+ * @param string $action Action to check
+ * @param bool|null $x Value for set, or null to just get value
+ * @return bool|null Null for unrecognized rights.
+ */
+ public function prevents( $action, $x = null ) {
+ $config = RequestContext::getMain()->getConfig();
+ $blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
+ $blockAllowsUTEdit = $config->get( 'BlockAllowsUTEdit' );
+
+ $res = null;
+ switch ( $action ) {
+ case 'edit':
+ # For now... <evil laugh>
+ $res = true;
+ break;
+ case 'createaccount':
+ $res = wfSetVar( $this->blockCreateAccount, $x );
+ break;
+ case 'sendemail':
+ $res = wfSetVar( $this->mBlockEmail, $x );
+ break;
+ case 'upload':
+ // Until T6995 is completed
+ $res = $this->isSitewide();
+ break;
+ case 'editownusertalk':
+ // NOTE: this check is not reliable on partial blocks
+ // since partially blocked users are always allowed to edit
+ // their own talk page unless a restriction exists on the
+ // page or User_talk: namespace
+ wfSetVar( $this->allowUsertalk, $x === null ? null : !$x );
+ $res = !$this->isUsertalkEditAllowed();
+
+ // edit own user talk can be disabled by config
+ if ( !$blockAllowsUTEdit ) {
+ $res = true;
+ }
+ break;
+ case 'read':
+ $res = false;
+ break;
+ case 'purge':
+ $res = false;
+ break;
+ }
+ if ( !$res && $blockDisablesLogin ) {
+ // If a block would disable login, then it should
+ // prevent any action that all users cannot do
+ $anon = new User;
+ $res = $anon->isAllowed( $action ) ? $res : true;
+ }
+
+ return $res;
+ }
+
+ /**
+ * From an existing Block, get the target and the type of target.
+ * Note that, except for null, it is always safe to treat the target
+ * as a string; for User objects this will return User::__toString()
+ * which in turn gives User::getName().
+ *
+ * @param string|int|User|null $target
+ * @return array [ User|String|null, Block::TYPE_ constant|null ]
+ */
+ public static function parseTarget( $target ) {
+ # We may have been through this before
+ if ( $target instanceof User ) {
+ if ( IP::isValid( $target->getName() ) ) {
+ return [ $target, self::TYPE_IP ];
+ } else {
+ return [ $target, self::TYPE_USER ];
+ }
+ } elseif ( $target === null ) {
+ return [ null, null ];
+ }
+
+ $target = trim( $target );
+
+ if ( IP::isValid( $target ) ) {
+ # We can still create a User if it's an IP address, but we need to turn
+ # off validation checking (which would exclude IP addresses)
+ return [
+ User::newFromName( IP::sanitizeIP( $target ), false ),
+ self::TYPE_IP
+ ];
+
+ } elseif ( IP::isValidRange( $target ) ) {
+ # Can't create a User from an IP range
+ return [ IP::sanitizeRange( $target ), self::TYPE_RANGE ];
+ }
+
+ # Consider the possibility that this is not a username at all
+ # but actually an old subpage (T31797)
+ if ( strpos( $target, '/' ) !== false ) {
+ # An old subpage, drill down to the user behind it
+ $target = explode( '/', $target )[0];
+ }
+
+ $userObj = User::newFromName( $target );
+ if ( $userObj instanceof User ) {
+ # Note that since numbers are valid usernames, a $target of "12345" will be
+ # considered a User. If you want to pass a block ID, prepend a hash "#12345",
+ # since hash characters are not valid in usernames or titles generally.
+ return [ $userObj, self::TYPE_USER ];
+
+ } elseif ( preg_match( '/^#\d+$/', $target ) ) {
+ # Autoblock reference in the form "#12345"
+ return [ substr( $target, 1 ), self::TYPE_AUTO ];
+
+ } else {
+ return [ null, null ];
+ }
+ }
+
+ /**
+ * Get the type of target for this particular block.
+ * @return int Block::TYPE_ constant, will never be TYPE_ID
+ */
+ public function getType() {
+ return $this->type;
+ }
+
+ /**
+ * Get the target and target type for this particular Block. Note that for autoblocks,
+ * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
+ * in this situation.
+ * @return array [ User|String, Block::TYPE_ constant ]
+ * @todo FIXME: This should be an integral part of the Block member variables
+ */
+ public function getTargetAndType() {
+ return [ $this->getTarget(), $this->getType() ];
+ }
+
+ /**
+ * Get the target for this particular Block. Note that for autoblocks,
+ * this returns the unredacted name; frontend functions need to call $block->getRedactedName()
+ * in this situation.
+ * @return User|string
+ */
+ public function getTarget() {
+ return $this->target;
+ }
+
+ /**
+ * Get the block expiry time
+ *
+ * @since 1.19
+ * @return string
+ */
+ public function getExpiry() {
+ return $this->mExpiry;
+ }
+
+ /**
+ * Set the block expiry time
+ *
+ * @since 1.33
+ * @param string $expiry
+ */
+ public function setExpiry( $expiry ) {
+ $this->mExpiry = $expiry;
+ }
+
+ /**
+ * Get the timestamp indicating when the block was created
+ *
+ * @since 1.33
+ * @return string
+ */
+ public function getTimestamp() {
+ return $this->mTimestamp;
+ }
+
+ /**
+ * Set the timestamp indicating when the block was created
+ *
+ * @since 1.33
+ * @param string $timestamp
+ */
+ public function setTimestamp( $timestamp ) {
+ $this->mTimestamp = $timestamp;
+ }
+
+ /**
+ * Set the target for this block, and update $this->type accordingly
+ * @param mixed $target
+ */
+ public function setTarget( $target ) {
+ list( $this->target, $this->type ) = static::parseTarget( $target );
+ }
+
+ /**
+ * Get the user who implemented this block
+ * @return User User object. May name a foreign user.
+ */
+ public function getBlocker() {
+ return $this->blocker;
+ }
+
+ /**
+ * Set the user who implemented (or will implement) this block
+ * @param User|string $user Local User object or username string
+ */
+ public function setBlocker( $user ) {
+ if ( is_string( $user ) ) {
+ $user = User::newFromName( $user, false );
+ }
+
+ if ( $user->isAnon() && User::isUsableName( $user->getName() ) ) {
+ throw new InvalidArgumentException(
+ 'Blocker must be a local user or a name that cannot be a local user'
+ );
+ }
+
+ $this->blocker = $user;
+ }
+
+ /**
+ * Get the key and parameters for the corresponding error message.
+ *
+ * @since 1.22
+ * @param IContextSource $context
+ * @return array
+ */
+ abstract public function getPermissionsError( IContextSource $context );
+
+ /**
+ * Get block information used in different block error messages
+ *
+ * @since 1.33
+ * @param IContextSource $context
+ * @return array
+ */
+ public function getBlockErrorParams( IContextSource $context ) {
+ $blocker = $this->getBlocker();
+ if ( $blocker instanceof User ) { // local user
+ $blockerUserpage = $blocker->getUserPage();
+ $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
+ } else { // foreign user
+ $link = $blocker;
+ }
+
+ $reason = $this->getReason();
+ if ( $reason == '' ) {
+ $reason = $context->msg( 'blockednoreason' )->text();
+ }
+
+ /* $ip returns who *is* being blocked, $intended contains who was meant to be blocked.
+ * This could be a username, an IP range, or a single IP. */
+ $intended = $this->getTarget();
+ $lang = $context->getLanguage();
+
+ return [
+ $link,
+ $reason,
+ $context->getRequest()->getIP(),
+ $this->getByName(),
+ // TODO: SystemBlock replaces this with the system block type. Clean up
+ // error params so that this is not necessary.
+ $this->getId(),
+ $lang->formatExpiry( $this->getExpiry() ),
+ (string)$intended,
+ $lang->userTimeAndDate( $this->getTimestamp(), $context->getUser() ),
+ ];
+ }
+
+ /**
+ * Determine whether the block allows the user to edit their own
+ * user talk page. This is done separately from Block::appliesToRight
+ * because there is no right for editing one's own user talk page
+ * and because the user's talk page needs to be passed into the
+ * Block object, which is unaware of the user.
+ *
+ * The ipb_allow_usertalk flag (which corresponds to the property
+ * allowUsertalk) is used on sitewide blocks and partial blocks
+ * that contain a namespace restriction on the user talk namespace,
+ * but do not contain a page restriction on the user's talk page.
+ * For all other (i.e. most) partial blocks, the flag is ignored,
+ * and the user can always edit their user talk page unless there
+ * is a page restriction on their user talk page, in which case
+ * they can never edit it. (Ideally the flag would be stored as
+ * null in these cases, but the database field isn't nullable.)
+ *
+ * This method does not validate that the passed in talk page belongs to the
+ * block target since the target (an IP) might not be the same as the user's
+ * talk page (if they are logged in).
+ *
+ * @since 1.33
+ * @param Title|null $usertalk The user's user talk page. If null,
+ * and if the target is a User, the target's userpage is used
+ * @return bool The user can edit their talk page
+ */
+ public function appliesToUsertalk( Title $usertalk = null ) {
+ if ( !$usertalk ) {
+ if ( $this->target instanceof User ) {
+ $usertalk = $this->target->getTalkPage();
+ } else {
+ throw new InvalidArgumentException(
+ '$usertalk must be provided if block target is not a user/IP'
+ );
+ }
+ }
+
+ if ( $usertalk->getNamespace() !== NS_USER_TALK ) {
+ throw new InvalidArgumentException(
+ '$usertalk must be a user talk page'
+ );
+ }
+
+ if ( !$this->isSitewide() ) {
+ if ( $this->appliesToPage( $usertalk->getArticleID() ) ) {
+ return true;
+ }
+ if ( !$this->appliesToNamespace( NS_USER_TALK ) ) {
+ return false;
+ }
+ }
+
+ // This is a type of block which uses the ipb_allow_usertalk
+ // flag. The flag can still be overridden by global configs.
+ $config = RequestContext::getMain()->getConfig();
+ if ( !$config->get( 'BlockAllowsUTEdit' ) ) {
+ return true;
+ }
+ return !$this->isUsertalkEditAllowed();
+ }
+
+ /**
+ * Checks if a block applies to a particular title
+ *
+ * This check does not consider whether `$this->isUsertalkEditAllowed`
+ * returns false, as the identity of the user making the hypothetical edit
+ * isn't known here (particularly in the case of IP hardblocks, range
+ * blocks, and auto-blocks).
+ *
+ * @param Title $title
+ * @return bool
+ */
+ public function appliesToTitle( Title $title ) {
+ return $this->isSitewide();
+ }
+
+ /**
+ * Checks if a block applies to a particular namespace
+ *
+ * @since 1.33
+ *
+ * @param int $ns
+ * @return bool
+ */
+ public function appliesToNamespace( $ns ) {
+ return $this->isSitewide();
+ }
+
+ /**
+ * Checks if a block applies to a particular page
+ *
+ * This check does not consider whether `$this->isUsertalkEditAllowed`
+ * returns false, as the identity of the user making the hypothetical edit
+ * isn't known here (particularly in the case of IP hardblocks, range
+ * blocks, and auto-blocks).
+ *
+ * @since 1.33
+ *
+ * @param int $pageId
+ * @return bool
+ */
+ public function appliesToPage( $pageId ) {
+ return $this->isSitewide();
+ }
+
+ /**
+ * Check if the block should be tracked with a cookie.
+ *
+ * @since 1.33
+ * @param bool $isAnon The user is logged out
+ * @return bool The block should be tracked with a cookie
+ */
+ public function shouldTrackWithCookie( $isAnon ) {
+ return false;
+ }
+
+ /**
+ * Check if the block prevents a user from resetting their password
+ *
+ * @since 1.33
+ * @return bool The block blocks password reset
+ */
+ public function appliesToPasswordReset() {
+ return $this->isCreateAccountBlocked();
+ }
+
}
use Block;
use IP;
+use MediaWiki\User\UserIdentity;
use User;
use WebRequest;
use Wikimedia\IPSet;
-use MediaWiki\User\UserIdentity;
/**
* A service class for checking blocks.
$block = Block::newFromTarget( $user, $ip, !$fromReplica );
// Cookie blocking
- if ( !$block instanceof Block ) {
+ if ( !$block instanceof AbstractBlock ) {
$block = $this->getBlockFromCookieValue( $user, $request );
}
// Proxy blocking
- if ( !$block instanceof Block && $ip !== null && !in_array( $ip, $this->proxyWhitelist ) ) {
+ if ( !$block instanceof AbstractBlock
+ && $ip !== null
+ && !in_array( $ip, $this->proxyWhitelist )
+ ) {
// Local list
if ( $this->isLocallyBlockedProxy( $ip ) ) {
- $block = new Block( [
+ $block = new SystemBlock( [
'byText' => wfMessage( 'proxyblocker' )->text(),
'reason' => wfMessage( 'proxyblockreason' )->plain(),
'address' => $ip,
'systemBlock' => 'proxy',
] );
} elseif ( $isAnon && $this->isDnsBlacklisted( $ip ) ) {
- $block = new Block( [
+ $block = new SystemBlock( [
'byText' => wfMessage( 'sorbs' )->text(),
'reason' => wfMessage( 'sorbsreason' )->plain(),
'address' => $ip,
}
// (T25343) Apply IP blocks to the contents of XFF headers, if enabled
- if ( !$block instanceof Block
+ if ( !$block instanceof AbstractBlock
&& $this->applyIpBlocksToXff
&& $ip !== null
&& !in_array( $ip, $this->proxyWhitelist )
$xffblocks = Block::getBlocksForIPList( $xff, $isAnon, !$fromReplica );
// TODO: remove dependency on Block
$block = Block::chooseBlock( $xffblocks, $xff );
- if ( $block instanceof Block ) {
+ if ( $block instanceof AbstractBlock ) {
# 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
+ if ( !$block instanceof AbstractBlock
&& $ip !== null
&& $isAnon
&& IP::isInRanges( $ip, $this->softBlockRanges )
) {
- $block = new Block( [
+ $block = new SystemBlock( [
'address' => $ip,
'byText' => 'MediaWiki default',
'reason' => wfMessage( 'softblockrangesreason', $ip )->plain(),
--- /dev/null
+<?php
+/**
+ * Class for temporary blocks created on enforcement.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+namespace MediaWiki\Block;
+
+use IContextSource;
+
+/**
+ * System blocks are temporary blocks that are created on enforcement (e.g.
+ * from IP blacklists) and are not saved to the database. The target of a
+ * system block is an IP address. System blocks do not give rise to
+ * autoblocks and are not tracked with cookies.
+ *
+ * @since 1.34
+ */
+class SystemBlock extends AbstractBlock {
+ /** @var string|null */
+ private $systemBlockType;
+
+ /**
+ * Create a new block with specified parameters on a user, IP or IP range.
+ *
+ * @param array $options Parameters of the block:
+ * systemBlock string Indicate that this block is automatically
+ * created by MediaWiki rather than being stored
+ * in the database. Value is a string to return
+ * from self::getSystemBlockType().
+ */
+ function __construct( $options = [] ) {
+ parent::__construct( $options );
+
+ $defaults = [
+ 'systemBlock' => null,
+ ];
+
+ $options += $defaults;
+
+ $this->systemBlockType = $options['systemBlock'];
+ }
+
+ /**
+ * Get the system block type, if any. A SystemBlock can have the following types:
+ * - 'proxy': the IP is blacklisted in $wgProxyList
+ * - 'dnsbl': the IP is associated with a blacklisted domain in $wgDnsBlacklistUrls
+ * - 'wgSoftBlockRanges': the IP is covered by $wgSoftBlockRanges
+ * - 'global-block': for backwards compatability with the UserIsBlockedGlobally hook
+ *
+ * @since 1.29
+ * @return string|null
+ */
+ public function getSystemBlockType() {
+ return $this->systemBlockType;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getPermissionsError( IContextSource $context ) {
+ $params = $this->getBlockErrorParams( $context );
+ // TODO: Clean up error messages params so we don't have to do this
+ $params[ 4 ] = $this->getSystemBlockType();
+
+ $msg = 'systemblockedtext';
+
+ array_unshift( $params, $msg );
+
+ return $params;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function appliesToPasswordReset() {
+ switch ( $this->getSystemBlockType() ) {
+ case null:
+ case 'global-block':
+ return $this->isCreateAccountBlocked();
+ case 'proxy':
+ return true;
+ case 'dnsbl':
+ case 'wgSoftBlockRanges':
+ return false;
+ default:
+ return true;
+ }
+ }
+
+}
* @file
*/
+use MediaWiki\Block\AbstractBlock;
+
/**
* Show an error when the user tries to do something whilst blocked.
*
* @ingroup Exception
*/
class UserBlockedError extends ErrorPageError {
- public function __construct( Block $block ) {
+ public function __construct( AbstractBlock $block ) {
// @todo FIXME: Implement a more proper way to get context here.
$params = $block->getPermissionsError( RequestContext::getMain() );
parent::__construct( 'blockedtitle', array_shift( $params ), $params );
* @file
*/
+use MediaWiki\Block\AbstractBlock;
+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 */
$fromReplica
);
- if ( $block instanceof Block ) {
+ if ( $block instanceof AbstractBlock ) {
wfDebug( __METHOD__ . ": Found block.\n" );
$this->mBlock = $block;
$this->mBlockedby = $block->getByName();
* @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'
] );
/**
* Get whether the user is explicitly blocked from account creation.
- * @return bool|Block
+ * @return bool|AbstractBlock
*/
public function isBlockedFromCreateAccount() {
$this->getBlockedStatus();
if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
$this->mBlockedFromCreateAccount = Block::newFromTarget( null, $this->getRequest()->getIP() );
}
- return $this->mBlockedFromCreateAccount instanceof Block
+ return $this->mBlockedFromCreateAccount instanceof AbstractBlock
&& $this->mBlockedFromCreateAccount->appliesToRight( 'createaccount' )
? $this->mBlockedFromCreateAccount
: false;
);
}
- /**
- * @covers Block::getSystemBlockType
- * @covers Block::insert
- * @covers Block::doAutoblock
- */
- public function testSystemBlocks() {
- $user = $this->getUserForBlocking();
- $this->addBlockForUser( $user );
-
- $blockOptions = [
- 'address' => $user->getName(),
- 'reason' => 'test system block',
- 'timestamp' => wfTimestampNow(),
- 'expiry' => $this->db->getInfinity(),
- 'byText' => 'MediaWiki default',
- 'systemBlock' => 'test',
- 'enableAutoblock' => true,
- ];
- $block = new Block( $blockOptions );
-
- $this->assertSame( 'test', $block->getSystemBlockType() );
-
- try {
- $block->insert();
- $this->fail( 'Expected exception not thrown' );
- } catch ( MWException $ex ) {
- $this->assertSame( 'Cannot insert a system block into the database', $ex->getMessage() );
- }
-
- try {
- $block->doAutoblock( '192.0.2.2' );
- $this->fail( 'Expected exception not thrown' );
- } catch ( MWException $ex ) {
- $this->assertSame( 'Cannot autoblock from a system block', $ex->getMessage() );
- }
- }
-
/**
* @covers Block::newFromRow
*/
use User;
use MediaWiki\Block\Restriction\NamespaceRestriction;
use MediaWiki\Block\Restriction\PageRestriction;
+use MediaWiki\Block\SystemBlock;
use MediaWiki\MediaWikiServices;
use MediaWiki\Permissions\PermissionManager;
# $user->mBlock->mExpiry == 'infinity'
$this->user->mBlockedby = $this->user->getName();
- $this->user->mBlock = new Block( [
+ $this->user->mBlock = new SystemBlock( [
'address' => '127.0.8.1',
'by' => $this->user->getId(),
'reason' => 'no reason given',
'timestamp' => $now,
'auto' => false,
- 'expiry' => 10,
'systemBlock' => 'test',
] );
$errors = [ [ 'systemblockedtext',
'[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
- 'Useruser', 'test', '23:00, 31 December 1969', '127.0.8.1',
+ 'Useruser', 'test', 'infinite', '127.0.8.1',
$wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
$this->assertEquals( $errors,
--- /dev/null
+<?php
+
+use MediaWiki\Block\SystemBlock;
+
+/**
+ * @group Blocking
+ * @coversDefaultClass \MediaWiki\Block\SystemBlock
+ */
+class SystemBlockTest extends MediaWikiLangTestCase {
+ /**
+ * @covers ::getSystemBlockType
+ */
+ public function testSystemBlockType() {
+ $block = new SystemBlock( [
+ 'systemBlock' => 'proxy',
+ ] );
+
+ $this->assertSame( 'proxy', $block->getSystemBlockType() );
+ }
+
+}
<?php
use MediaWiki\Block\Restriction\PageRestriction;
+use MediaWiki\Block\SystemBlock;
use MediaWiki\MediaWikiServices;
/**
# $user->mBlock->mExpiry == 'infinity'
$this->user->mBlockedby = $this->user->getName();
- $this->user->mBlock = new Block( [
+ $this->user->mBlock = new SystemBlock( [
'address' => '127.0.8.1',
'by' => $this->user->getId(),
'reason' => 'no reason given',
'timestamp' => $now,
- 'auto' => false,
- 'expiry' => 10,
'systemBlock' => 'test',
] );
$errors = [ [ 'systemblockedtext',
'[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
- 'Useruser', 'test', '23:00, 31 December 1969', '127.0.8.1',
+ 'Useruser', 'test', 'infinite', '127.0.8.1',
$wgLang->timeanddate( wfTimestamp( TS_MW, $now ), true ) ] ];
$this->assertEquals( $errors,
<?php
use Wikimedia\TestingAccessWrapper;
+use MediaWiki\Block\SystemBlock;
/**
* @covers ApiBlockInfoTrait
*/
class ApiBlockInfoTraitTest extends MediaWikiTestCase {
-
- public function testGetBlockInfo() {
- $block = new Block();
+ /**
+ * @dataProvider provideGetBlockInfo
+ */
+ public function testGetBlockInfo( $block, $expectedInfo ) {
$mock = $this->getMockForTrait( ApiBlockInfoTrait::class );
$info = TestingAccessWrapper::newFromObject( $mock )->getBlockInfo( $block );
- $subset = [
+ $subset = array_merge( [
'blockid' => null,
'blockedby' => '',
'blockedbyid' => 0,
'blockreason' => '',
'blockexpiry' => 'infinite',
- 'blockpartial' => false,
- ];
+ ], $expectedInfo );
$this->assertArraySubset( $subset, $info );
}
- public function testGetBlockInfoPartial() {
- $mock = $this->getMockForTrait( ApiBlockInfoTrait::class );
-
- $block = new Block( [
- 'sitewide' => false,
- ] );
- $info = TestingAccessWrapper::newFromObject( $mock )->getBlockInfo( $block );
- $subset = [
- 'blockid' => null,
- 'blockedby' => '',
- 'blockedbyid' => 0,
- 'blockreason' => '',
- 'blockexpiry' => 'infinite',
- 'blockpartial' => true,
+ public static function provideGetBlockInfo() {
+ return [
+ 'Sitewide block' => [
+ new Block(),
+ [ 'blockpartial' => false ],
+ ],
+ 'Partial block' => [
+ new Block( [ 'sitewide' => false ] ),
+ [ 'blockpartial' => true ],
+ ],
+ 'System block' => [
+ new SystemBlock( [ 'systemBlock' => 'proxy' ] ),
+ [ 'systemblocktype' => 'proxy' ]
+ ],
];
- $this->assertArraySubset( $subset, $info );
}
-
}
<?php
use MediaWiki\Auth\AuthManager;
+use MediaWiki\Block\SystemBlock;
/**
* @covers PasswordReset
'enableEmail' => true,
'allowsAuthenticationDataChange' => true,
'canEditPrivate' => true,
- 'block' => new Block( [ 'systemBlock' => 'proxy' ] ),
+ 'block' => new SystemBlock(
+ [ 'systemBlock' => 'proxy' ]
+ ),
'globalBlock' => null,
'isAllowed' => false,
],
- 'globally blocked with account creation disabled' => [
- 'passwordResetRoutes' => [ 'username' => true ],
- 'enableEmail' => true,
- 'allowsAuthenticationDataChange' => true,
- 'canEditPrivate' => true,
- 'block' => null,
- 'globalBlock' => new Block( [ 'systemBlock' => 'global-block', 'createAccount' => true ] ),
- 'isAllowed' => false,
- ],
'globally blocked with account creation not disabled' => [
'passwordResetRoutes' => [ 'username' => true ],
'enableEmail' => true,
'allowsAuthenticationDataChange' => true,
'canEditPrivate' => true,
'block' => null,
- 'globalBlock' => new Block( [ 'systemBlock' => 'global-block', 'createAccount' => false ] ),
+ 'globalBlock' => new SystemBlock(
+ [ 'systemBlock' => 'global-block' ]
+ ),
'isAllowed' => true,
],
'blocked via wgSoftBlockRanges' => [
'enableEmail' => true,
'allowsAuthenticationDataChange' => true,
'canEditPrivate' => true,
- 'block' => new Block( [ 'systemBlock' => 'wgSoftBlockRanges', 'anonOnly' => true ] ),
+ 'block' => new SystemBlock(
+ [ 'systemBlock' => 'wgSoftBlockRanges', 'anonOnly' => true ]
+ ),
'globalBlock' => null,
'isAllowed' => true,
],
'enableEmail' => true,
'allowsAuthenticationDataChange' => true,
'canEditPrivate' => true,
- 'block' => new Block( [ 'systemBlock' => 'unknown' ] ),
+ 'block' => new SystemBlock( [ 'systemBlock' => 'unknown' ] ),
'globalBlock' => null,
'isAllowed' => false,
],
use MediaWiki\Block\Restriction\PageRestriction;
use MediaWiki\Block\Restriction\NamespaceRestriction;
+use MediaWiki\Block\SystemBlock;
use MediaWiki\MediaWikiServices;
use MediaWiki\User\UserIdentityValue;
use Wikimedia\TestingAccessWrapper;
$request->setIP( '10.20.30.40' );
$setSessionUser( $wgUser, $request );
$block = $wgUser->getBlock();
- $this->assertInstanceOf( Block::class, $block );
+ $this->assertInstanceOf( SystemBlock::class, $block );
$this->assertSame( 'wgSoftBlockRanges', $block->getSystemBlockType() );
// Make sure the block is really soft