2004-02-18 02:15:00 +00:00
|
|
|
<?php
|
2004-09-02 23:28:24 +00:00
|
|
|
/**
|
|
|
|
|
* Blocks and bans object
|
2005-08-02 13:35:19 +00:00
|
|
|
*
|
2011-03-22 17:18:15 +00:00
|
|
|
* 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
|
2004-09-03 23:00:01 +00:00
|
|
|
*
|
2011-03-22 17:18:15 +00:00
|
|
|
* @file
|
2004-09-02 23:28:24 +00:00
|
|
|
*/
|
2016-09-22 02:52:06 +00:00
|
|
|
|
2017-02-07 04:49:57 +00:00
|
|
|
use Wikimedia\Rdbms\Database;
|
2017-02-10 18:09:05 +00:00
|
|
|
use Wikimedia\Rdbms\IDatabase;
|
2019-04-11 19:54:10 +00:00
|
|
|
use MediaWiki\Block\BlockRestrictionStore;
|
2018-08-16 04:55:55 +00:00
|
|
|
use MediaWiki\Block\Restriction\Restriction;
|
2018-10-30 18:19:22 +00:00
|
|
|
use MediaWiki\Block\Restriction\NamespaceRestriction;
|
|
|
|
|
use MediaWiki\Block\Restriction\PageRestriction;
|
2016-09-22 02:52:06 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
|
|
|
|
|
2008-09-22 04:52:51 +00:00
|
|
|
class Block {
|
2014-05-12 14:42:51 +00:00
|
|
|
/** @var string */
|
|
|
|
|
public $mReason;
|
2011-06-02 19:32:45 +00:00
|
|
|
|
2014-05-22 14:45:46 +00:00
|
|
|
/** @var string */
|
2014-05-12 14:42:51 +00:00
|
|
|
public $mTimestamp;
|
2011-03-22 17:18:15 +00:00
|
|
|
|
2014-05-22 14:45:46 +00:00
|
|
|
/** @var bool */
|
2014-05-12 14:42:51 +00:00
|
|
|
public $mAuto;
|
|
|
|
|
|
2014-05-22 14:45:46 +00:00
|
|
|
/** @var string */
|
2014-05-12 14:42:51 +00:00
|
|
|
public $mExpiry;
|
|
|
|
|
|
2014-05-22 14:45:46 +00:00
|
|
|
/** @var bool */
|
2014-05-12 14:42:51 +00:00
|
|
|
public $mHideName;
|
|
|
|
|
|
|
|
|
|
/** @var int */
|
|
|
|
|
public $mParentBlockId;
|
|
|
|
|
|
|
|
|
|
/** @var int */
|
2017-08-04 14:57:27 +00:00
|
|
|
private $mId;
|
2014-05-12 14:42:51 +00:00
|
|
|
|
|
|
|
|
/** @var bool */
|
2017-08-04 14:57:27 +00:00
|
|
|
private $mFromMaster;
|
2014-05-12 14:42:51 +00:00
|
|
|
|
|
|
|
|
/** @var bool */
|
2017-08-04 14:57:27 +00:00
|
|
|
private $mBlockEmail;
|
2014-05-12 14:42:51 +00:00
|
|
|
|
|
|
|
|
/** @var bool */
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
private $allowUsertalk;
|
2014-05-12 14:42:51 +00:00
|
|
|
|
|
|
|
|
/** @var bool */
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
private $blockCreateAccount;
|
2011-03-19 23:47:08 +00:00
|
|
|
|
2014-04-23 09:25:56 +00:00
|
|
|
/** @var User|string */
|
2017-08-04 14:57:27 +00:00
|
|
|
private $target;
|
2011-03-21 19:12:41 +00:00
|
|
|
|
2014-04-23 09:25:56 +00:00
|
|
|
/** @var int Hack for foreign blocking (CentralAuth) */
|
2017-08-04 14:57:27 +00:00
|
|
|
private $forcedTargetID;
|
2012-04-10 00:12:06 +00:00
|
|
|
|
2019-02-15 19:24:58 +00:00
|
|
|
/**
|
|
|
|
|
* @var int Block::TYPE_ constant. After the block has been loaded
|
|
|
|
|
* from the database, this can only be USER, IP or RANGE.
|
|
|
|
|
*/
|
2017-08-04 14:57:27 +00:00
|
|
|
private $type;
|
2011-03-21 19:12:41 +00:00
|
|
|
|
2014-04-06 18:02:32 +00:00
|
|
|
/** @var User */
|
2017-08-04 14:57:27 +00:00
|
|
|
private $blocker;
|
2011-03-21 19:12:41 +00:00
|
|
|
|
2014-04-23 09:25:56 +00:00
|
|
|
/** @var bool */
|
2017-08-04 14:57:27 +00:00
|
|
|
private $isHardblock;
|
2011-03-22 17:18:15 +00:00
|
|
|
|
2014-04-23 09:25:56 +00:00
|
|
|
/** @var bool */
|
2017-08-04 14:57:27 +00:00
|
|
|
private $isAutoblocking;
|
2011-03-22 17:18:15 +00:00
|
|
|
|
2016-12-01 16:51:03 +00:00
|
|
|
/** @var string|null */
|
2017-08-04 14:57:27 +00:00
|
|
|
private $systemBlockType;
|
2016-12-01 16:51:03 +00:00
|
|
|
|
2018-08-16 04:55:55 +00:00
|
|
|
/** @var bool */
|
|
|
|
|
private $isSitewide;
|
|
|
|
|
|
|
|
|
|
/** @var Restriction[] */
|
|
|
|
|
private $restrictions;
|
|
|
|
|
|
2011-03-20 17:43:17 +00:00
|
|
|
# TYPE constants
|
2011-03-12 21:54:35 +00:00
|
|
|
const TYPE_USER = 1;
|
|
|
|
|
const TYPE_IP = 2;
|
|
|
|
|
const TYPE_RANGE = 3;
|
2011-03-13 14:47:34 +00:00
|
|
|
const TYPE_AUTO = 4;
|
|
|
|
|
const TYPE_ID = 5;
|
2011-03-12 21:54:35 +00:00
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
/**
|
2019-04-29 22:26:03 +00:00
|
|
|
* Create a new block with specified option parameters on a user, IP or IP range.
|
2014-05-22 14:45:46 +00:00
|
|
|
*
|
|
|
|
|
* @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
|
|
|
|
|
* createAccount bool Disallow creation of new accounts
|
|
|
|
|
* enableAutoblock bool Enable automatic blocking
|
|
|
|
|
* 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)
|
2016-12-01 16:51:03 +00:00
|
|
|
* 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().
|
2019-02-28 11:43:01 +00:00
|
|
|
* sitewide bool Disallow editing all pages and all contribution
|
|
|
|
|
* actions, except those specifically allowed by
|
|
|
|
|
* other block flags
|
2014-05-22 14:45:46 +00:00
|
|
|
*
|
2019-04-29 22:26:03 +00:00
|
|
|
* @since 1.26 $options array
|
2011-03-21 19:12:41 +00:00
|
|
|
*/
|
2019-04-29 22:26:03 +00:00
|
|
|
public function __construct( array $options = [] ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$defaults = [
|
2014-05-22 14:45:46 +00:00
|
|
|
'address' => '',
|
|
|
|
|
'user' => null,
|
|
|
|
|
'by' => null,
|
|
|
|
|
'reason' => '',
|
|
|
|
|
'timestamp' => '',
|
|
|
|
|
'auto' => false,
|
|
|
|
|
'expiry' => '',
|
|
|
|
|
'anonOnly' => false,
|
|
|
|
|
'createAccount' => false,
|
|
|
|
|
'enableAutoblock' => false,
|
|
|
|
|
'hideName' => false,
|
|
|
|
|
'blockEmail' => false,
|
|
|
|
|
'allowUsertalk' => false,
|
|
|
|
|
'byText' => '',
|
2016-12-01 16:51:03 +00:00
|
|
|
'systemBlock' => null,
|
2018-08-16 04:55:55 +00:00
|
|
|
'sitewide' => true,
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2011-03-21 19:12:41 +00:00
|
|
|
|
2014-05-22 14:45:46 +00:00
|
|
|
$options += $defaults;
|
|
|
|
|
|
|
|
|
|
$this->setTarget( $options['address'] );
|
|
|
|
|
|
|
|
|
|
if ( $this->target instanceof User && $options['user'] ) {
|
|
|
|
|
# Needed for foreign users
|
|
|
|
|
$this->forcedTargetID = $options['user'];
|
2012-02-28 02:04:30 +00:00
|
|
|
}
|
2014-05-22 14:45:46 +00:00
|
|
|
|
|
|
|
|
if ( $options['by'] ) {
|
|
|
|
|
# Local user
|
2016-03-19 00:08:06 +00:00
|
|
|
$this->setBlocker( User::newFromId( $options['by'] ) );
|
2014-05-22 14:45:46 +00:00
|
|
|
} else {
|
|
|
|
|
# Foreign user
|
|
|
|
|
$this->setBlocker( $options['byText'] );
|
2011-11-01 00:11:53 +00:00
|
|
|
}
|
2014-05-22 14:45:46 +00:00
|
|
|
|
2019-03-22 15:16:40 +00:00
|
|
|
$this->setReason( $options['reason'] );
|
2019-03-25 15:11:26 +00:00
|
|
|
$this->setTimestamp( wfTimestamp( TS_MW, $options['timestamp'] ) );
|
2019-03-22 15:16:40 +00:00
|
|
|
$this->setExpiry( wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] ) );
|
2014-05-22 14:45:46 +00:00
|
|
|
|
|
|
|
|
# Boolean settings
|
|
|
|
|
$this->mAuto = (bool)$options['auto'];
|
2019-03-22 15:16:40 +00:00
|
|
|
$this->setHideName( (bool)$options['hideName'] );
|
2014-05-22 14:45:46 +00:00
|
|
|
$this->isHardblock( !$options['anonOnly'] );
|
|
|
|
|
$this->isAutoblocking( (bool)$options['enableAutoblock'] );
|
2018-08-16 04:55:55 +00:00
|
|
|
$this->isSitewide( (bool)$options['sitewide'] );
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
$this->isEmailBlocked( (bool)$options['blockEmail'] );
|
|
|
|
|
$this->isCreateAccountBlocked( (bool)$options['createAccount'] );
|
|
|
|
|
$this->isUsertalkEditAllowed( (bool)$options['allowUsertalk'] );
|
2011-03-22 17:18:15 +00:00
|
|
|
|
2005-12-01 10:37:47 +00:00
|
|
|
$this->mFromMaster = false;
|
2016-12-01 16:51:03 +00:00
|
|
|
$this->systemBlockType = $options['systemBlock'];
|
2004-02-14 12:37:25 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2008-09-21 14:22:23 +00:00
|
|
|
/**
|
2019-02-15 19:24:58 +00:00
|
|
|
* Load a block from the block id.
|
2008-09-22 04:52:51 +00:00
|
|
|
*
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param int $id Block id to search for
|
|
|
|
|
* @return Block|null
|
2008-09-21 14:22:23 +00:00
|
|
|
*/
|
2008-11-23 09:52:29 +00:00
|
|
|
public static function newFromID( $id ) {
|
2016-09-05 19:55:19 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
2017-10-06 17:03:55 +00:00
|
|
|
$blockQuery = self::getQueryInfo();
|
2011-03-22 17:18:15 +00:00
|
|
|
$res = $dbr->selectRow(
|
2017-10-06 17:03:55 +00:00
|
|
|
$blockQuery['tables'],
|
|
|
|
|
$blockQuery['fields'],
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'ipb_id' => $id ],
|
2017-10-06 17:03:55 +00:00
|
|
|
__METHOD__,
|
|
|
|
|
[],
|
|
|
|
|
$blockQuery['joins']
|
2011-03-22 17:18:15 +00:00
|
|
|
);
|
2011-06-15 19:05:25 +00:00
|
|
|
if ( $res ) {
|
2012-05-25 14:50:57 +00:00
|
|
|
return self::newFromRow( $res );
|
2011-06-15 19:05:25 +00:00
|
|
|
} else {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2003-09-01 13:13:56 +00:00
|
|
|
}
|
2009-10-19 11:15:51 +00:00
|
|
|
|
2012-06-05 22:58:54 +00:00
|
|
|
/**
|
|
|
|
|
* Return the list of ipblocks fields that should be selected to create
|
|
|
|
|
* a new block.
|
2017-10-06 17:03:55 +00:00
|
|
|
* @deprecated since 1.31, use self::getQueryInfo() instead.
|
2012-06-05 22:58:54 +00:00
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public static function selectFields() {
|
2017-09-12 17:12:29 +00:00
|
|
|
global $wgActorTableSchemaMigrationStage;
|
|
|
|
|
|
2018-09-18 18:21:20 +00:00
|
|
|
if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_READ_NEW ) {
|
2017-09-12 17:12:29 +00:00
|
|
|
// If code is using this instead of self::getQueryInfo(), there's a
|
|
|
|
|
// decent chance it's going to try to directly access
|
|
|
|
|
// $row->ipb_by or $row->ipb_by_text and we can't give it
|
2018-09-18 18:21:20 +00:00
|
|
|
// useful values here once those aren't being used anymore.
|
2017-09-12 17:12:29 +00:00
|
|
|
throw new BadMethodCallException(
|
2018-09-18 18:21:20 +00:00
|
|
|
'Cannot use ' . __METHOD__
|
|
|
|
|
. ' when $wgActorTableSchemaMigrationStage has SCHEMA_COMPAT_READ_NEW'
|
2017-09-12 17:12:29 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-06 17:03:55 +00:00
|
|
|
wfDeprecated( __METHOD__, '1.31' );
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
2012-05-25 14:50:57 +00:00
|
|
|
'ipb_id',
|
|
|
|
|
'ipb_address',
|
|
|
|
|
'ipb_by',
|
|
|
|
|
'ipb_by_text',
|
2018-09-18 18:21:20 +00:00
|
|
|
'ipb_by_actor' => 'NULL',
|
2012-05-25 14:50:57 +00:00
|
|
|
'ipb_timestamp',
|
|
|
|
|
'ipb_auto',
|
|
|
|
|
'ipb_anon_only',
|
|
|
|
|
'ipb_create_account',
|
|
|
|
|
'ipb_enable_autoblock',
|
|
|
|
|
'ipb_expiry',
|
|
|
|
|
'ipb_deleted',
|
|
|
|
|
'ipb_block_email',
|
|
|
|
|
'ipb_allow_usertalk',
|
2012-06-05 22:58:54 +00:00
|
|
|
'ipb_parent_block_id',
|
2018-08-16 04:55:55 +00:00
|
|
|
'ipb_sitewide',
|
2018-01-24 23:41:01 +00:00
|
|
|
] + CommentStore::getStore()->getFields( 'ipb_reason' );
|
2012-05-25 14:50:57 +00:00
|
|
|
}
|
|
|
|
|
|
2017-10-06 17:03:55 +00:00
|
|
|
/**
|
|
|
|
|
* Return the tables, fields, and join conditions to be selected to create
|
|
|
|
|
* a new block object.
|
|
|
|
|
* @since 1.31
|
|
|
|
|
* @return array With three keys:
|
|
|
|
|
* - tables: (string[]) to include in the `$table` to `IDatabase->select()`
|
|
|
|
|
* - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
|
|
|
|
|
* - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
|
|
|
|
|
*/
|
|
|
|
|
public static function getQueryInfo() {
|
2018-01-24 23:41:01 +00:00
|
|
|
$commentQuery = CommentStore::getStore()->getJoin( 'ipb_reason' );
|
2017-09-12 17:12:29 +00:00
|
|
|
$actorQuery = ActorMigration::newMigration()->getJoin( 'ipb_by' );
|
2017-10-06 17:03:55 +00:00
|
|
|
return [
|
2017-09-12 17:12:29 +00:00
|
|
|
'tables' => [ 'ipblocks' ] + $commentQuery['tables'] + $actorQuery['tables'],
|
2017-10-06 17:03:55 +00:00
|
|
|
'fields' => [
|
|
|
|
|
'ipb_id',
|
|
|
|
|
'ipb_address',
|
|
|
|
|
'ipb_timestamp',
|
|
|
|
|
'ipb_auto',
|
|
|
|
|
'ipb_anon_only',
|
|
|
|
|
'ipb_create_account',
|
|
|
|
|
'ipb_enable_autoblock',
|
|
|
|
|
'ipb_expiry',
|
|
|
|
|
'ipb_deleted',
|
|
|
|
|
'ipb_block_email',
|
|
|
|
|
'ipb_allow_usertalk',
|
|
|
|
|
'ipb_parent_block_id',
|
2018-08-16 04:55:55 +00:00
|
|
|
'ipb_sitewide',
|
2017-09-12 17:12:29 +00:00
|
|
|
] + $commentQuery['fields'] + $actorQuery['fields'],
|
|
|
|
|
'joins' => $commentQuery['joins'] + $actorQuery['joins'],
|
2017-10-06 17:03:55 +00:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-23 09:52:29 +00:00
|
|
|
/**
|
2011-03-22 17:18:15 +00:00
|
|
|
* Check if two blocks are effectively equal. Doesn't check irrelevant things like
|
2012-10-26 16:18:59 +00:00
|
|
|
* the blocking user or the block timestamp, only things which affect the blocked user
|
2011-05-28 18:58:51 +00:00
|
|
|
*
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param Block $block
|
2011-05-28 18:58:51 +00:00
|
|
|
*
|
|
|
|
|
* @return bool
|
2008-11-23 09:52:29 +00:00
|
|
|
*/
|
|
|
|
|
public function equals( Block $block ) {
|
2009-10-19 11:15:51 +00:00
|
|
|
return (
|
2011-03-22 17:18:15 +00:00
|
|
|
(string)$this->target == (string)$block->target
|
|
|
|
|
&& $this->type == $block->type
|
2008-11-23 09:52:29 +00:00
|
|
|
&& $this->mAuto == $block->mAuto
|
2011-03-22 17:18:15 +00:00
|
|
|
&& $this->isHardblock() == $block->isHardblock()
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
&& $this->isCreateAccountBlocked() == $block->isCreateAccountBlocked()
|
2019-03-22 15:16:40 +00:00
|
|
|
&& $this->getExpiry() == $block->getExpiry()
|
2011-03-22 17:18:15 +00:00
|
|
|
&& $this->isAutoblocking() == $block->isAutoblocking()
|
2019-03-22 15:16:40 +00:00
|
|
|
&& $this->getHideName() == $block->getHideName()
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
&& $this->isEmailBlocked() == $block->isEmailBlocked()
|
|
|
|
|
&& $this->isUsertalkEditAllowed() == $block->isUsertalkEditAllowed()
|
2019-03-22 15:16:40 +00:00
|
|
|
&& $this->getReason() == $block->getReason()
|
2018-08-16 04:55:55 +00:00
|
|
|
&& $this->isSitewide() == $block->isSitewide()
|
|
|
|
|
// Block::getRestrictions() may perform a database query, so keep it at
|
|
|
|
|
// the end.
|
2019-04-11 19:54:10 +00:00
|
|
|
&& $this->getBlockRestrictionStore()->equals(
|
|
|
|
|
$this->getRestrictions(), $block->getRestrictions()
|
|
|
|
|
)
|
2008-11-23 09:52:29 +00:00
|
|
|
);
|
|
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
/**
|
|
|
|
|
* Load a block from the database which affects the already-set $this->target:
|
|
|
|
|
* 1) A block directly on the given user or IP
|
2013-03-13 07:42:41 +00:00
|
|
|
* 2) A rangeblock encompassing the given IP (smallest first)
|
2011-03-21 19:12:41 +00:00
|
|
|
* 3) An autoblock on the given IP
|
2018-06-26 21:14:43 +00:00
|
|
|
* @param User|string|null $vagueTarget Also search for blocks affecting this target. Doesn't
|
2011-05-24 21:04:50 +00:00
|
|
|
* make any sense to use TYPE_AUTO / TYPE_ID here. Leave blank to skip IP lookups.
|
2012-10-07 23:35:26 +00:00
|
|
|
* @throws MWException
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return bool Whether a relevant block was found
|
2011-03-21 19:12:41 +00:00
|
|
|
*/
|
|
|
|
|
protected function newLoad( $vagueTarget = null ) {
|
2016-09-05 19:55:19 +00:00
|
|
|
$db = wfGetDB( $this->mFromMaster ? DB_MASTER : DB_REPLICA );
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $this->type !== null ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$conds = [
|
|
|
|
|
'ipb_address' => [ (string)$this->target ],
|
|
|
|
|
];
|
2011-03-21 19:12:41 +00:00
|
|
|
} else {
|
2016-02-17 09:09:32 +00:00
|
|
|
$conds = [ 'ipb_address' => [] ];
|
2003-09-01 13:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
2011-07-11 16:53:31 +00:00
|
|
|
# Be aware that the != '' check is explicit, since empty values will be
|
2017-02-20 22:44:19 +00:00
|
|
|
# passed by some callers (T31116)
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $vagueTarget != '' ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
list( $target, $type ) = self::parseTarget( $vagueTarget );
|
2013-04-26 14:42:31 +00:00
|
|
|
switch ( $type ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
case self::TYPE_USER:
|
2013-03-13 07:42:41 +00:00
|
|
|
# Slightly weird, but who are we to argue?
|
2011-03-21 19:12:41 +00:00
|
|
|
$conds['ipb_address'][] = (string)$target;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case self::TYPE_IP:
|
|
|
|
|
$conds['ipb_address'][] = (string)$target;
|
|
|
|
|
$conds[] = self::getRangeCond( IP::toHex( $target ) );
|
|
|
|
|
$conds = $db->makeList( $conds, LIST_OR );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case self::TYPE_RANGE:
|
|
|
|
|
list( $start, $end ) = IP::parseRange( $target );
|
|
|
|
|
$conds['ipb_address'][] = (string)$target;
|
|
|
|
|
$conds[] = self::getRangeCond( $start, $end );
|
|
|
|
|
$conds = $db->makeList( $conds, LIST_OR );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw new MWException( "Tried to load block with invalid type" );
|
2006-07-10 06:30:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-06 17:03:55 +00:00
|
|
|
$blockQuery = self::getQueryInfo();
|
|
|
|
|
$res = $db->select(
|
|
|
|
|
$blockQuery['tables'], $blockQuery['fields'], $conds, __METHOD__, [], $blockQuery['joins']
|
|
|
|
|
);
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
# This result could contain a block on the user, a block on the IP, and a russian-doll
|
|
|
|
|
# set of rangeblocks. We want to choose the most specific one, so keep a leader board.
|
|
|
|
|
$bestRow = null;
|
2006-07-10 06:30:03 +00:00
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
# Lower will be better
|
|
|
|
|
$bestBlockScore = 100;
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
foreach ( $res as $row ) {
|
2012-05-25 14:50:57 +00:00
|
|
|
$block = self::newFromRow( $row );
|
2010-02-14 22:07:30 +00:00
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
# Don't use expired blocks
|
2015-12-30 04:29:10 +00:00
|
|
|
if ( $block->isExpired() ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
continue;
|
2006-07-11 05:30:35 +00:00
|
|
|
}
|
2010-02-14 22:07:30 +00:00
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
# Don't use anon only blocks on users
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $this->type == self::TYPE_USER && !$block->isHardblock() ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
2010-02-14 22:07:30 +00:00
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $block->getType() == self::TYPE_RANGE ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
# This is the number of bits that are allowed to vary in the block, give
|
|
|
|
|
# or take some floating point errors
|
2015-11-24 23:40:00 +00:00
|
|
|
$end = Wikimedia\base_convert( $block->getRangeEnd(), 16, 10 );
|
|
|
|
|
$start = Wikimedia\base_convert( $block->getRangeStart(), 16, 10 );
|
2011-03-21 19:12:41 +00:00
|
|
|
$size = log( $end - $start + 1, 2 );
|
|
|
|
|
|
2019-05-01 17:28:55 +00:00
|
|
|
# Rank a range block covering a single IP equally with a single-IP block
|
2013-03-07 16:50:43 +00:00
|
|
|
$score = self::TYPE_RANGE - 1 + ( $size / 128 );
|
2011-06-02 19:32:45 +00:00
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
} else {
|
|
|
|
|
$score = $block->getType();
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $score < $bestBlockScore ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
$bestBlockScore = $score;
|
|
|
|
|
$bestRow = $row;
|
2006-07-11 05:30:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $bestRow !== null ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
$this->initFromRow( $bestRow );
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2006-07-10 06:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-19 23:47:08 +00:00
|
|
|
/**
|
2013-03-13 07:42:41 +00:00
|
|
|
* Get a set of SQL conditions which will select rangeblocks encompassing a given range
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $start Hexadecimal IP representation
|
2018-06-26 21:14:43 +00:00
|
|
|
* @param string|null $end Hexadecimal IP representation, or null to use $start = $end
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return string
|
2011-03-19 23:47:08 +00:00
|
|
|
*/
|
2011-03-20 17:43:17 +00:00
|
|
|
public static function getRangeCond( $start, $end = null ) {
|
|
|
|
|
if ( $end === null ) {
|
2011-03-19 23:47:08 +00:00
|
|
|
$end = $start;
|
|
|
|
|
}
|
2017-02-20 22:44:19 +00:00
|
|
|
# Per T16634, we want to include relevant active rangeblocks; for
|
2011-03-19 23:47:08 +00:00
|
|
|
# rangeblocks, we want to include larger ranges which enclose the given
|
|
|
|
|
# range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
|
|
|
|
|
# so we can improve performance by filtering on a LIKE clause
|
|
|
|
|
$chunk = self::getIpFragment( $start );
|
2016-09-05 19:55:19 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
2011-03-19 23:47:08 +00:00
|
|
|
$like = $dbr->buildLike( $chunk, $dbr->anyString() );
|
|
|
|
|
|
|
|
|
|
# Fairly hard to make a malicious SQL statement out of hex characters,
|
|
|
|
|
# but stranger things have happened...
|
|
|
|
|
$safeStart = $dbr->addQuotes( $start );
|
|
|
|
|
$safeEnd = $dbr->addQuotes( $end );
|
|
|
|
|
|
|
|
|
|
return $dbr->makeList(
|
2016-02-17 09:09:32 +00:00
|
|
|
[
|
2011-03-19 23:47:08 +00:00
|
|
|
"ipb_range_start $like",
|
|
|
|
|
"ipb_range_start <= $safeStart",
|
|
|
|
|
"ipb_range_end >= $safeEnd",
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2011-03-19 23:47:08 +00:00
|
|
|
LIST_AND
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the component of an IP address which is certain to be the same between an IP
|
|
|
|
|
* address and a rangeblock containing that IP address.
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param string $hex Hexadecimal IP representation
|
|
|
|
|
* @return string
|
2011-03-19 23:47:08 +00:00
|
|
|
*/
|
2011-03-20 17:43:17 +00:00
|
|
|
protected static function getIpFragment( $hex ) {
|
2011-03-19 23:47:08 +00:00
|
|
|
global $wgBlockCIDRLimit;
|
2011-03-20 17:43:17 +00:00
|
|
|
if ( substr( $hex, 0, 3 ) == 'v6-' ) {
|
2013-01-26 18:32:03 +00:00
|
|
|
return 'v6-' . substr( substr( $hex, 3 ), 0, floor( $wgBlockCIDRLimit['IPv6'] / 4 ) );
|
2011-03-19 23:47:08 +00:00
|
|
|
} else {
|
2013-01-26 18:32:03 +00:00
|
|
|
return substr( $hex, 0, floor( $wgBlockCIDRLimit['IPv4'] / 4 ) );
|
2011-03-19 23:47:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-21 14:22:23 +00:00
|
|
|
/**
|
|
|
|
|
* Given a database row from the ipblocks table, initialize
|
|
|
|
|
* member variables
|
2014-07-13 03:55:43 +00:00
|
|
|
* @param stdClass $row A row from the ipblocks table
|
2008-09-21 14:22:23 +00:00
|
|
|
*/
|
2011-03-19 17:44:01 +00:00
|
|
|
protected function initFromRow( $row ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
$this->setTarget( $row->ipb_address );
|
2017-09-12 17:12:29 +00:00
|
|
|
$this->setBlocker( User::newFromAnyId(
|
2017-10-06 22:17:58 +00:00
|
|
|
$row->ipb_by, $row->ipb_by_text, $row->ipb_by_actor ?? null
|
2017-09-12 17:12:29 +00:00
|
|
|
) );
|
2011-07-18 22:23:42 +00:00
|
|
|
|
2019-03-25 15:11:26 +00:00
|
|
|
$this->setTimestamp( wfTimestamp( TS_MW, $row->ipb_timestamp ) );
|
2003-09-07 13:56:25 +00:00
|
|
|
$this->mAuto = $row->ipb_auto;
|
2019-03-22 15:16:40 +00:00
|
|
|
$this->setHideName( $row->ipb_deleted );
|
2015-05-06 15:33:08 +00:00
|
|
|
$this->mId = (int)$row->ipb_id;
|
2012-03-28 02:44:32 +00:00
|
|
|
$this->mParentBlockId = $row->ipb_parent_block_id;
|
2011-07-18 22:23:42 +00:00
|
|
|
|
2011-07-18 21:48:56 +00:00
|
|
|
// I wish I didn't have to do this
|
2017-06-06 17:39:14 +00:00
|
|
|
$db = wfGetDB( DB_REPLICA );
|
2019-03-22 15:16:40 +00:00
|
|
|
$this->setExpiry( $db->decodeExpiry( $row->ipb_expiry ) );
|
|
|
|
|
$this->setReason(
|
|
|
|
|
CommentStore::getStore()
|
2017-10-06 17:03:55 +00:00
|
|
|
// Legacy because $row may have come from self::selectFields()
|
2019-03-22 15:16:40 +00:00
|
|
|
->getCommentLegacy( $db, 'ipb_reason', $row )->text
|
|
|
|
|
);
|
2011-03-22 17:18:15 +00:00
|
|
|
|
|
|
|
|
$this->isHardblock( !$row->ipb_anon_only );
|
|
|
|
|
$this->isAutoblocking( $row->ipb_enable_autoblock );
|
2018-08-16 04:55:55 +00:00
|
|
|
$this->isSitewide( (bool)$row->ipb_sitewide );
|
2011-03-22 17:18:15 +00:00
|
|
|
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
$this->isCreateAccountBlocked( $row->ipb_create_account );
|
|
|
|
|
$this->isEmailBlocked( $row->ipb_block_email );
|
|
|
|
|
$this->isUsertalkEditAllowed( $row->ipb_allow_usertalk );
|
2005-08-02 13:35:19 +00:00
|
|
|
}
|
2003-09-01 13:13:56 +00:00
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
/**
|
|
|
|
|
* Create a new Block object from a database row
|
2014-07-13 03:55:43 +00:00
|
|
|
* @param stdClass $row Row from the ipblocks table
|
2011-03-21 19:12:41 +00:00
|
|
|
* @return Block
|
|
|
|
|
*/
|
2012-12-20 15:09:25 +00:00
|
|
|
public static function newFromRow( $row ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
$block = new Block;
|
|
|
|
|
$block->initFromRow( $row );
|
|
|
|
|
return $block;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-21 14:22:23 +00:00
|
|
|
/**
|
|
|
|
|
* Delete the row from the IP blocks table.
|
2008-09-22 04:52:51 +00:00
|
|
|
*
|
2012-10-07 23:35:26 +00:00
|
|
|
* @throws MWException
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return bool
|
2008-09-21 14:22:23 +00:00
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public function delete() {
|
|
|
|
|
if ( wfReadOnly() ) {
|
2006-07-10 06:30:03 +00:00
|
|
|
return false;
|
2005-03-08 02:45:25 +00:00
|
|
|
}
|
2010-02-14 22:07:30 +00:00
|
|
|
|
2011-03-22 17:18:15 +00:00
|
|
|
if ( !$this->getId() ) {
|
|
|
|
|
throw new MWException( "Block::delete() requires that the mId member be filled\n" );
|
2003-09-07 13:56:25 +00:00
|
|
|
}
|
2006-07-10 06:30:03 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2018-08-16 04:55:55 +00:00
|
|
|
|
2019-04-11 19:54:10 +00:00
|
|
|
$this->getBlockRestrictionStore()->deleteByParentBlockId( $this->getId() );
|
2016-02-17 09:09:32 +00:00
|
|
|
$dbw->delete( 'ipblocks', [ 'ipb_parent_block_id' => $this->getId() ], __METHOD__ );
|
2018-08-16 04:55:55 +00:00
|
|
|
|
2019-04-11 19:54:10 +00:00
|
|
|
$this->getBlockRestrictionStore()->deleteByBlockId( $this->getId() );
|
2016-02-17 09:09:32 +00:00
|
|
|
$dbw->delete( 'ipblocks', [ 'ipb_id' => $this->getId() ], __METHOD__ );
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2006-07-10 06:30:03 +00:00
|
|
|
return $dbw->affectedRows() > 0;
|
2003-09-01 13:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
2006-11-08 09:54:06 +00:00
|
|
|
/**
|
2008-09-22 04:52:51 +00:00
|
|
|
* Insert a block into the block table. Will fail if there is a conflicting
|
|
|
|
|
* block (same name and options) already in the database.
|
|
|
|
|
*
|
2018-06-26 21:14:43 +00:00
|
|
|
* @param IDatabase|null $dbw If you have one available
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return bool|array False on failure, assoc array on success:
|
2018-05-19 20:46:54 +00:00
|
|
|
* ('id' => block ID, 'autoIds' => array of autoblock IDs)
|
2008-09-22 04:52:51 +00:00
|
|
|
*/
|
2010-04-17 21:16:06 +00:00
|
|
|
public function insert( $dbw = null ) {
|
2016-04-19 14:25:43 +00:00
|
|
|
global $wgBlockDisablesLogin;
|
2016-12-01 16:51:03 +00:00
|
|
|
|
|
|
|
|
if ( $this->getSystemBlockType() !== null ) {
|
|
|
|
|
throw new MWException( 'Cannot insert a system block into the database' );
|
|
|
|
|
}
|
2017-09-12 17:12:29 +00:00
|
|
|
if ( !$this->getBlocker() || $this->getBlocker()->getName() === '' ) {
|
|
|
|
|
throw new MWException( 'Cannot insert a block without a blocker set' );
|
|
|
|
|
}
|
2016-12-01 16:51:03 +00:00
|
|
|
|
2005-01-11 09:29:29 +00:00
|
|
|
wfDebug( "Block::insert; timestamp {$this->mTimestamp}\n" );
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2011-03-22 11:51:09 +00:00
|
|
|
if ( $dbw === null ) {
|
2010-04-17 20:59:05 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2011-03-22 11:51:09 +00:00
|
|
|
}
|
2006-07-10 06:30:03 +00:00
|
|
|
|
2018-02-23 16:58:58 +00:00
|
|
|
self::purgeExpired();
|
2006-11-22 11:51:49 +00:00
|
|
|
|
2017-06-06 17:39:14 +00:00
|
|
|
$row = $this->getDatabaseArray( $dbw );
|
2011-12-15 18:57:53 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
|
2006-07-10 06:30:03 +00:00
|
|
|
$affected = $dbw->affectedRows();
|
2018-08-16 04:55:55 +00:00
|
|
|
if ( $affected ) {
|
|
|
|
|
$this->setId( $dbw->insertId() );
|
|
|
|
|
if ( $this->restrictions ) {
|
2019-04-11 19:54:10 +00:00
|
|
|
$this->getBlockRestrictionStore()->insert( $this->restrictions );
|
2018-08-16 04:55:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2015-04-06 22:13:07 +00:00
|
|
|
|
|
|
|
|
# Don't collide with expired blocks.
|
2015-04-17 20:04:35 +00:00
|
|
|
# Do this after trying to insert to avoid locking.
|
2015-04-06 22:13:07 +00:00
|
|
|
if ( !$affected ) {
|
2015-04-17 20:04:35 +00:00
|
|
|
# T96428: The ipb_address index uses a prefix on a field, so
|
|
|
|
|
# use a standard SELECT + DELETE to avoid annoying gap locks.
|
|
|
|
|
$ids = $dbw->selectFieldValues( 'ipblocks',
|
|
|
|
|
'ipb_id',
|
2016-02-17 09:09:32 +00:00
|
|
|
[
|
2015-04-06 22:13:07 +00:00
|
|
|
'ipb_address' => $row['ipb_address'],
|
|
|
|
|
'ipb_user' => $row['ipb_user'],
|
|
|
|
|
'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() )
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2015-04-06 22:13:07 +00:00
|
|
|
__METHOD__
|
|
|
|
|
);
|
2015-04-17 20:04:35 +00:00
|
|
|
if ( $ids ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], __METHOD__ );
|
2019-04-11 19:54:10 +00:00
|
|
|
$this->getBlockRestrictionStore()->deleteByBlockId( $ids );
|
2016-02-17 09:09:32 +00:00
|
|
|
$dbw->insert( 'ipblocks', $row, __METHOD__, [ 'IGNORE' ] );
|
2015-04-17 20:04:35 +00:00
|
|
|
$affected = $dbw->affectedRows();
|
2018-08-16 04:55:55 +00:00
|
|
|
$this->setId( $dbw->insertId() );
|
|
|
|
|
if ( $this->restrictions ) {
|
2019-04-11 19:54:10 +00:00
|
|
|
$this->getBlockRestrictionStore()->insert( $this->restrictions );
|
2018-08-16 04:55:55 +00:00
|
|
|
}
|
2015-04-17 20:04:35 +00:00
|
|
|
}
|
2015-04-06 22:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-22 11:22:15 +00:00
|
|
|
if ( $affected ) {
|
2011-03-22 11:51:09 +00:00
|
|
|
$auto_ipd_ids = $this->doRetroactiveAutoblock();
|
2016-04-19 14:25:43 +00:00
|
|
|
|
|
|
|
|
if ( $wgBlockDisablesLogin && $this->target instanceof User ) {
|
|
|
|
|
// Change user login token to force them to be logged out.
|
|
|
|
|
$this->target->setToken();
|
|
|
|
|
$this->target->saveSettings();
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
|
2011-03-22 11:22:15 +00:00
|
|
|
}
|
2006-11-08 09:54:06 +00:00
|
|
|
|
2011-03-22 11:22:15 +00:00
|
|
|
return false;
|
2003-09-01 13:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
2008-09-21 15:16:32 +00:00
|
|
|
/**
|
2008-09-22 04:52:51 +00:00
|
|
|
* Update a block in the DB with new parameters.
|
|
|
|
|
* The ID field needs to be loaded first.
|
2011-06-26 23:01:29 +00:00
|
|
|
*
|
2014-03-23 01:28:57 +00:00
|
|
|
* @return bool|array False on failure, array on success:
|
|
|
|
|
* ('id' => block ID, 'autoIds' => array of autoblock IDs)
|
2008-09-21 15:16:32 +00:00
|
|
|
*/
|
|
|
|
|
public function update() {
|
|
|
|
|
wfDebug( "Block::update; timestamp {$this->mTimestamp}\n" );
|
|
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
|
|
|
|
|
2013-06-02 17:36:30 +00:00
|
|
|
$dbw->startAtomic( __METHOD__ );
|
|
|
|
|
|
2018-08-16 04:55:55 +00:00
|
|
|
$result = $dbw->update(
|
2010-02-14 22:07:30 +00:00
|
|
|
'ipblocks',
|
2011-03-22 17:18:15 +00:00
|
|
|
$this->getDatabaseArray( $dbw ),
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'ipb_id' => $this->getId() ],
|
2011-03-22 17:18:15 +00:00
|
|
|
__METHOD__
|
2010-02-14 22:07:30 +00:00
|
|
|
);
|
2008-09-21 15:16:32 +00:00
|
|
|
|
2018-08-16 04:55:55 +00:00
|
|
|
// Only update the restrictions if they have been modified.
|
|
|
|
|
if ( $this->restrictions !== null ) {
|
|
|
|
|
// An empty array should remove all of the restrictions.
|
|
|
|
|
if ( empty( $this->restrictions ) ) {
|
2019-04-11 19:54:10 +00:00
|
|
|
$success = $this->getBlockRestrictionStore()->deleteByBlockId( $this->getId() );
|
2018-08-16 04:55:55 +00:00
|
|
|
} else {
|
2019-04-11 19:54:10 +00:00
|
|
|
$success = $this->getBlockRestrictionStore()->update( $this->restrictions );
|
2018-08-16 04:55:55 +00:00
|
|
|
}
|
|
|
|
|
// Update the result. The first false is the result, otherwise, true.
|
|
|
|
|
$result = $result && $success;
|
|
|
|
|
}
|
2013-06-02 17:36:30 +00:00
|
|
|
|
2014-03-23 16:27:02 +00:00
|
|
|
if ( $this->isAutoblocking() ) {
|
2017-02-20 22:44:19 +00:00
|
|
|
// update corresponding autoblock(s) (T50813)
|
2014-03-23 16:27:02 +00:00
|
|
|
$dbw->update(
|
|
|
|
|
'ipblocks',
|
2017-06-06 17:39:14 +00:00
|
|
|
$this->getAutoblockUpdateArray( $dbw ),
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'ipb_parent_block_id' => $this->getId() ],
|
2014-03-23 16:27:02 +00:00
|
|
|
__METHOD__
|
|
|
|
|
);
|
2018-08-16 04:55:55 +00:00
|
|
|
|
|
|
|
|
// Only update the restrictions if they have been modified.
|
|
|
|
|
if ( $this->restrictions !== null ) {
|
2019-04-11 19:54:10 +00:00
|
|
|
$this->getBlockRestrictionStore()->updateByParentBlockId( $this->getId(), $this->restrictions );
|
2018-08-16 04:55:55 +00:00
|
|
|
}
|
2014-03-23 16:27:02 +00:00
|
|
|
} else {
|
|
|
|
|
// autoblock no longer required, delete corresponding autoblock(s)
|
2019-04-11 19:54:10 +00:00
|
|
|
$this->getBlockRestrictionStore()->deleteByParentBlockId( $this->getId() );
|
2014-03-23 16:27:02 +00:00
|
|
|
$dbw->delete(
|
|
|
|
|
'ipblocks',
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'ipb_parent_block_id' => $this->getId() ],
|
2014-03-23 16:27:02 +00:00
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
}
|
2013-06-02 17:36:30 +00:00
|
|
|
|
|
|
|
|
$dbw->endAtomic( __METHOD__ );
|
|
|
|
|
|
2018-08-16 04:55:55 +00:00
|
|
|
if ( $result ) {
|
2013-06-02 17:36:30 +00:00
|
|
|
$auto_ipd_ids = $this->doRetroactiveAutoblock();
|
2016-02-17 09:09:32 +00:00
|
|
|
return [ 'id' => $this->mId, 'autoIds' => $auto_ipd_ids ];
|
2013-06-02 17:36:30 +00:00
|
|
|
}
|
|
|
|
|
|
2018-08-16 04:55:55 +00:00
|
|
|
return $result;
|
2008-09-21 15:16:32 +00:00
|
|
|
}
|
2010-02-14 22:07:30 +00:00
|
|
|
|
2008-09-21 15:16:32 +00:00
|
|
|
/**
|
2011-03-22 17:18:15 +00:00
|
|
|
* Get an array suitable for passing to $dbw->insert() or $dbw->update()
|
2017-06-06 17:39:14 +00:00
|
|
|
* @param IDatabase $dbw
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return array
|
2008-09-21 15:16:32 +00:00
|
|
|
*/
|
2017-06-06 17:39:14 +00:00
|
|
|
protected function getDatabaseArray( IDatabase $dbw ) {
|
2019-03-22 15:16:40 +00:00
|
|
|
$expiry = $dbw->encodeExpiry( $this->getExpiry() );
|
2009-10-19 11:15:51 +00:00
|
|
|
|
2012-04-10 00:12:06 +00:00
|
|
|
if ( $this->forcedTargetID ) {
|
|
|
|
|
$uid = $this->forcedTargetID;
|
|
|
|
|
} else {
|
2016-03-19 00:08:06 +00:00
|
|
|
$uid = $this->target instanceof User ? $this->target->getId() : 0;
|
2012-04-10 00:12:06 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$a = [
|
2011-03-22 17:18:15 +00:00
|
|
|
'ipb_address' => (string)$this->target,
|
2012-04-10 00:12:06 +00:00
|
|
|
'ipb_user' => $uid,
|
2019-03-22 15:16:40 +00:00
|
|
|
'ipb_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
|
2011-03-22 17:18:15 +00:00
|
|
|
'ipb_auto' => $this->mAuto,
|
|
|
|
|
'ipb_anon_only' => !$this->isHardblock(),
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
'ipb_create_account' => $this->isCreateAccountBlocked(),
|
2011-03-22 17:18:15 +00:00
|
|
|
'ipb_enable_autoblock' => $this->isAutoblocking(),
|
2011-07-18 21:48:56 +00:00
|
|
|
'ipb_expiry' => $expiry,
|
2011-03-22 17:18:15 +00:00
|
|
|
'ipb_range_start' => $this->getRangeStart(),
|
|
|
|
|
'ipb_range_end' => $this->getRangeEnd(),
|
2019-03-22 15:16:40 +00:00
|
|
|
'ipb_deleted' => intval( $this->getHideName() ), // typecast required for SQLite
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
'ipb_block_email' => $this->isEmailBlocked(),
|
|
|
|
|
'ipb_allow_usertalk' => $this->isUsertalkEditAllowed(),
|
2018-08-16 04:55:55 +00:00
|
|
|
'ipb_parent_block_id' => $this->mParentBlockId,
|
|
|
|
|
'ipb_sitewide' => $this->isSitewide(),
|
2019-03-22 15:16:40 +00:00
|
|
|
] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->getReason() )
|
2017-09-12 17:12:29 +00:00
|
|
|
+ ActorMigration::newMigration()->getInsertValues( $dbw, 'ipb_by', $this->getBlocker() );
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2011-03-22 17:18:15 +00:00
|
|
|
return $a;
|
2008-09-21 15:16:32 +00:00
|
|
|
}
|
2009-10-19 11:15:51 +00:00
|
|
|
|
2013-06-02 17:36:30 +00:00
|
|
|
/**
|
2017-06-06 17:39:14 +00:00
|
|
|
* @param IDatabase $dbw
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return array
|
2013-06-02 17:36:30 +00:00
|
|
|
*/
|
2017-06-06 17:39:14 +00:00
|
|
|
protected function getAutoblockUpdateArray( IDatabase $dbw ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
'ipb_create_account' => $this->isCreateAccountBlocked(),
|
2019-03-22 15:16:40 +00:00
|
|
|
'ipb_deleted' => (int)$this->getHideName(), // typecast required for SQLite
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
'ipb_allow_usertalk' => $this->isUsertalkEditAllowed(),
|
2019-02-04 22:31:55 +00:00
|
|
|
'ipb_sitewide' => $this->isSitewide(),
|
2019-03-22 15:16:40 +00:00
|
|
|
] + CommentStore::getStore()->insert( $dbw, 'ipb_reason', $this->getReason() )
|
2017-09-12 17:12:29 +00:00
|
|
|
+ ActorMigration::newMigration()->getInsertValues( $dbw, 'ipb_by', $this->getBlocker() );
|
2013-06-02 17:36:30 +00:00
|
|
|
}
|
|
|
|
|
|
2006-11-08 09:54:06 +00:00
|
|
|
/**
|
2009-10-19 11:15:51 +00:00
|
|
|
* Retroactively autoblocks the last IP used by the user (if it is a user)
|
|
|
|
|
* blocked by this Block.
|
|
|
|
|
*
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return array Block IDs of retroactive autoblocks made
|
2009-10-19 11:15:51 +00:00
|
|
|
*/
|
2011-03-19 17:44:01 +00:00
|
|
|
protected function doRetroactiveAutoblock() {
|
2016-02-17 09:09:32 +00:00
|
|
|
$blockIds = [];
|
2011-07-15 00:05:50 +00:00
|
|
|
# If autoblock is enabled, autoblock the LAST IP(s) used
|
2011-03-22 17:18:15 +00:00
|
|
|
if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
|
|
|
|
|
wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
|
2009-10-19 11:15:51 +00:00
|
|
|
|
2014-12-09 07:23:30 +00:00
|
|
|
$continue = Hooks::run(
|
2016-02-17 09:09:32 +00:00
|
|
|
'PerformRetroactiveAutoblock', [ $this, &$blockIds ] );
|
2009-10-19 11:15:51 +00:00
|
|
|
|
2011-07-15 00:48:02 +00:00
|
|
|
if ( $continue ) {
|
|
|
|
|
self::defaultRetroactiveAutoblock( $this, $blockIds );
|
2008-06-27 06:24:42 +00:00
|
|
|
}
|
2011-07-15 00:05:50 +00:00
|
|
|
}
|
|
|
|
|
return $blockIds;
|
|
|
|
|
}
|
2006-11-08 09:54:06 +00:00
|
|
|
|
2011-07-15 00:05:50 +00:00
|
|
|
/**
|
|
|
|
|
* Retroactively autoblocks the last IP used by the user (if it is a user)
|
|
|
|
|
* blocked by this Block. This will use the recentchanges table.
|
|
|
|
|
*
|
2011-07-15 00:48:02 +00:00
|
|
|
* @param Block $block
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param array &$blockIds
|
2011-07-15 00:05:50 +00:00
|
|
|
*/
|
2011-07-15 00:48:02 +00:00
|
|
|
protected static function defaultRetroactiveAutoblock( Block $block, array &$blockIds ) {
|
2013-01-04 19:58:00 +00:00
|
|
|
global $wgPutIPinRC;
|
|
|
|
|
|
|
|
|
|
// No IPs are in recentchanges table, so nothing to select
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( !$wgPutIPinRC ) {
|
2013-01-04 19:58:00 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 14:11:03 +00:00
|
|
|
// Autoblocks only apply to TYPE_USER
|
|
|
|
|
if ( $block->getType() !== self::TYPE_USER ) {
|
|
|
|
|
return;
|
2017-09-12 17:12:29 +00:00
|
|
|
}
|
2018-11-01 14:11:03 +00:00
|
|
|
$target = $block->getTarget(); // TYPE_USER => always a User object
|
2017-09-12 17:12:29 +00:00
|
|
|
|
2016-09-05 19:55:19 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
2017-09-12 17:12:29 +00:00
|
|
|
$rcQuery = ActorMigration::newMigration()->getWhere( $dbr, 'rc_user', $target, false );
|
2011-07-15 00:05:50 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$options = [ 'ORDER BY' => 'rc_timestamp DESC' ];
|
2011-07-15 00:05:50 +00:00
|
|
|
|
|
|
|
|
// Just the last IP used.
|
|
|
|
|
$options['LIMIT'] = 1;
|
|
|
|
|
|
2017-09-12 17:12:29 +00:00
|
|
|
$res = $dbr->select(
|
|
|
|
|
[ 'recentchanges' ] + $rcQuery['tables'],
|
|
|
|
|
[ 'rc_ip' ],
|
|
|
|
|
$rcQuery['conds'],
|
|
|
|
|
__METHOD__,
|
|
|
|
|
$options,
|
|
|
|
|
$rcQuery['joins']
|
|
|
|
|
);
|
2011-07-15 00:05:50 +00:00
|
|
|
|
2013-01-06 10:52:40 +00:00
|
|
|
if ( !$res->numRows() ) {
|
2011-07-15 00:05:50 +00:00
|
|
|
# No results, don't autoblock anything
|
|
|
|
|
wfDebug( "No IP found to retroactively autoblock\n" );
|
|
|
|
|
} else {
|
|
|
|
|
foreach ( $res as $row ) {
|
|
|
|
|
if ( $row->rc_ip ) {
|
|
|
|
|
$id = $block->doAutoblock( $row->rc_ip );
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $id ) {
|
|
|
|
|
$blockIds[] = $id;
|
|
|
|
|
}
|
2008-06-27 06:24:42 +00:00
|
|
|
}
|
2006-11-08 09:54:06 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-19 11:15:51 +00:00
|
|
|
|
2006-11-08 09:54:06 +00:00
|
|
|
/**
|
2008-08-08 05:56:43 +00:00
|
|
|
* Checks whether a given IP is on the autoblock whitelist.
|
2011-03-22 17:18:15 +00:00
|
|
|
* TODO: this probably belongs somewhere else, but not sure where...
|
2008-09-22 04:52:51 +00:00
|
|
|
*
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $ip The IP to check
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return bool
|
2008-08-08 05:56:43 +00:00
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public static function isWhitelistedFromAutoblocks( $ip ) {
|
2008-09-21 14:22:23 +00:00
|
|
|
// Try to get the autoblock_whitelist from the cache, as it's faster
|
|
|
|
|
// than getting the msg raw and explode()'ing it.
|
2016-10-14 09:17:25 +00:00
|
|
|
$cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
|
2015-10-19 17:52:19 +00:00
|
|
|
$lines = $cache->getWithSetCallback(
|
2017-10-25 01:42:31 +00:00
|
|
|
$cache->makeKey( 'ip-autoblock', 'whitelist' ),
|
2015-10-19 17:52:19 +00:00
|
|
|
$cache::TTL_DAY,
|
2016-10-14 09:17:25 +00:00
|
|
|
function ( $curValue, &$ttl, array &$setOpts ) {
|
|
|
|
|
$setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
|
|
|
|
|
|
2015-10-15 02:45:03 +00:00
|
|
|
return explode( "\n",
|
|
|
|
|
wfMessage( 'autoblock_whitelist' )->inContentLanguage()->plain() );
|
|
|
|
|
}
|
|
|
|
|
);
|
2006-11-22 23:42:39 +00:00
|
|
|
|
2010-02-14 22:07:30 +00:00
|
|
|
wfDebug( "Checking the autoblock whitelist..\n" );
|
2006-11-22 23:42:39 +00:00
|
|
|
|
2010-02-14 22:07:30 +00:00
|
|
|
foreach ( $lines as $line ) {
|
2006-11-22 23:42:39 +00:00
|
|
|
# List items only
|
|
|
|
|
if ( substr( $line, 0, 1 ) !== '*' ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-19 11:15:51 +00:00
|
|
|
$wlEntry = substr( $line, 1 );
|
|
|
|
|
$wlEntry = trim( $wlEntry );
|
2006-11-22 23:42:39 +00:00
|
|
|
|
2010-02-14 22:07:30 +00:00
|
|
|
wfDebug( "Checking $ip against $wlEntry..." );
|
2006-11-22 23:42:39 +00:00
|
|
|
|
|
|
|
|
# Is the IP in this range?
|
2009-10-19 11:15:51 +00:00
|
|
|
if ( IP::isInRange( $ip, $wlEntry ) ) {
|
2010-02-14 22:07:30 +00:00
|
|
|
wfDebug( " IP $ip matches $wlEntry, not autoblocking\n" );
|
2008-08-08 05:56:43 +00:00
|
|
|
return true;
|
2006-12-08 10:30:50 +00:00
|
|
|
} else {
|
|
|
|
|
wfDebug( " No match\n" );
|
2006-11-22 23:42:39 +00:00
|
|
|
}
|
2006-11-22 11:51:49 +00:00
|
|
|
}
|
2009-10-19 11:15:51 +00:00
|
|
|
|
2008-08-08 05:56:43 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-09-22 04:52:51 +00:00
|
|
|
* Autoblocks the given IP, referring to this Block.
|
|
|
|
|
*
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param string $autoblockIP The IP to autoblock.
|
|
|
|
|
* @return int|bool Block ID if an autoblock was inserted, false if not.
|
2008-09-22 04:52:51 +00:00
|
|
|
*/
|
2011-03-23 00:10:46 +00:00
|
|
|
public function doAutoblock( $autoblockIP ) {
|
2008-08-08 05:56:43 +00:00
|
|
|
# If autoblocks are disabled, go away.
|
2011-03-22 17:18:15 +00:00
|
|
|
if ( !$this->isAutoblocking() ) {
|
2011-03-22 11:22:15 +00:00
|
|
|
return false;
|
2008-08-08 05:56:43 +00:00
|
|
|
}
|
|
|
|
|
|
2016-12-01 16:51:03 +00:00
|
|
|
# Don't autoblock for system blocks
|
|
|
|
|
if ( $this->getSystemBlockType() !== null ) {
|
|
|
|
|
throw new MWException( 'Cannot autoblock from a system block' );
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-18 00:29:32 +00:00
|
|
|
# Check for presence on the autoblock whitelist.
|
2011-03-22 17:18:15 +00:00
|
|
|
if ( self::isWhitelistedFromAutoblocks( $autoblockIP ) ) {
|
2011-03-22 11:22:15 +00:00
|
|
|
return false;
|
2008-08-08 05:56:43 +00:00
|
|
|
}
|
2010-02-14 22:07:30 +00:00
|
|
|
|
2017-01-01 23:07:11 +00:00
|
|
|
// Avoid PHP 7.1 warning of passing $this by reference
|
|
|
|
|
$block = $this;
|
2011-06-18 00:29:32 +00:00
|
|
|
# Allow hooks to cancel the autoblock.
|
2017-01-01 23:07:11 +00:00
|
|
|
if ( !Hooks::run( 'AbortAutoblock', [ $autoblockIP, &$block ] ) ) {
|
2009-01-13 20:28:54 +00:00
|
|
|
wfDebug( "Autoblock aborted by hook.\n" );
|
2008-05-23 10:34:11 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2006-11-22 11:51:49 +00:00
|
|
|
|
2011-06-18 00:29:32 +00:00
|
|
|
# It's okay to autoblock. Go ahead and insert/update the block...
|
2006-11-22 11:51:49 +00:00
|
|
|
|
2011-06-18 00:29:32 +00:00
|
|
|
# Do not add a *new* block if the IP is already blocked.
|
2017-07-23 01:24:09 +00:00
|
|
|
$ipblock = self::newFromTarget( $autoblockIP );
|
2006-11-08 09:54:06 +00:00
|
|
|
if ( $ipblock ) {
|
2011-06-18 00:29:32 +00:00
|
|
|
# Check if the block is an autoblock and would exceed the user block
|
|
|
|
|
# if renewed. If so, do nothing, otherwise prolong the block time...
|
2013-05-15 01:12:35 +00:00
|
|
|
if ( $ipblock->mAuto && // @todo Why not compare $ipblock->mExpiry?
|
2019-03-22 15:16:40 +00:00
|
|
|
$this->getExpiry() > self::getAutoblockExpiry( $ipblock->getTimestamp() )
|
2010-05-30 14:48:30 +00:00
|
|
|
) {
|
2011-06-18 00:29:32 +00:00
|
|
|
# Reset block timestamp to now and its expiry to
|
|
|
|
|
# $wgAutoblockExpiry in the future
|
2007-03-31 17:23:10 +00:00
|
|
|
$ipblock->updateTimestamp();
|
|
|
|
|
}
|
2011-03-22 11:22:15 +00:00
|
|
|
return false;
|
2006-11-08 09:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
2011-06-18 00:29:32 +00:00
|
|
|
# Make a new block object with the desired properties.
|
2011-03-23 00:10:46 +00:00
|
|
|
$autoblock = new Block;
|
2011-03-22 17:18:15 +00:00
|
|
|
wfDebug( "Autoblocking {$this->getTarget()}@" . $autoblockIP . "\n" );
|
2011-03-23 00:10:46 +00:00
|
|
|
$autoblock->setTarget( $autoblockIP );
|
|
|
|
|
$autoblock->setBlocker( $this->getBlocker() );
|
2019-03-22 15:16:40 +00:00
|
|
|
$autoblock->setReason(
|
|
|
|
|
wfMessage( 'autoblocker', $this->getTarget(), $this->getReason() )
|
|
|
|
|
->inContentLanguage()->plain()
|
|
|
|
|
);
|
2011-06-24 10:00:35 +00:00
|
|
|
$timestamp = wfTimestampNow();
|
2019-03-25 15:11:26 +00:00
|
|
|
$autoblock->setTimestamp( $timestamp );
|
2011-03-23 00:10:46 +00:00
|
|
|
$autoblock->mAuto = 1;
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
$autoblock->isCreateAccountBlocked( $this->isCreateAccountBlocked() );
|
2007-03-14 05:24:06 +00:00
|
|
|
# Continue suppressing the name if needed
|
2019-03-22 15:16:40 +00:00
|
|
|
$autoblock->setHideName( $this->getHideName() );
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
$autoblock->isUsertalkEditAllowed( $this->isUsertalkEditAllowed() );
|
2012-03-28 02:44:32 +00:00
|
|
|
$autoblock->mParentBlockId = $this->mId;
|
2018-08-16 04:55:55 +00:00
|
|
|
$autoblock->isSitewide( $this->isSitewide() );
|
|
|
|
|
$autoblock->setRestrictions( $this->getRestrictions() );
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2019-03-22 15:16:40 +00:00
|
|
|
if ( $this->getExpiry() == 'infinity' ) {
|
2011-03-23 00:10:46 +00:00
|
|
|
# Original block was indefinite, start an autoblock now
|
2019-03-22 15:16:40 +00:00
|
|
|
$autoblock->setExpiry( self::getAutoblockExpiry( $timestamp ) );
|
2006-11-08 09:54:06 +00:00
|
|
|
} else {
|
2011-03-23 00:10:46 +00:00
|
|
|
# If the user is already blocked with an expiry date, we don't
|
|
|
|
|
# want to pile on top of that.
|
2019-03-22 15:16:40 +00:00
|
|
|
$autoblock->setExpiry( min( $this->getExpiry(), self::getAutoblockExpiry( $timestamp ) ) );
|
2006-11-08 09:54:06 +00:00
|
|
|
}
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2011-06-18 00:29:32 +00:00
|
|
|
# Insert the block...
|
2011-03-23 00:10:46 +00:00
|
|
|
$status = $autoblock->insert();
|
|
|
|
|
return $status
|
|
|
|
|
? $status['id']
|
|
|
|
|
: false;
|
2006-11-08 09:54:06 +00:00
|
|
|
}
|
|
|
|
|
|
2008-09-21 14:22:23 +00:00
|
|
|
/**
|
|
|
|
|
* Check if a block has expired. Delete it if it is.
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return bool
|
2008-09-21 14:22:23 +00:00
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public function deleteIfExpired() {
|
2003-09-01 13:13:56 +00:00
|
|
|
if ( $this->isExpired() ) {
|
2005-01-11 08:05:22 +00:00
|
|
|
wfDebug( "Block::deleteIfExpired() -- deleting\n" );
|
2003-09-01 13:13:56 +00:00
|
|
|
$this->delete();
|
2005-10-22 20:52:30 +00:00
|
|
|
$retVal = true;
|
2003-09-01 13:13:56 +00:00
|
|
|
} else {
|
2005-01-11 08:05:22 +00:00
|
|
|
wfDebug( "Block::deleteIfExpired() -- not expired\n" );
|
2005-10-22 20:52:30 +00:00
|
|
|
$retVal = false;
|
2003-09-01 13:13:56 +00:00
|
|
|
}
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2005-10-22 20:52:30 +00:00
|
|
|
return $retVal;
|
2003-09-01 13:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
2008-09-21 14:22:23 +00:00
|
|
|
/**
|
|
|
|
|
* Has the block expired?
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return bool
|
2008-09-21 14:22:23 +00:00
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public function isExpired() {
|
2011-06-24 10:00:35 +00:00
|
|
|
$timestamp = wfTimestampNow();
|
|
|
|
|
wfDebug( "Block::isExpired() checking current " . $timestamp . " vs $this->mExpiry\n" );
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2019-03-22 15:16:40 +00:00
|
|
|
if ( !$this->getExpiry() ) {
|
2004-02-16 00:05:25 +00:00
|
|
|
return false;
|
|
|
|
|
} else {
|
2019-03-22 15:16:40 +00:00
|
|
|
return $timestamp > $this->getExpiry();
|
2004-02-16 00:05:25 +00:00
|
|
|
}
|
2003-09-01 13:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
2008-09-21 14:22:23 +00:00
|
|
|
/**
|
|
|
|
|
* Is the block address valid (i.e. not a null string?)
|
2019-03-27 16:36:30 +00:00
|
|
|
*
|
|
|
|
|
* @deprecated since 1.33 No longer needed in core.
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return bool
|
2008-09-21 14:22:23 +00:00
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public function isValid() {
|
2019-03-27 16:36:30 +00:00
|
|
|
wfDeprecated( __METHOD__, '1.33' );
|
2011-03-22 17:18:15 +00:00
|
|
|
return $this->getTarget() != null;
|
2003-09-01 13:13:56 +00:00
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2008-09-21 14:22:23 +00:00
|
|
|
/**
|
2010-02-14 22:07:30 +00:00
|
|
|
* Update the timestamp on autoblocks.
|
2008-09-21 14:22:23 +00:00
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public function updateTimestamp() {
|
2004-02-27 08:25:56 +00:00
|
|
|
if ( $this->mAuto ) {
|
2019-03-25 15:11:26 +00:00
|
|
|
$this->setTimestamp( wfTimestamp() );
|
2019-03-22 15:16:40 +00:00
|
|
|
$this->setExpiry( self::getAutoblockExpiry( $this->getTimestamp() ) );
|
2004-02-27 08:25:56 +00:00
|
|
|
|
2007-01-22 23:50:42 +00:00
|
|
|
$dbw = wfGetDB( DB_MASTER );
|
2005-08-02 13:35:19 +00:00
|
|
|
$dbw->update( 'ipblocks',
|
2016-02-17 09:09:32 +00:00
|
|
|
[ /* SET */
|
2019-03-22 15:16:40 +00:00
|
|
|
'ipb_timestamp' => $dbw->timestamp( $this->getTimestamp() ),
|
|
|
|
|
'ipb_expiry' => $dbw->timestamp( $this->getExpiry() ),
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
|
|
|
|
[ /* WHERE */
|
2016-03-03 02:48:08 +00:00
|
|
|
'ipb_id' => $this->getId(),
|
2016-02-17 09:09:32 +00:00
|
|
|
],
|
2011-03-22 17:18:15 +00:00
|
|
|
__METHOD__
|
2004-07-10 03:09:26 +00:00
|
|
|
);
|
2004-02-14 12:37:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
2005-08-02 13:35:19 +00:00
|
|
|
|
2011-03-19 23:47:08 +00:00
|
|
|
/**
|
|
|
|
|
* Get the IP address at the start of the range in Hex form
|
2012-10-07 23:35:26 +00:00
|
|
|
* @throws MWException
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return string IP in Hex form
|
2011-03-19 23:47:08 +00:00
|
|
|
*/
|
2011-03-20 17:43:17 +00:00
|
|
|
public function getRangeStart() {
|
2013-04-26 14:42:31 +00:00
|
|
|
switch ( $this->type ) {
|
2011-03-19 23:47:08 +00:00
|
|
|
case self::TYPE_USER:
|
2011-06-07 18:13:21 +00:00
|
|
|
return '';
|
2011-03-19 23:47:08 +00:00
|
|
|
case self::TYPE_IP:
|
|
|
|
|
return IP::toHex( $this->target );
|
|
|
|
|
case self::TYPE_RANGE:
|
2011-03-22 17:18:15 +00:00
|
|
|
list( $start, /*...*/ ) = IP::parseRange( $this->target );
|
|
|
|
|
return $start;
|
2013-04-11 05:29:05 +00:00
|
|
|
default:
|
|
|
|
|
throw new MWException( "Block with invalid type" );
|
2011-03-19 23:47:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2013-06-23 01:01:26 +00:00
|
|
|
* Get the IP address at the end of the range in Hex form
|
2012-10-07 23:35:26 +00:00
|
|
|
* @throws MWException
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return string IP in Hex form
|
2011-03-19 23:47:08 +00:00
|
|
|
*/
|
2011-03-20 17:43:17 +00:00
|
|
|
public function getRangeEnd() {
|
2013-04-26 14:42:31 +00:00
|
|
|
switch ( $this->type ) {
|
2011-03-19 23:47:08 +00:00
|
|
|
case self::TYPE_USER:
|
2011-06-07 18:13:21 +00:00
|
|
|
return '';
|
2011-03-19 23:47:08 +00:00
|
|
|
case self::TYPE_IP:
|
|
|
|
|
return IP::toHex( $this->target );
|
|
|
|
|
case self::TYPE_RANGE:
|
2011-03-22 17:18:15 +00:00
|
|
|
list( /*...*/, $end ) = IP::parseRange( $this->target );
|
|
|
|
|
return $end;
|
2013-04-11 05:29:05 +00:00
|
|
|
default:
|
|
|
|
|
throw new MWException( "Block with invalid type" );
|
2011-03-19 23:47:08 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-21 18:26:55 +00:00
|
|
|
/**
|
2008-09-21 14:22:23 +00:00
|
|
|
* Get the user id of the blocking sysop
|
2008-09-22 04:52:51 +00:00
|
|
|
*
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return int (0 for foreign users)
|
2006-11-21 18:26:55 +00:00
|
|
|
*/
|
|
|
|
|
public function getBy() {
|
2019-03-21 22:23:31 +00:00
|
|
|
return $this->getBlocker()->getId();
|
2006-11-21 18:26:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-09-21 14:22:23 +00:00
|
|
|
* Get the username of the blocking sysop
|
2008-09-22 04:52:51 +00:00
|
|
|
*
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return string
|
2006-11-21 18:26:55 +00:00
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public function getByName() {
|
2019-03-21 22:23:31 +00:00
|
|
|
return $this->getBlocker()->getName();
|
2005-08-23 16:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
/**
|
|
|
|
|
* Get the block ID
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
|
|
|
|
public function getId() {
|
|
|
|
|
return $this->mId;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-16 04:55:55 +00:00
|
|
|
/**
|
|
|
|
|
* Set the block ID
|
|
|
|
|
*
|
|
|
|
|
* @param int $blockId
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
|
|
|
|
private function setId( $blockId ) {
|
|
|
|
|
$this->mId = (int)$blockId;
|
|
|
|
|
|
|
|
|
|
if ( is_array( $this->restrictions ) ) {
|
2019-04-11 19:54:10 +00:00
|
|
|
$this->restrictions = $this->getBlockRestrictionStore()->setBlockId(
|
|
|
|
|
$blockId, $this->restrictions
|
|
|
|
|
);
|
2018-08-16 04:55:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 15:16:40 +00:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-01 16:51:03 +00:00
|
|
|
/**
|
|
|
|
|
* Get the system block type, if any
|
2017-08-04 14:51:21 +00:00
|
|
|
* @since 1.29
|
2016-12-01 16:51:03 +00:00
|
|
|
* @return string|null
|
|
|
|
|
*/
|
|
|
|
|
public function getSystemBlockType() {
|
|
|
|
|
return $this->systemBlockType;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-22 04:52:51 +00:00
|
|
|
/**
|
|
|
|
|
* Get/set a flag determining whether the master is used for reads
|
2011-06-26 23:01:29 +00:00
|
|
|
*
|
2014-09-16 23:00:19 +00:00
|
|
|
* @param bool|null $x
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return bool
|
2008-09-22 04:52:51 +00:00
|
|
|
*/
|
2009-10-19 11:15:51 +00:00
|
|
|
public function fromMaster( $x = null ) {
|
2005-12-01 10:37:47 +00:00
|
|
|
return wfSetVar( $this->mFromMaster, $x );
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-19 23:47:08 +00:00
|
|
|
/**
|
2014-10-25 00:15:12 +00:00
|
|
|
* Get/set whether the Block is a hardblock (affects logged-in users on a given IP/range)
|
2014-09-16 23:00:19 +00:00
|
|
|
* @param bool|null $x
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return bool
|
2011-03-19 23:47:08 +00:00
|
|
|
*/
|
2011-03-20 17:43:17 +00:00
|
|
|
public function isHardblock( $x = null ) {
|
2011-03-22 17:18:15 +00:00
|
|
|
wfSetVar( $this->isHardblock, $x );
|
|
|
|
|
|
|
|
|
|
# You can't *not* hardblock a user
|
|
|
|
|
return $this->getType() == self::TYPE_USER
|
|
|
|
|
? true
|
|
|
|
|
: $this->isHardblock;
|
2011-03-19 23:47:08 +00:00
|
|
|
}
|
|
|
|
|
|
2014-09-16 23:00:19 +00:00
|
|
|
/**
|
|
|
|
|
* @param null|bool $x
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2011-03-21 19:12:41 +00:00
|
|
|
public function isAutoblocking( $x = null ) {
|
2011-03-22 17:18:15 +00:00
|
|
|
wfSetVar( $this->isAutoblocking, $x );
|
|
|
|
|
|
|
|
|
|
# You can't put an autoblock on an IP or range as we don't have any history to
|
|
|
|
|
# look over to get more IPs from
|
|
|
|
|
return $this->getType() == self::TYPE_USER
|
|
|
|
|
? $this->isAutoblocking
|
|
|
|
|
: false;
|
2011-03-21 19:12:41 +00:00
|
|
|
}
|
|
|
|
|
|
2018-08-16 04:55:55 +00:00
|
|
|
/**
|
|
|
|
|
* 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).
|
|
|
|
|
*
|
2019-01-08 12:44:33 +00:00
|
|
|
* @since 1.33
|
2018-08-16 04:55:55 +00:00
|
|
|
* @param null|bool $x
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function isSitewide( $x = null ) {
|
|
|
|
|
return wfSetVar( $this->isSitewide, $x );
|
|
|
|
|
}
|
|
|
|
|
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-19 23:47:08 +00:00
|
|
|
/**
|
|
|
|
|
* Get/set whether the Block prevents a given action
|
2016-06-29 14:45:25 +00:00
|
|
|
*
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
* @deprecated since 1.33, use appliesToRight to determine block
|
|
|
|
|
* behaviour, and specific methods to get/set properties
|
2016-06-29 14:45:25 +00:00
|
|
|
* @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.
|
2011-03-19 23:47:08 +00:00
|
|
|
*/
|
2011-03-20 17:43:17 +00:00
|
|
|
public function prevents( $action, $x = null ) {
|
2018-08-27 01:45:18 +00:00
|
|
|
$config = RequestContext::getMain()->getConfig();
|
|
|
|
|
$blockDisablesLogin = $config->get( 'BlockDisablesLogin' );
|
|
|
|
|
$blockAllowsUTEdit = $config->get( 'BlockAllowsUTEdit' );
|
|
|
|
|
|
2016-06-29 14:45:25 +00:00
|
|
|
$res = null;
|
2013-04-26 14:42:31 +00:00
|
|
|
switch ( $action ) {
|
2011-03-19 23:47:08 +00:00
|
|
|
case 'edit':
|
2011-03-21 19:12:41 +00:00
|
|
|
# For now... <evil laugh>
|
2016-06-29 14:45:25 +00:00
|
|
|
$res = true;
|
|
|
|
|
break;
|
2011-03-19 23:47:08 +00:00
|
|
|
case 'createaccount':
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
$res = wfSetVar( $this->blockCreateAccount, $x );
|
2016-06-29 14:45:25 +00:00
|
|
|
break;
|
2011-03-19 23:47:08 +00:00
|
|
|
case 'sendemail':
|
2016-06-29 14:45:25 +00:00
|
|
|
$res = wfSetVar( $this->mBlockEmail, $x );
|
|
|
|
|
break;
|
2018-08-27 01:45:18 +00:00
|
|
|
case 'upload':
|
|
|
|
|
// Until T6995 is completed
|
|
|
|
|
$res = $this->isSitewide();
|
|
|
|
|
break;
|
2011-03-20 17:43:17 +00:00
|
|
|
case 'editownusertalk':
|
2018-12-03 13:20:47 +00:00
|
|
|
// 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
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
wfSetVar( $this->allowUsertalk, $x === null ? null : !$x );
|
2019-03-29 23:20:50 +00:00
|
|
|
$res = !$this->isUsertalkEditAllowed();
|
2018-12-03 13:20:47 +00:00
|
|
|
|
2018-08-27 01:45:18 +00:00
|
|
|
// edit own user talk can be disabled by config
|
|
|
|
|
if ( !$blockAllowsUTEdit ) {
|
|
|
|
|
$res = true;
|
|
|
|
|
}
|
2016-06-29 14:45:25 +00:00
|
|
|
break;
|
|
|
|
|
case 'read':
|
|
|
|
|
$res = false;
|
|
|
|
|
break;
|
2019-01-08 21:14:48 +00:00
|
|
|
case 'purge':
|
|
|
|
|
$res = false;
|
|
|
|
|
break;
|
2016-06-29 14:45:25 +00:00
|
|
|
}
|
2018-08-27 01:45:18 +00:00
|
|
|
if ( !$res && $blockDisablesLogin ) {
|
2016-06-29 14:45:25 +00:00
|
|
|
// 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;
|
2011-03-19 23:47:08 +00:00
|
|
|
}
|
2016-06-29 14:45:25 +00:00
|
|
|
|
|
|
|
|
return $res;
|
2011-03-19 23:47:08 +00:00
|
|
|
}
|
|
|
|
|
|
2008-09-22 04:52:51 +00:00
|
|
|
/**
|
|
|
|
|
* Get the block name, but with autoblocked IPs hidden as per standard privacy policy
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return string Text is escaped
|
2008-09-22 04:52:51 +00:00
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public function getRedactedName() {
|
2006-07-10 06:30:03 +00:00
|
|
|
if ( $this->mAuto ) {
|
2018-09-20 13:16:11 +00:00
|
|
|
return Html::element(
|
2011-03-13 15:14:33 +00:00
|
|
|
'span',
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'class' => 'mw-autoblockid' ],
|
2018-09-20 13:16:11 +00:00
|
|
|
wfMessage( 'autoblockid', $this->mId )->text()
|
2011-03-13 15:14:33 +00:00
|
|
|
);
|
2006-07-10 06:30:03 +00:00
|
|
|
} else {
|
2011-03-22 17:18:15 +00:00
|
|
|
return htmlspecialchars( $this->getTarget() );
|
2006-07-10 06:30:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2008-09-21 14:22:23 +00:00
|
|
|
/**
|
|
|
|
|
* Get a timestamp of the expiry for autoblocks
|
2008-09-22 04:52:51 +00:00
|
|
|
*
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param string|int $timestamp
|
|
|
|
|
* @return string
|
2008-09-21 14:22:23 +00:00
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public static function getAutoblockExpiry( $timestamp ) {
|
2004-02-14 12:37:25 +00:00
|
|
|
global $wgAutoblockExpiry;
|
2010-05-30 14:48:30 +00:00
|
|
|
|
2004-09-07 06:26:15 +00:00
|
|
|
return wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $timestamp ) + $wgAutoblockExpiry );
|
2004-02-14 12:37:25 +00:00
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
|
|
|
|
/**
|
2006-07-10 06:30:03 +00:00
|
|
|
* Purge expired blocks from the ipblocks table
|
|
|
|
|
*/
|
2008-11-30 13:09:19 +00:00
|
|
|
public static function purgeExpired() {
|
2013-04-18 04:35:33 +00:00
|
|
|
if ( wfReadOnly() ) {
|
|
|
|
|
return;
|
2013-01-17 22:25:55 +00:00
|
|
|
}
|
2013-04-18 04:35:33 +00:00
|
|
|
|
2018-02-28 23:54:57 +00:00
|
|
|
DeferredUpdates::addUpdate( new AutoCommitUpdate(
|
2016-01-13 16:54:48 +00:00
|
|
|
wfGetDB( DB_MASTER ),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
function ( IDatabase $dbw, $fname ) {
|
2018-02-23 16:58:58 +00:00
|
|
|
$ids = $dbw->selectFieldValues( 'ipblocks',
|
|
|
|
|
'ipb_id',
|
2016-02-17 09:09:32 +00:00
|
|
|
[ 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ],
|
2016-01-13 16:54:48 +00:00
|
|
|
$fname
|
|
|
|
|
);
|
2018-02-23 16:58:58 +00:00
|
|
|
if ( $ids ) {
|
2019-04-11 19:54:10 +00:00
|
|
|
$blockRestrictionStore = MediaWikiServices::getInstance()->getBlockRestrictionStore();
|
|
|
|
|
$blockRestrictionStore->deleteByBlockId( $ids );
|
|
|
|
|
|
2018-02-23 16:58:58 +00:00
|
|
|
$dbw->delete( 'ipblocks', [ 'ipb_id' => $ids ], $fname );
|
|
|
|
|
}
|
2016-01-13 16:54:48 +00:00
|
|
|
}
|
|
|
|
|
) );
|
2006-07-10 06:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-13 14:47:34 +00:00
|
|
|
/**
|
2011-03-13 21:33:52 +00:00
|
|
|
* Given a target and the target's type, get an existing Block object if possible.
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param string|User|int $specificTarget A block target, which may be one of several types:
|
2011-03-13 14:47:34 +00:00
|
|
|
* * A user to block, in which case $target will be a User
|
|
|
|
|
* * An IP to block, in which case $target will be a User generated by using
|
|
|
|
|
* User::newFromName( $ip, false ) to turn off name validation
|
|
|
|
|
* * An IP range, in which case $target will be a String "123.123.123.123/18" etc
|
2011-03-21 19:12:41 +00:00
|
|
|
* * The ID of an existing block, in the format "#12345" (since pure numbers are valid
|
|
|
|
|
* usernames
|
|
|
|
|
* Calling this with a user, IP address or range will not select autoblocks, and will
|
|
|
|
|
* only select a block where the targets match exactly (so looking for blocks on
|
|
|
|
|
* 1.2.3.4 will not select 1.2.0.0/16 or even 1.2.3.4/32)
|
2018-06-26 21:14:43 +00:00
|
|
|
* @param string|User|int|null $vagueTarget As above, but we will search for *any* block which
|
2011-03-21 19:12:41 +00:00
|
|
|
* affects that target (so for an IP address, get ranges containing that IP; and also
|
2011-05-24 21:04:50 +00:00
|
|
|
* get any relevant autoblocks). Leave empty or blank to skip IP-based lookups.
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param bool $fromMaster Whether to use the DB_MASTER database
|
2011-03-21 19:12:41 +00:00
|
|
|
* @return Block|null (null if no relevant block could be found). The target and type
|
|
|
|
|
* of the returned Block will refer to the actual block which was found, which might
|
|
|
|
|
* not be the same as the target you gave if you used $vagueTarget!
|
2011-03-13 14:47:34 +00:00
|
|
|
*/
|
2011-03-21 19:12:41 +00:00
|
|
|
public static function newFromTarget( $specificTarget, $vagueTarget = null, $fromMaster = false ) {
|
|
|
|
|
list( $target, $type ) = self::parseTarget( $specificTarget );
|
2017-07-23 01:24:09 +00:00
|
|
|
if ( $type == self::TYPE_ID || $type == self::TYPE_AUTO ) {
|
|
|
|
|
return self::newFromID( $target );
|
2011-03-13 14:47:34 +00:00
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
} elseif ( $target === null && $vagueTarget == '' ) {
|
2011-03-22 11:45:18 +00:00
|
|
|
# We're not going to find anything useful here
|
2011-06-27 13:48:01 +00:00
|
|
|
# Be aware that the == '' check is explicit, since empty values will be
|
2017-02-20 22:44:19 +00:00
|
|
|
# passed by some callers (T31116)
|
2011-03-22 11:45:18 +00:00
|
|
|
return null;
|
|
|
|
|
|
2014-03-23 01:28:57 +00:00
|
|
|
} elseif ( in_array(
|
|
|
|
|
$type,
|
2017-07-23 01:24:09 +00:00
|
|
|
[ self::TYPE_USER, self::TYPE_IP, self::TYPE_RANGE, null ] )
|
2014-03-23 01:28:57 +00:00
|
|
|
) {
|
2011-03-21 19:12:41 +00:00
|
|
|
$block = new Block();
|
|
|
|
|
$block->fromMaster( $fromMaster );
|
2011-03-13 14:47:34 +00:00
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $type !== null ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
$block->setTarget( $target );
|
|
|
|
|
}
|
2011-03-13 14:47:34 +00:00
|
|
|
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $block->newLoad( $vagueTarget ) ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
return $block;
|
|
|
|
|
}
|
2011-03-13 14:47:34 +00:00
|
|
|
}
|
2011-12-15 18:57:53 +00:00
|
|
|
return null;
|
2011-03-13 14:47:34 +00:00
|
|
|
}
|
|
|
|
|
|
2012-11-17 23:23:09 +00:00
|
|
|
/**
|
|
|
|
|
* Get all blocks that match any IP from an array of IP addresses
|
|
|
|
|
*
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param array $ipChain List of IPs (strings), usually retrieved from the
|
2017-02-25 21:53:36 +00:00
|
|
|
* X-Forwarded-For header of the request
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param bool $isAnon Exclude anonymous-only blocks if false
|
2016-09-05 20:21:26 +00:00
|
|
|
* @param bool $fromMaster Whether to query the master or replica DB
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return array Array of Blocks
|
2013-05-20 05:52:14 +00:00
|
|
|
* @since 1.22
|
2012-11-17 23:23:09 +00:00
|
|
|
*/
|
|
|
|
|
public static function getBlocksForIPList( array $ipChain, $isAnon, $fromMaster = false ) {
|
2019-01-09 16:24:36 +00:00
|
|
|
if ( $ipChain === [] ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [];
|
2012-11-17 23:23:09 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$conds = [];
|
2016-09-22 02:52:06 +00:00
|
|
|
$proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
|
2012-11-17 23:23:09 +00:00
|
|
|
foreach ( array_unique( $ipChain ) as $ipaddr ) {
|
|
|
|
|
# Discard invalid IP addresses. Since XFF can be spoofed and we do not
|
|
|
|
|
# necessarily trust the header given to us, make sure that we are only
|
|
|
|
|
# checking for blocks on well-formatted IP addresses (IPv4 and IPv6).
|
|
|
|
|
# Do not treat private IP spaces as special as it may be desirable for wikis
|
|
|
|
|
# to block those IP ranges in order to stop misbehaving proxies that spoof XFF.
|
|
|
|
|
if ( !IP::isValid( $ipaddr ) ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
# Don't check trusted IPs (includes local squids which will be in every request)
|
2016-09-22 02:52:06 +00:00
|
|
|
if ( $proxyLookup->isTrustedProxy( $ipaddr ) ) {
|
2012-11-17 23:23:09 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
# Check both the original IP (to check against single blocks), as well as build
|
|
|
|
|
# the clause to check for rangeblocks for the given IP.
|
|
|
|
|
$conds['ipb_address'][] = $ipaddr;
|
|
|
|
|
$conds[] = self::getRangeCond( IP::toHex( $ipaddr ) );
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-09 16:24:36 +00:00
|
|
|
if ( $conds === [] ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [];
|
2012-11-17 23:23:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $fromMaster ) {
|
|
|
|
|
$db = wfGetDB( DB_MASTER );
|
|
|
|
|
} else {
|
2016-09-05 19:55:19 +00:00
|
|
|
$db = wfGetDB( DB_REPLICA );
|
2012-11-17 23:23:09 +00:00
|
|
|
}
|
|
|
|
|
$conds = $db->makeList( $conds, LIST_OR );
|
|
|
|
|
if ( !$isAnon ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
$conds = [ $conds, 'ipb_anon_only' => 0 ];
|
2012-11-17 23:23:09 +00:00
|
|
|
}
|
2017-10-06 17:03:55 +00:00
|
|
|
$blockQuery = self::getQueryInfo();
|
|
|
|
|
$rows = $db->select(
|
|
|
|
|
$blockQuery['tables'],
|
|
|
|
|
array_merge( [ 'ipb_range_start', 'ipb_range_end' ], $blockQuery['fields'] ),
|
2012-11-17 23:23:09 +00:00
|
|
|
$conds,
|
2017-10-06 17:03:55 +00:00
|
|
|
__METHOD__,
|
|
|
|
|
[],
|
|
|
|
|
$blockQuery['joins']
|
2012-11-17 23:23:09 +00:00
|
|
|
);
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$blocks = [];
|
2012-11-17 23:23:09 +00:00
|
|
|
foreach ( $rows as $row ) {
|
|
|
|
|
$block = self::newFromRow( $row );
|
2015-12-30 04:29:10 +00:00
|
|
|
if ( !$block->isExpired() ) {
|
2012-11-17 23:23:09 +00:00
|
|
|
$blocks[] = $block;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $blocks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* From a list of multiple blocks, find the most exact and strongest Block.
|
2014-10-21 19:39:17 +00:00
|
|
|
*
|
2012-11-17 23:23:09 +00:00
|
|
|
* The logic for finding the "best" block is:
|
|
|
|
|
* - Blocks that match the block's target IP are preferred over ones in a range
|
|
|
|
|
* - Hardblocks are chosen over softblocks that prevent account creation
|
|
|
|
|
* - Softblocks that prevent account creation are chosen over other softblocks
|
|
|
|
|
* - Other softblocks are chosen over autoblocks
|
|
|
|
|
* - If there are multiple exact or range blocks at the same level, the one chosen
|
|
|
|
|
* is random
|
2014-10-21 19:39:17 +00:00
|
|
|
* This should be used when $blocks where retrieved from the user's IP address
|
|
|
|
|
* and $ipChain is populated from the same IP address information.
|
2014-07-24 08:08:16 +00:00
|
|
|
*
|
2014-10-21 19:39:17 +00:00
|
|
|
* @param array $blocks Array of Block objects
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param array $ipChain List of IPs (strings). This is used to determine how "close"
|
2017-02-25 21:53:36 +00:00
|
|
|
* a block is to the server, and if a block matches exactly, or is in a range.
|
|
|
|
|
* The order is furthest from the server to nearest e.g., (Browser, proxy1, proxy2,
|
|
|
|
|
* local-squid, ...)
|
2014-09-16 23:00:19 +00:00
|
|
|
* @throws MWException
|
2014-07-24 17:42:24 +00:00
|
|
|
* @return Block|null The "best" block from the list
|
2012-11-17 23:23:09 +00:00
|
|
|
*/
|
2013-04-26 14:42:31 +00:00
|
|
|
public static function chooseBlock( array $blocks, array $ipChain ) {
|
2019-01-09 16:24:36 +00:00
|
|
|
if ( $blocks === [] ) {
|
2012-11-17 23:23:09 +00:00
|
|
|
return null;
|
|
|
|
|
} elseif ( count( $blocks ) == 1 ) {
|
|
|
|
|
return $blocks[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort hard blocks before soft ones and secondarily sort blocks
|
|
|
|
|
// that disable account creation before those that don't.
|
2014-07-20 19:41:41 +00:00
|
|
|
usort( $blocks, function ( Block $a, Block $b ) {
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
$aWeight = (int)$a->isHardblock() . (int)$a->appliesToRight( 'createaccount' );
|
|
|
|
|
$bWeight = (int)$b->isHardblock() . (int)$b->appliesToRight( 'createaccount' );
|
2012-11-17 23:23:09 +00:00
|
|
|
return strcmp( $bWeight, $aWeight ); // highest weight first
|
|
|
|
|
} );
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$blocksListExact = [
|
2012-11-17 23:23:09 +00:00
|
|
|
'hard' => false,
|
|
|
|
|
'disable_create' => false,
|
|
|
|
|
'other' => false,
|
|
|
|
|
'auto' => false
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
|
|
|
|
$blocksListRange = [
|
2012-11-17 23:23:09 +00:00
|
|
|
'hard' => false,
|
|
|
|
|
'disable_create' => false,
|
|
|
|
|
'other' => false,
|
|
|
|
|
'auto' => false
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2012-11-17 23:23:09 +00:00
|
|
|
$ipChain = array_reverse( $ipChain );
|
|
|
|
|
|
2014-09-16 23:00:19 +00:00
|
|
|
/** @var Block $block */
|
2012-11-17 23:23:09 +00:00
|
|
|
foreach ( $blocks as $block ) {
|
|
|
|
|
// Stop searching if we have already have a "better" block. This
|
|
|
|
|
// is why the order of the blocks matters
|
|
|
|
|
if ( !$block->isHardblock() && $blocksListExact['hard'] ) {
|
|
|
|
|
break;
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
} elseif ( !$block->appliesToRight( 'createaccount' ) && $blocksListExact['disable_create'] ) {
|
2012-11-17 23:23:09 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ( $ipChain as $checkip ) {
|
|
|
|
|
$checkipHex = IP::toHex( $checkip );
|
|
|
|
|
if ( (string)$block->getTarget() === $checkip ) {
|
|
|
|
|
if ( $block->isHardblock() ) {
|
|
|
|
|
$blocksListExact['hard'] = $blocksListExact['hard'] ?: $block;
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
} elseif ( $block->appliesToRight( 'createaccount' ) ) {
|
2012-11-17 23:23:09 +00:00
|
|
|
$blocksListExact['disable_create'] = $blocksListExact['disable_create'] ?: $block;
|
|
|
|
|
} elseif ( $block->mAuto ) {
|
|
|
|
|
$blocksListExact['auto'] = $blocksListExact['auto'] ?: $block;
|
|
|
|
|
} else {
|
|
|
|
|
$blocksListExact['other'] = $blocksListExact['other'] ?: $block;
|
|
|
|
|
}
|
|
|
|
|
// We found closest exact match in the ip list, so go to the next Block
|
|
|
|
|
break;
|
2016-02-17 09:09:32 +00:00
|
|
|
} elseif ( array_filter( $blocksListExact ) == []
|
2012-11-17 23:23:09 +00:00
|
|
|
&& $block->getRangeStart() <= $checkipHex
|
|
|
|
|
&& $block->getRangeEnd() >= $checkipHex
|
|
|
|
|
) {
|
|
|
|
|
if ( $block->isHardblock() ) {
|
|
|
|
|
$blocksListRange['hard'] = $blocksListRange['hard'] ?: $block;
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
} elseif ( $block->appliesToRight( 'createaccount' ) ) {
|
2012-11-17 23:23:09 +00:00
|
|
|
$blocksListRange['disable_create'] = $blocksListRange['disable_create'] ?: $block;
|
|
|
|
|
} elseif ( $block->mAuto ) {
|
|
|
|
|
$blocksListRange['auto'] = $blocksListRange['auto'] ?: $block;
|
|
|
|
|
} else {
|
|
|
|
|
$blocksListRange['other'] = $blocksListRange['other'] ?: $block;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
if ( array_filter( $blocksListExact ) == [] ) {
|
2012-11-17 23:23:09 +00:00
|
|
|
$blocksList = &$blocksListRange;
|
|
|
|
|
} else {
|
|
|
|
|
$blocksList = &$blocksListExact;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$chosenBlock = null;
|
|
|
|
|
if ( $blocksList['hard'] ) {
|
|
|
|
|
$chosenBlock = $blocksList['hard'];
|
|
|
|
|
} elseif ( $blocksList['disable_create'] ) {
|
|
|
|
|
$chosenBlock = $blocksList['disable_create'];
|
|
|
|
|
} elseif ( $blocksList['other'] ) {
|
|
|
|
|
$chosenBlock = $blocksList['other'];
|
|
|
|
|
} elseif ( $blocksList['auto'] ) {
|
|
|
|
|
$chosenBlock = $blocksList['auto'];
|
|
|
|
|
} else {
|
|
|
|
|
throw new MWException( "Proxy block found, but couldn't be classified." );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $chosenBlock;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-13 14:47:34 +00:00
|
|
|
/**
|
2013-01-03 10:53:41 +00:00
|
|
|
* 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().
|
2011-06-26 23:01:29 +00:00
|
|
|
*
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param string|int|User|null $target
|
2017-09-09 20:47:04 +00:00
|
|
|
* @return array [ User|String|null, Block::TYPE_ constant|null ]
|
2011-03-13 14:47:34 +00:00
|
|
|
*/
|
2011-03-20 17:43:17 +00:00
|
|
|
public static function parseTarget( $target ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
# We may have been through this before
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( $target instanceof User ) {
|
|
|
|
|
if ( IP::isValid( $target->getName() ) ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [ $target, self::TYPE_IP ];
|
2011-03-21 19:12:41 +00:00
|
|
|
} else {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [ $target, self::TYPE_USER ];
|
2011-03-21 19:12:41 +00:00
|
|
|
}
|
2013-04-20 22:49:30 +00:00
|
|
|
} elseif ( $target === null ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [ null, null ];
|
2011-03-21 19:12:41 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-17 07:48:58 +00:00
|
|
|
$target = trim( $target );
|
|
|
|
|
|
2011-08-12 14:32:05 +00:00
|
|
|
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)
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
2011-08-12 14:32:05 +00:00
|
|
|
User::newFromName( IP::sanitizeIP( $target ), false ),
|
2017-07-23 01:24:09 +00:00
|
|
|
self::TYPE_IP
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2011-08-12 14:32:05 +00:00
|
|
|
|
2017-08-23 00:07:35 +00:00
|
|
|
} elseif ( IP::isValidRange( $target ) ) {
|
2011-08-12 14:32:05 +00:00
|
|
|
# Can't create a User from an IP range
|
2017-07-23 01:24:09 +00:00
|
|
|
return [ IP::sanitizeRange( $target ), self::TYPE_RANGE ];
|
2011-08-12 14:32:05 +00:00
|
|
|
}
|
|
|
|
|
|
2011-07-11 16:53:31 +00:00
|
|
|
# Consider the possibility that this is not a username at all
|
2018-10-04 07:06:00 +00:00
|
|
|
# but actually an old subpage (T31797)
|
2013-04-20 22:49:30 +00:00
|
|
|
if ( strpos( $target, '/' ) !== false ) {
|
2011-07-11 16:53:31 +00:00
|
|
|
# An old subpage, drill down to the user behind it
|
2016-02-17 19:54:59 +00:00
|
|
|
$target = explode( '/', $target )[0];
|
2011-07-11 16:53:31 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-13 14:47:34 +00:00
|
|
|
$userObj = User::newFromName( $target );
|
2011-03-20 17:43:17 +00:00
|
|
|
if ( $userObj instanceof User ) {
|
2011-03-19 16:50:21 +00:00
|
|
|
# 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.
|
2017-07-23 01:24:09 +00:00
|
|
|
return [ $userObj, self::TYPE_USER ];
|
2011-03-13 14:47:34 +00:00
|
|
|
|
2011-03-20 17:43:17 +00:00
|
|
|
} elseif ( preg_match( '/^#\d+$/', $target ) ) {
|
2011-03-13 14:47:34 +00:00
|
|
|
# Autoblock reference in the form "#12345"
|
2017-07-23 01:24:09 +00:00
|
|
|
return [ substr( $target, 1 ), self::TYPE_AUTO ];
|
2011-03-13 14:47:34 +00:00
|
|
|
|
2011-03-19 16:50:21 +00:00
|
|
|
} else {
|
|
|
|
|
# WTF?
|
2016-02-17 09:09:32 +00:00
|
|
|
return [ null, null ];
|
2011-03-13 14:47:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-02-15 19:24:58 +00:00
|
|
|
* 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.
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return int Block::TYPE_ constant, will never be TYPE_ID
|
2011-03-21 19:12:41 +00:00
|
|
|
*/
|
|
|
|
|
public function getType() {
|
|
|
|
|
return $this->mAuto
|
|
|
|
|
? self::TYPE_AUTO
|
|
|
|
|
: $this->type;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-21 23:27:08 +00:00
|
|
|
/**
|
|
|
|
|
* 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.
|
2017-09-09 20:47:04 +00:00
|
|
|
* @return array [ User|String, Block::TYPE_ constant ]
|
2011-05-17 22:03:20 +00:00
|
|
|
* @todo FIXME: This should be an integral part of the Block member variables
|
2011-03-21 23:27:08 +00:00
|
|
|
*/
|
|
|
|
|
public function getTargetAndType() {
|
2016-02-17 09:09:32 +00:00
|
|
|
return [ $this->getTarget(), $this->getType() ];
|
2011-03-21 23:27:08 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
/**
|
|
|
|
|
* Get the target for this particular Block. Note that for autoblocks,
|
2011-03-13 15:14:33 +00:00
|
|
|
* this returns the unredacted name; frontend functions need to call $block->getRedactedName()
|
|
|
|
|
* in this situation.
|
2014-04-23 09:25:56 +00:00
|
|
|
* @return User|string
|
2011-03-13 14:47:34 +00:00
|
|
|
*/
|
2011-03-21 19:12:41 +00:00
|
|
|
public function getTarget() {
|
|
|
|
|
return $this->target;
|
|
|
|
|
}
|
2011-03-13 15:14:33 +00:00
|
|
|
|
2011-12-06 15:23:21 +00:00
|
|
|
/**
|
2019-03-22 15:16:40 +00:00
|
|
|
* Get the block expiry time
|
2011-12-06 15:23:21 +00:00
|
|
|
*
|
2019-03-22 15:16:40 +00:00
|
|
|
* @since 1.19
|
|
|
|
|
* @return string
|
2011-12-06 15:23:21 +00:00
|
|
|
*/
|
|
|
|
|
public function getExpiry() {
|
|
|
|
|
return $this->mExpiry;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 15:16:40 +00:00
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
/**
|
|
|
|
|
* Set the target for this block, and update $this->type accordingly
|
2014-04-23 09:25:56 +00:00
|
|
|
* @param mixed $target
|
2011-03-21 19:12:41 +00:00
|
|
|
*/
|
2012-12-20 15:09:25 +00:00
|
|
|
public function setTarget( $target ) {
|
2011-03-21 19:12:41 +00:00
|
|
|
list( $this->target, $this->type ) = self::parseTarget( $target );
|
2011-03-13 14:47:34 +00:00
|
|
|
}
|
2011-03-13 21:33:52 +00:00
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
/**
|
|
|
|
|
* Get the user who implemented this block
|
2017-09-12 17:12:29 +00:00
|
|
|
* @return User User object. May name a foreign user.
|
2011-03-21 19:12:41 +00:00
|
|
|
*/
|
2012-12-20 15:09:25 +00:00
|
|
|
public function getBlocker() {
|
2011-03-21 19:12:41 +00:00
|
|
|
return $this->blocker;
|
2011-03-13 21:33:52 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
/**
|
|
|
|
|
* Set the user who implemented (or will implement) this block
|
2017-10-25 19:26:53 +00:00
|
|
|
* @param User|string $user Local User object or username string
|
2011-03-21 19:12:41 +00:00
|
|
|
*/
|
2012-12-20 15:09:25 +00:00
|
|
|
public function setBlocker( $user ) {
|
2017-10-25 19:26:53 +00:00
|
|
|
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'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-21 19:12:41 +00:00
|
|
|
$this->blocker = $user;
|
2011-03-13 21:33:52 +00:00
|
|
|
}
|
2013-04-03 21:44:00 +00:00
|
|
|
|
2013-02-07 21:56:54 +00:00
|
|
|
/**
|
|
|
|
|
* Set the 'BlockID' cookie to this block's ID and expiry time. The cookie's expiry will be
|
2016-12-20 12:08:38 +00:00
|
|
|
* the same as the block's, to a maximum of 24 hours.
|
2013-02-07 21:56:54 +00:00
|
|
|
*
|
2017-08-04 14:51:21 +00:00
|
|
|
* @since 1.29
|
|
|
|
|
*
|
2013-02-07 21:56:54 +00:00
|
|
|
* @param WebResponse $response The response on which to set the cookie.
|
|
|
|
|
*/
|
2017-01-18 07:03:05 +00:00
|
|
|
public function setCookie( WebResponse $response ) {
|
2013-02-07 21:56:54 +00:00
|
|
|
// Calculate the default expiry time.
|
2016-12-20 12:08:38 +00:00
|
|
|
$maxExpiryTime = wfTimestamp( TS_MW, wfTimestamp() + ( 24 * 60 * 60 ) );
|
2013-02-07 21:56:54 +00:00
|
|
|
|
|
|
|
|
// Use the Block's expiry time only if it's less than the default.
|
2016-12-20 12:08:38 +00:00
|
|
|
$expiryTime = $this->getExpiry();
|
|
|
|
|
if ( $expiryTime === 'infinity' || $expiryTime > $maxExpiryTime ) {
|
|
|
|
|
$expiryTime = $maxExpiryTime;
|
2013-02-07 21:56:54 +00:00
|
|
|
}
|
|
|
|
|
|
2016-12-20 12:08:38 +00:00
|
|
|
// Set the cookie. Reformat the MediaWiki datetime as a Unix timestamp for the cookie.
|
2017-01-04 03:38:27 +00:00
|
|
|
$expiryValue = DateTime::createFromFormat( 'YmdHis', $expiryTime )->format( 'U' );
|
|
|
|
|
$cookieOptions = [ 'httpOnly' => false ];
|
2017-01-18 07:03:05 +00:00
|
|
|
$cookieValue = $this->getCookieValue();
|
2017-01-04 03:38:27 +00:00
|
|
|
$response->setCookie( 'BlockID', $cookieValue, $expiryValue, $cookieOptions );
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-18 07:03:05 +00:00
|
|
|
/**
|
|
|
|
|
* Unset the 'BlockID' cookie.
|
|
|
|
|
*
|
2017-08-04 14:51:21 +00:00
|
|
|
* @since 1.29
|
|
|
|
|
*
|
2017-01-18 07:03:05 +00:00
|
|
|
* @param WebResponse $response The response on which to unset the cookie.
|
|
|
|
|
*/
|
|
|
|
|
public static function clearCookie( WebResponse $response ) {
|
|
|
|
|
$response->clearCookie( 'BlockID', [ 'httpOnly' => false ] );
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-04 03:38:27 +00:00
|
|
|
/**
|
|
|
|
|
* Get the BlockID cookie's value for this block. This is usually the block ID concatenated
|
|
|
|
|
* with an HMAC in order to avoid spoofing (T152951), but if wgSecretKey is not set will just
|
|
|
|
|
* be the block ID.
|
2017-08-04 14:51:21 +00:00
|
|
|
*
|
|
|
|
|
* @since 1.29
|
|
|
|
|
*
|
2017-01-04 03:38:27 +00:00
|
|
|
* @return string The block ID, probably concatenated with "!" and the HMAC.
|
|
|
|
|
*/
|
|
|
|
|
public function getCookieValue() {
|
|
|
|
|
$config = RequestContext::getMain()->getConfig();
|
|
|
|
|
$id = $this->getId();
|
|
|
|
|
$secretKey = $config->get( 'SecretKey' );
|
|
|
|
|
if ( !$secretKey ) {
|
|
|
|
|
// If there's no secret key, don't append a HMAC.
|
|
|
|
|
return $id;
|
|
|
|
|
}
|
|
|
|
|
$hmac = MWCryptHash::hmac( $id, $secretKey, false );
|
2017-08-11 13:53:17 +00:00
|
|
|
$cookieValue = $id . '!' . $hmac;
|
2017-01-04 03:38:27 +00:00
|
|
|
return $cookieValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the stored ID from the 'BlockID' cookie. The cookie's value is usually a combination of
|
|
|
|
|
* the ID and a HMAC (see Block::setCookie), but will sometimes only be the ID.
|
2017-08-04 14:51:21 +00:00
|
|
|
*
|
|
|
|
|
* @since 1.29
|
|
|
|
|
*
|
2017-01-04 03:38:27 +00:00
|
|
|
* @param string $cookieValue The string in which to find the ID.
|
2017-08-04 14:51:21 +00:00
|
|
|
*
|
2017-08-20 11:20:59 +00:00
|
|
|
* @return int|null The block ID, or null if the HMAC is present and invalid.
|
2017-01-04 03:38:27 +00:00
|
|
|
*/
|
|
|
|
|
public static function getIdFromCookieValue( $cookieValue ) {
|
|
|
|
|
// Extract the ID prefix from the cookie value (may be the whole value, if no bang found).
|
|
|
|
|
$bangPos = strpos( $cookieValue, '!' );
|
|
|
|
|
$id = ( $bangPos === false ) ? $cookieValue : substr( $cookieValue, 0, $bangPos );
|
|
|
|
|
// Get the site-wide secret key.
|
|
|
|
|
$config = RequestContext::getMain()->getConfig();
|
|
|
|
|
$secretKey = $config->get( 'SecretKey' );
|
|
|
|
|
if ( !$secretKey ) {
|
|
|
|
|
// If there's no secret key, just use the ID as given.
|
|
|
|
|
return $id;
|
|
|
|
|
}
|
|
|
|
|
$storedHmac = substr( $cookieValue, $bangPos + 1 );
|
|
|
|
|
$calculatedHmac = MWCryptHash::hmac( $id, $secretKey, false );
|
|
|
|
|
if ( $calculatedHmac === $storedHmac ) {
|
|
|
|
|
return $id;
|
|
|
|
|
} else {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2013-02-07 21:56:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-03 21:44:00 +00:00
|
|
|
/**
|
|
|
|
|
* Get the key and parameters for the corresponding error message.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.22
|
|
|
|
|
* @param IContextSource $context
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function getPermissionsError( IContextSource $context ) {
|
2018-08-27 01:45:18 +00:00
|
|
|
$params = $this->getBlockErrorParams( $context );
|
|
|
|
|
|
|
|
|
|
$msg = 'blockedtext';
|
|
|
|
|
if ( $this->getSystemBlockType() !== null ) {
|
|
|
|
|
$msg = 'systemblockedtext';
|
|
|
|
|
} elseif ( $this->mAuto ) {
|
|
|
|
|
$msg = 'autoblockedtext';
|
|
|
|
|
} elseif ( !$this->isSitewide() ) {
|
|
|
|
|
$msg = 'blockedtext-partial';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
array_unshift( $params, $msg );
|
|
|
|
|
|
|
|
|
|
return $params;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get block information used in different block error messages
|
|
|
|
|
*
|
2019-01-08 12:44:33 +00:00
|
|
|
* @since 1.33
|
2018-08-27 01:45:18 +00:00
|
|
|
* @param IContextSource $context
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public function getBlockErrorParams( IContextSource $context ) {
|
2013-04-03 21:44:00 +00:00
|
|
|
$blocker = $this->getBlocker();
|
|
|
|
|
if ( $blocker instanceof User ) { // local user
|
|
|
|
|
$blockerUserpage = $blocker->getUserPage();
|
|
|
|
|
$link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
|
|
|
|
|
} else { // foreign user
|
|
|
|
|
$link = $blocker;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 15:16:40 +00:00
|
|
|
$reason = $this->getReason();
|
2013-04-03 21:44:00 +00:00
|
|
|
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();
|
2016-12-01 16:51:03 +00:00
|
|
|
$systemBlockType = $this->getSystemBlockType();
|
2013-04-03 21:44:00 +00:00
|
|
|
$lang = $context->getLanguage();
|
2018-08-27 01:45:18 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
return [
|
2013-04-03 21:44:00 +00:00
|
|
|
$link,
|
|
|
|
|
$reason,
|
|
|
|
|
$context->getRequest()->getIP(),
|
|
|
|
|
$this->getByName(),
|
2018-06-20 05:26:57 +00:00
|
|
|
$systemBlockType ?? $this->getId(),
|
2019-03-22 15:16:40 +00:00
|
|
|
$lang->formatExpiry( $this->getExpiry() ),
|
2013-04-03 21:44:00 +00:00
|
|
|
(string)$intended,
|
2019-03-22 15:16:40 +00:00
|
|
|
$lang->userTimeAndDate( $this->getTimestamp(), $context->getUser() ),
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2013-04-03 21:44:00 +00:00
|
|
|
}
|
2018-08-16 04:55:55 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get Restrictions.
|
|
|
|
|
*
|
|
|
|
|
* Getting the restrictions will perform a database query if the restrictions
|
|
|
|
|
* are not already loaded.
|
|
|
|
|
*
|
2019-01-08 12:44:33 +00:00
|
|
|
* @since 1.33
|
2018-08-16 04:55:55 +00:00
|
|
|
* @return Restriction[]
|
|
|
|
|
*/
|
|
|
|
|
public function getRestrictions() {
|
|
|
|
|
if ( $this->restrictions === null ) {
|
|
|
|
|
// If the block id has not been set, then do not attempt to load the
|
|
|
|
|
// restrictions.
|
|
|
|
|
if ( !$this->mId ) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
2019-04-11 19:54:10 +00:00
|
|
|
$this->restrictions = $this->getBlockRestrictionStore()->loadByBlockId( $this->mId );
|
2018-08-16 04:55:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->restrictions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set Restrictions.
|
|
|
|
|
*
|
2019-01-08 12:44:33 +00:00
|
|
|
* @since 1.33
|
2018-08-16 04:55:55 +00:00
|
|
|
* @param Restriction[] $restrictions
|
|
|
|
|
* @return self
|
|
|
|
|
*/
|
|
|
|
|
public function setRestrictions( array $restrictions ) {
|
|
|
|
|
$this->restrictions = array_filter( $restrictions, function ( $restriction ) {
|
|
|
|
|
return $restriction instanceof Restriction;
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
2018-08-27 01:45:18 +00:00
|
|
|
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
/**
|
|
|
|
|
* 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.)
|
|
|
|
|
*
|
2019-02-25 18:35:35 +00:00
|
|
|
* 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).
|
|
|
|
|
*
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
* @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 ) {
|
2019-02-25 18:35:35 +00:00
|
|
|
if ( $this->target instanceof User ) {
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
$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();
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-27 01:45:18 +00:00
|
|
|
/**
|
2018-11-01 14:11:03 +00:00
|
|
|
* Checks if a block applies to a particular title
|
|
|
|
|
*
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
* This check does not consider whether `$this->isUsertalkEditAllowed`
|
2018-11-01 14:11:03 +00:00
|
|
|
* 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).
|
2018-08-27 01:45:18 +00:00
|
|
|
*
|
2018-11-01 14:11:03 +00:00
|
|
|
* @param Title $title
|
2018-08-27 01:45:18 +00:00
|
|
|
* @return bool
|
|
|
|
|
*/
|
2018-11-01 14:11:03 +00:00
|
|
|
public function appliesToTitle( Title $title ) {
|
|
|
|
|
if ( $this->isSitewide() ) {
|
|
|
|
|
return true;
|
2018-08-27 01:45:18 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-01 14:11:03 +00:00
|
|
|
$restrictions = $this->getRestrictions();
|
|
|
|
|
foreach ( $restrictions as $restriction ) {
|
|
|
|
|
if ( $restriction->matches( $title ) ) {
|
|
|
|
|
return true;
|
2018-08-27 01:45:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-01 14:11:03 +00:00
|
|
|
return false;
|
2018-08-27 01:45:18 +00:00
|
|
|
}
|
2018-10-30 18:19:22 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks if a block applies to a particular namespace
|
|
|
|
|
*
|
|
|
|
|
* @since 1.33
|
|
|
|
|
*
|
|
|
|
|
* @param int $ns
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
public function appliesToNamespace( $ns ) {
|
|
|
|
|
if ( $this->isSitewide() ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Blocks do not apply to virtual namespaces.
|
|
|
|
|
if ( $ns < 0 ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$restriction = $this->findRestriction( NamespaceRestriction::TYPE, $ns );
|
|
|
|
|
|
|
|
|
|
return (bool)$restriction;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks if a block applies to a particular page
|
|
|
|
|
*
|
Separate out different functionalities of Block::prevents
Block::prevents plays several different roles:
* acts as get/setter for Boolean properties that correspond to
ipb_create_account, ipb_block_email and ipb_allow_usertalk
* calculates whether a block blocks a given right, based on Block
properties, global configs, white/blacklists and anonymous user
rights
* decides whether a block prevents editing of the target's own
user talk page (listed separately because 'editownusertalk' is
not a right)
This patch:
* renames mDisableUsertalk to allowEditUsertalk (and reverses the
value), to match the field ipb_allow_usertalk and make this logic
easier to follow
* renames mCreateAccount to blockCreateAccount, to make it clear
that the flag blocks account creation when true, and make this
logic easier to follow
* decouples the block that is stored in the database (which now
reflects the form that the admin submitted) and the behaviour of
the block on enforcement (since the properties set by the admin
can be overridden by global configs) - so if the global configs
change, the block behaviour could too
* creates get/setters for blockCreateAccount, mBlockEmail and
allowEditUsertalk properties
* creates appliesToRight, exclusively for checking whether the
block blocks a given right, taking into account the block
properties, global configs and anonymous user rights
* creates appliesToUsertalk, for checking whether the block
blocks a user from editing their own talk page. The block is
unaware of the user trying to make the edit, and this user is not
always the same as the block target, e.g. if the block target is
an IP range. Therefore the user's talk page is passed in to this
method. appliesToUsertalk can be called from anywhere where the
user is known
* uses the get/setters wherever Block::prevents was being used as
such
* uses appliesToRight whenever Block::prevents was being used to
determine if the block blocks a given right
* uses appliesToUsertalk in User::isBlockedFrom
Bug: T211578
Bug: T214508
Change-Id: I0e131696419211319082cb454f4f05297e55d22e
2019-02-09 12:17:54 +00:00
|
|
|
* This check does not consider whether `$this->isUsertalkEditAllowed`
|
2018-10-30 18:19:22 +00:00
|
|
|
* 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 ) {
|
|
|
|
|
if ( $this->isSitewide() ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the pageId is not over zero, the block cannot apply to it.
|
|
|
|
|
if ( $pageId <= 0 ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$restriction = $this->findRestriction( PageRestriction::TYPE, $pageId );
|
|
|
|
|
|
|
|
|
|
return (bool)$restriction;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Find Restriction by type and value.
|
|
|
|
|
*
|
|
|
|
|
* @param string $type
|
|
|
|
|
* @param int $value
|
|
|
|
|
* @return Restriction|null
|
|
|
|
|
*/
|
|
|
|
|
private function findRestriction( $type, $value ) {
|
|
|
|
|
$restrictions = $this->getRestrictions();
|
|
|
|
|
foreach ( $restrictions as $restriction ) {
|
|
|
|
|
if ( $restriction->getType() !== $type ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $restriction->getValue() === $value ) {
|
|
|
|
|
return $restriction;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2019-03-13 16:08:15 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the block should be tracked with a cookie.
|
|
|
|
|
*
|
|
|
|
|
* @since 1.33
|
2019-04-25 12:02:12 +00:00
|
|
|
* @param bool $isAnon The user is logged out
|
2019-03-13 16:08:15 +00:00
|
|
|
* @return bool The block should be tracked with a cookie
|
|
|
|
|
*/
|
2019-04-25 12:02:12 +00:00
|
|
|
public function shouldTrackWithCookie( $isAnon ) {
|
2019-03-13 16:08:15 +00:00
|
|
|
$config = RequestContext::getMain()->getConfig();
|
|
|
|
|
switch ( $this->getType() ) {
|
|
|
|
|
case self::TYPE_IP:
|
|
|
|
|
case self::TYPE_RANGE:
|
2019-04-25 12:02:12 +00:00
|
|
|
return $isAnon && $config->get( 'CookieSetOnIpBlock' );
|
2019-03-13 16:08:15 +00:00
|
|
|
case self::TYPE_USER:
|
2019-04-25 12:02:12 +00:00
|
|
|
return !$isAnon && $config->get( 'CookieSetOnAutoblock' ) && $this->isAutoblocking();
|
2019-03-13 16:08:15 +00:00
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the block prevents a user from resetting their password
|
|
|
|
|
*
|
|
|
|
|
* @since 1.33
|
2019-04-02 10:00:49 +00:00
|
|
|
* @return bool The block blocks password reset
|
2019-03-13 16:08:15 +00:00
|
|
|
*/
|
|
|
|
|
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:
|
2019-04-02 10:00:49 +00:00
|
|
|
return true;
|
2019-03-13 16:08:15 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-11 19:54:10 +00:00
|
|
|
/**
|
|
|
|
|
* Get a BlockRestrictionStore instance
|
|
|
|
|
*
|
|
|
|
|
* @return BlockRestrictionStore
|
|
|
|
|
*/
|
|
|
|
|
private function getBlockRestrictionStore() : BlockRestrictionStore {
|
|
|
|
|
return MediaWikiServices::getInstance()->getBlockRestrictionStore();
|
|
|
|
|
}
|
2003-09-01 13:13:56 +00:00
|
|
|
}
|