aboutsummaryrefslogtreecommitdiffstats
path: root/includes/block
diff options
context:
space:
mode:
authordaniel <dkinzler@wikimedia.org>2021-04-16 14:55:24 +0200
committerdaniel <dkinzler@wikimedia.org>2021-05-11 11:36:11 +0200
commit753b1bcaffa3b575d91b31ec20ba4fa420009813 (patch)
tree0ee7fd54706a4edc2979cac5e5a4f3c99f7c195d /includes/block
parentb6fea9934146a76fea1f887ab6022d53f7d30995 (diff)
downloadmediawikicore-753b1bcaffa3b575d91b31ec20ba4fa420009813.tar.gz
mediawikicore-753b1bcaffa3b575d91b31ec20ba4fa420009813.zip
Introduce Block interface and replace AbstractBlock.
In order to allow Authority to know about user blocks, we need a narrow interface to represent such blocks. This deprecates some methods on AbstractBlocks in favor of new methods on the Block interface that avoid binding to the User class. Bug: T271494 Change-Id: I7bb950533970984a014de0434518fbbefb695131
Diffstat (limited to 'includes/block')
-rw-r--r--includes/block/AbstractBlock.php58
-rw-r--r--includes/block/Block.php150
-rw-r--r--includes/block/BlockErrorFormatter.php29
-rw-r--r--includes/block/BlockPermissionChecker.php5
-rw-r--r--includes/block/BlockUser.php6
-rw-r--r--includes/block/CompositeBlock.php8
-rw-r--r--includes/block/DatabaseBlock.php8
-rw-r--r--includes/block/DatabaseBlockStore.php20
-rw-r--r--includes/block/SystemBlock.php9
-rw-r--r--includes/block/UnblockUser.php17
10 files changed, 248 insertions, 62 deletions
diff --git a/includes/block/AbstractBlock.php b/includes/block/AbstractBlock.php
index c56859b5f02c..49280ef4f168 100644
--- a/includes/block/AbstractBlock.php
+++ b/includes/block/AbstractBlock.php
@@ -34,7 +34,7 @@ use User;
* @note Extensions should not subclass this, as MediaWiki currently does not support custom block types.
* @since 1.34 Factored out from DatabaseBlock (previously Block).
*/
-abstract class AbstractBlock {
+abstract class AbstractBlock implements Block {
/** @var CommentStoreComment */
protected $reason;
@@ -80,14 +80,6 @@ abstract class AbstractBlock {
/** @var bool */
protected $isSitewide = true;
- # TYPE constants
- # Do not introduce negative constants without changing BlockUser command object.
- public const TYPE_USER = 1;
- public const TYPE_IP = 2;
- public const TYPE_RANGE = 3;
- public const TYPE_AUTO = 4;
- public const TYPE_ID = 5;
-
/**
* Create a new block with specified parameters on a user, IP or IP range.
*
@@ -139,15 +131,6 @@ abstract class AbstractBlock {
}
/**
- * Get the information that identifies this block, such that a user could
- * look up everything that can be found about this block. May be an ID,
- * array of IDs, type, etc.
- *
- * @return mixed Identifying information
- */
- abstract public function getIdentifier();
-
- /**
* Get the reason given for creating the block, as a string.
*
* Deprecated, since this gives the caller no control over the language
@@ -350,6 +333,9 @@ abstract class AbstractBlock {
*
* If the type is not null, it will be an AbstractBlock::TYPE_ constant.
*
+ * @deprecated since 1.37, use getTargetName() and getTargetUserIdentity()
+ * together with getType()
+ *
* @return array [ User|String|null, int|null ]
* @todo FIXME: This should be an integral part of the block member variables
*/
@@ -358,9 +344,11 @@ abstract class AbstractBlock {
}
/**
- * Get the target for this particular block. Note that for autoblocks,
+ * 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.
+ * @deprecated since 1.37, use getTargetName() and getTargetUserIdentity()
+ * together with getType()
* @return User|string|null
*/
public function getTarget() {
@@ -368,6 +356,38 @@ abstract class AbstractBlock {
}
/**
+ * @since 1.37
+ * @return ?UserIdentity
+ */
+ public function getTargetUserIdentity(): ?UserIdentity {
+ return $this->target instanceof UserIdentity ? $this->target : null;
+ }
+
+ /**
+ * @since 1.37
+ * @return string
+ */
+ public function getTargetName(): string {
+ return $this->target instanceof UserIdentity
+ ? $this->target->getName()
+ : (string)$this->target;
+ }
+
+ /**
+ * @param UserIdentity|string $target
+ *
+ * @return bool
+ * @since 1.37
+ */
+ public function isBlocking( $target ): bool {
+ $targetName = $target instanceof UserIdentity
+ ? $target->getName()
+ : (string)$target;
+
+ return $targetName === $this->getTargetName();
+ }
+
+ /**
* Get the block expiry time
*
* @since 1.19
diff --git a/includes/block/Block.php b/includes/block/Block.php
new file mode 100644
index 000000000000..523a23d3166a
--- /dev/null
+++ b/includes/block/Block.php
@@ -0,0 +1,150 @@
+<?php
+
+/**
+ * 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 CommentStoreComment;
+use MediaWiki\User\UserIdentity;
+
+/**
+ * Represents a block that may prevent users from performing specific operations.
+ * The block may apply to a specific user, to a network address, network range,
+ * or some other aspect of a web request.
+ * The block may apply to the entire site, or may be limited to specific pages
+ * or namespaces.
+ *
+ * @since 1.37 Extracted from the AbstractBlock base class,
+ * which was in turn factored out of DatabaseBlock in 1.34.
+ */
+interface Block {
+
+ # TYPE constants
+ # Do not introduce negative constants without changing BlockUser command object.
+ public const TYPE_USER = 1;
+ public const TYPE_IP = 2;
+ public const TYPE_RANGE = 3;
+ public const TYPE_AUTO = 4;
+ public const TYPE_ID = 5;
+
+ /**
+ * Get the block ID
+ * @return ?int
+ */
+ public function getId();
+
+ /**
+ * Get the information that identifies this block, such that a user could
+ * look up everything that can be found about this block. Typically a scalar ID (integer
+ * or string), but can also return a list of IDs, or an associative array encoding a composite
+ * ID. Must be safe to serialize as JSON.
+ *
+ * @return mixed Identifying information
+ */
+ public function getIdentifier();
+
+ /**
+ * Get the user who applied this block
+ *
+ * @return UserIdentity|null user identity or null. May be an external user.
+ */
+ public function getBlocker(): ?UserIdentity;
+
+ /**
+ * Get the reason for creating the block.
+ *
+ * @return CommentStoreComment
+ */
+ public function getReasonComment();
+
+ /**
+ * Get the UserIdentity identifying the blocked user,
+ * if the target is indeed a user (that is, if getType() returns TYPE_USER).
+ *
+ * @return ?UserIdentity
+ */
+ public function getTargetUserIdentity(): ?UserIdentity;
+
+ /**
+ * Return the name of the block target as a string.
+ * Depending on the type returned by get Type(), this could be a user name,
+ * an IP address or range, an internal ID, etc.
+ *
+ * @return string
+ */
+ public function getTargetName(): string;
+
+ /**
+ * Determines whether this block is blocking the given target (and only that target).
+ *
+ * @param UserIdentity|string $target
+ *
+ * @return bool
+ */
+ public function isBlocking( $target ): bool;
+
+ /**
+ * Get the block expiry time
+ *
+ * @return string
+ */
+ public function getExpiry();
+
+ /**
+ * Get the type of target for this particular block.
+ * @return int|null Block::TYPE_ constant, will never be TYPE_ID
+ */
+ public function getType();
+
+ /**
+ * Get the timestamp indicating when the block was created
+ *
+ * @return string
+ */
+ public function getTimestamp();
+
+ /**
+ * 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).
+ *
+ * @return bool
+ */
+ public function isSitewide();
+
+ /**
+ * Get the flag indicating whether this block blocks the target from
+ * creating an account. (Note that the flag may be overridden depending on
+ * global configs.)
+ *
+ * @return bool
+ */
+ public function isCreateAccountBlocked();
+
+ /**
+ * Returns whether the block is a hardblock (affects logged-in users on a given IP/range)
+ *
+ * Note that users are always hardblocked, since they're logged in by definition.
+ *
+ * @return bool
+ */
+ public function isHardblock();
+
+}
diff --git a/includes/block/BlockErrorFormatter.php b/includes/block/BlockErrorFormatter.php
index 9382f1edd54b..ca224f47a9a9 100644
--- a/includes/block/BlockErrorFormatter.php
+++ b/includes/block/BlockErrorFormatter.php
@@ -49,14 +49,14 @@ class BlockErrorFormatter {
* block features. Message parameters are formatted for the specified user and
* language.
*
- * @param AbstractBlock $block
+ * @param Block $block
* @param UserIdentity $user
* @param Language $language
* @param string $ip
* @return Message
*/
public function getMessage(
- AbstractBlock $block,
+ Block $block,
UserIdentity $user,
Language $language,
$ip
@@ -69,7 +69,7 @@ class BlockErrorFormatter {
/**
* Get a standard set of block details for building a block error message.
*
- * @param AbstractBlock $block
+ * @param Block $block
* @return mixed[]
* - identifier: Information for looking up the block
* - targetName: The target, as a string
@@ -79,12 +79,13 @@ class BlockErrorFormatter {
* - expiry: Expiry time
* - timestamp: Time the block was created
*/
- private function getBlockErrorInfo( AbstractBlock $block ) {
+ private function getBlockErrorInfo( Block $block ) {
+ $blocker = $block->getBlocker();
return [
'identifier' => $block->getIdentifier(),
- 'targetName' => (string)$block->getTarget(),
- 'blockerName' => $block->getByName(),
- 'blockerId' => $block->getBy(),
+ 'targetName' => $block->getTargetName(),
+ 'blockerName' => $blocker ? $blocker->getName() : '',
+ 'blockerId' => $blocker ? $blocker->getId() : 0,
'reason' => $block->getReasonComment(),
'expiry' => $block->getExpiry(),
'timestamp' => $block->getTimestamp(),
@@ -96,13 +97,13 @@ class BlockErrorFormatter {
* formatted for a specified user and language.
*
* @since 1.35
- * @param AbstractBlock $block
+ * @param Block $block
* @param UserIdentity $user
* @param Language $language
* @return mixed[] See getBlockErrorInfo
*/
private function getFormattedBlockErrorInfo(
- AbstractBlock $block,
+ Block $block,
UserIdentity $user,
Language $language
) {
@@ -158,13 +159,13 @@ class BlockErrorFormatter {
/**
* Determine the block error message key by examining the block.
*
- * @param AbstractBlock $block
+ * @param Block $block
* @return string Message key
*/
- private function getBlockErrorMessageKey( AbstractBlock $block ) {
+ private function getBlockErrorMessageKey( Block $block ) {
$key = 'blockedtext';
if ( $block instanceof DatabaseBlock ) {
- if ( $block->getType() === AbstractBlock::TYPE_AUTO ) {
+ if ( $block->getType() === Block::TYPE_AUTO ) {
$key = 'autoblockedtext';
} elseif ( !$block->isSitewide() ) {
$key = 'blockedtext-partial';
@@ -181,7 +182,7 @@ class BlockErrorFormatter {
* Get the formatted parameters needed to build the block error messages handled by
* getBlockErrorMessageKey.
*
- * @param AbstractBlock $block
+ * @param Block $block
* @param UserIdentity $user
* @param Language $language
* @param string $ip
@@ -196,7 +197,7 @@ class BlockErrorFormatter {
* - timestamp: Time the block was created, in the specified language
*/
private function getBlockErrorMessageParams(
- AbstractBlock $block,
+ Block $block,
UserIdentity $user,
Language $language,
$ip
diff --git a/includes/block/BlockPermissionChecker.php b/includes/block/BlockPermissionChecker.php
index f2cb746e8d4e..9bd91540a619 100644
--- a/includes/block/BlockPermissionChecker.php
+++ b/includes/block/BlockPermissionChecker.php
@@ -141,7 +141,7 @@ class BlockPermissionChecker {
// Blocked admin is trying to alter their own block
// Self-blocked admins can always remove or alter their block
- if ( $block->getByName() === $performerIdentity->getName() ) {
+ if ( $block->getBlocker() && $performerIdentity->equals( $block->getBlocker() ) ) {
return true;
}
@@ -155,7 +155,8 @@ class BlockPermissionChecker {
if (
$this->target instanceof UserIdentity &&
- $block->getByName() === $this->target->getName()
+ $block->getBlocker() &&
+ $this->target->equals( $block->getBlocker() )
) {
// T150826: Blocked admins can always block the admin who blocked them
return true;
diff --git a/includes/block/BlockUser.php b/includes/block/BlockUser.php
index 8555f8a2dfb4..04f5f90c5057 100644
--- a/includes/block/BlockUser.php
+++ b/includes/block/BlockUser.php
@@ -559,12 +559,12 @@ class BlockUser {
if ( $priorBlock === null ) {
$this->logger->warning( 'Block could not be inserted. No existing block was found.' );
- return Status::newFatal( 'ipb-block-not-found', $block->getTarget() );
+ return Status::newFatal( 'ipb-block-not-found', $block->getTargetName() );
}
if ( $block->equals( $priorBlock ) ) {
// Block settings are equal => user is already blocked
- return Status::newFatal( 'ipb_already_blocked', $block->getTarget() );
+ return Status::newFatal( 'ipb_already_blocked', $block->getTargetName() );
}
$currentBlock = $this->configureBlock( $priorBlock );
@@ -572,7 +572,7 @@ class BlockUser {
$isReblock = true;
$block = $currentBlock;
} else {
- return Status::newFatal( 'ipb_already_blocked', $block->getTarget() );
+ return Status::newFatal( 'ipb_already_blocked', $block->getTargetName() );
}
}
diff --git a/includes/block/CompositeBlock.php b/includes/block/CompositeBlock.php
index b333b26ac189..0f898b829640 100644
--- a/includes/block/CompositeBlock.php
+++ b/includes/block/CompositeBlock.php
@@ -22,6 +22,7 @@
namespace MediaWiki\Block;
+use MediaWiki\User\UserIdentity;
use Title;
/**
@@ -206,4 +207,11 @@ class CompositeBlock extends AbstractBlock {
public function getByName() {
return '';
}
+
+ /**
+ * @inheritDoc
+ */
+ public function getBlocker(): ?UserIdentity {
+ return null;
+ }
}
diff --git a/includes/block/DatabaseBlock.php b/includes/block/DatabaseBlock.php
index 949c8d1528db..761aa836ecea 100644
--- a/includes/block/DatabaseBlock.php
+++ b/includes/block/DatabaseBlock.php
@@ -391,7 +391,7 @@ class DatabaseBlock extends AbstractBlock {
if ( $block->getType() == self::TYPE_RANGE ) {
# This is the number of bits that are allowed to vary in the block, give
# or take some floating point errors
- $target = $block->getTarget();
+ $target = $block->getTargetName();
$max = IPUtils::isIPv6( $target ) ? 128 : 32;
list( $network, $bits ) = IPUtils::parseCIDR( $target );
$size = $max - $bits;
@@ -655,13 +655,13 @@ class DatabaseBlock extends AbstractBlock {
# Make a new block object with the desired properties.
$autoblock = new DatabaseBlock;
- wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP );
+ wfDebug( "Autoblocking {$this->getTargetName()}@" . $autoblockIP );
$autoblock->setTarget( $autoblockIP );
$autoblock->setBlocker( $this->getBlocker() );
$autoblock->setReason(
wfMessage(
'autoblocker',
- (string)$this->getTarget(),
+ $this->getTargetName(),
$this->getReasonComment()->text
)->inContentLanguage()->plain()
);
@@ -854,7 +854,7 @@ class DatabaseBlock extends AbstractBlock {
wfMessage( 'autoblockid', $this->mId )->text()
);
} else {
- return htmlspecialchars( $this->getTarget() );
+ return htmlspecialchars( $this->getTargetName() );
}
}
diff --git a/includes/block/DatabaseBlockStore.php b/includes/block/DatabaseBlockStore.php
index 191579ca17c9..ea5404399715 100644
--- a/includes/block/DatabaseBlockStore.php
+++ b/includes/block/DatabaseBlockStore.php
@@ -29,7 +29,6 @@ use MediaWiki\Config\ServiceOptions;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\User\ActorStoreFactory;
-use MediaWiki\User\UserIdentity;
use MWException;
use Psr\Log\LoggerInterface;
use ReadOnlyMode;
@@ -342,12 +341,11 @@ class DatabaseBlockStore {
) : array {
$expiry = $dbw->encodeExpiry( $block->getExpiry() );
- $target = $block->getTarget();
- $forcedTargetId = $block->getForcedTargetId();
+ $forcedTargetId = $block->getForcedTargetID();
if ( $forcedTargetId ) {
$userId = $forcedTargetId;
- } elseif ( $target instanceof User ) {
- $userId = $target->getId();
+ } elseif ( $block->getTargetUserIdentity() ) {
+ $userId = $block->getTargetUserIdentity()->getId();
} else {
$userId = 0;
}
@@ -360,7 +358,7 @@ class DatabaseBlockStore {
->acquireActorId( $block->getBlocker(), $dbw );
$blockArray = [
- 'ipb_address' => (string)$target,
+ 'ipb_address' => $block->getTargetName(),
'ipb_user' => $userId,
'ipb_by_actor' => $blockerActor,
'ipb_timestamp' => $dbw->timestamp( $block->getTimestamp() ),
@@ -431,7 +429,7 @@ class DatabaseBlockStore {
// If autoblock is enabled, autoblock the LAST IP(s) used
if ( $block->isAutoblocking() && $block->getType() == AbstractBlock::TYPE_USER ) {
$this->logger->debug(
- 'Doing retroactive autoblocks for ' . $block->getTarget()
+ 'Doing retroactive autoblocks for ' . $block->getTargetName()
);
$hookAutoBlocked = [];
@@ -463,12 +461,11 @@ class DatabaseBlockStore {
return [];
}
- list( $target, $type ) = $block->getTargetAndType();
+ $type = $block->getType();
if ( $type !== AbstractBlock::TYPE_USER ) {
// Autoblocks only apply to users
return [];
}
- /** @var UserIdentity $target */
$dbr = $this->loadBalancer->getConnectionRef( DB_REPLICA );
@@ -477,7 +474,10 @@ class DatabaseBlockStore {
'LIMIT' => 1,
];
- $actor = $this->actorStoreFactory->getActorNormalization()->findActorId( $target, $dbr );
+ $actor = $this->actorStoreFactory->getActorNormalization()->findActorId(
+ $block->getTargetUserIdentity(),
+ $dbr
+ );
if ( !$actor ) {
$this->logger->debug( 'No actor found to retroactively autoblock' );
return [];
diff --git a/includes/block/SystemBlock.php b/includes/block/SystemBlock.php
index e99d076f09fb..318cc1ab05d9 100644
--- a/includes/block/SystemBlock.php
+++ b/includes/block/SystemBlock.php
@@ -22,6 +22,8 @@
namespace MediaWiki\Block;
+use MediaWiki\User\UserIdentity;
+
/**
* System blocks are temporary blocks that are created on enforcement (e.g.
* from IP lists) and are not saved to the database. The target of a
@@ -107,4 +109,11 @@ class SystemBlock extends AbstractBlock {
public function getByName() {
return '';
}
+
+ /**
+ * @inheritDoc
+ */
+ public function getBlocker(): ?UserIdentity {
+ return null;
+ }
}
diff --git a/includes/block/UnblockUser.php b/includes/block/UnblockUser.php
index 85a69864c450..92b0e9263b7b 100644
--- a/includes/block/UnblockUser.php
+++ b/includes/block/UnblockUser.php
@@ -31,7 +31,6 @@ use MediaWiki\User\UserIdentity;
use RevisionDeleteUser;
use Status;
use TitleValue;
-use User;
/**
* Backend class for unblocking users
@@ -175,7 +174,7 @@ class UnblockUser {
$this->block->getType() === AbstractBlock::TYPE_RANGE &&
$this->targetType === AbstractBlock::TYPE_IP
) {
- $status->fatal( 'ipb_blocked_as_range', $this->target, $this->block->getTarget() );
+ $status->fatal( 'ipb_blocked_as_range', $this->target, $this->block->getTargetName() );
return $status;
}
@@ -190,17 +189,17 @@ class UnblockUser {
$deleteBlockStatus = $this->blockStore->deleteBlock( $this->block );
if ( !$deleteBlockStatus ) {
- $status->fatal( 'ipb_cant_unblock', $this->block->getTarget() );
+ $status->fatal( 'ipb_cant_unblock', $this->block->getTargetName() );
return $status;
}
$this->hookRunner->onUnblockUserComplete( $this->block, $legacyUser );
// Unset _deleted fields as needed
- if ( $this->block->getHideName() && $this->block->getTarget() instanceof User ) {
- // Something is deeply FUBAR if this is not a User object, but who knows?
- $id = $this->block->getTarget()->getId();
- RevisionDeleteUser::unsuppressUserName( $this->block->getTarget(), $id );
+ $user = $this->block->getTargetUserIdentity();
+ if ( $this->block->getHideName() && $user ) {
+ $id = $user->getId();
+ RevisionDeleteUser::unsuppressUserName( $user->getName(), $id );
}
$this->log();
@@ -217,9 +216,7 @@ class UnblockUser {
if ( $this->block->getType() === DatabaseBlock::TYPE_AUTO ) {
$page = TitleValue::tryNew( NS_USER, '#' . $this->block->getId() );
} else {
- $page = $this->block->getTarget() instanceof UserIdentity
- ? $this->block->getTarget()->getUserPage()
- : TitleValue::tryNew( NS_USER, $this->block->getTarget() );
+ $page = TitleValue::tryNew( NS_USER, $this->block->getTargetName() );
}
$logEntry = new ManualLogEntry( 'block', 'unblock' );