1<?php 2 3/** 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 * http://www.gnu.org/copyleft/gpl.html 18 * 19 * @file 20 */ 21 22namespace MediaWiki\Block; 23 24use MediaWiki\Config\ServiceOptions; 25use MediaWiki\Permissions\Authority; 26use MediaWiki\User\UserFactory; 27use MediaWiki\User\UserIdentity; 28 29/** 30 * Block permissions 31 * 32 * This class is responsible for making sure a user has permission to block 33 * 34 * This class is usable for both blocking as well as 35 * the unblocking process. 36 * 37 * @since 1.35 38 */ 39class BlockPermissionChecker { 40 /** 41 * @var UserIdentity|string|null Block target or null when unknown 42 */ 43 private $target; 44 45 /** 46 * @var int|null One of AbstractBlock::TYPE_* constants, or null when unknown 47 */ 48 private $targetType = null; 49 50 /** 51 * @var Authority Block performer 52 */ 53 private $performer; 54 55 /** 56 * @internal only for use by ServiceWiring and BlockPermissionCheckerFactory 57 */ 58 public const CONSTRUCTOR_OPTIONS = [ 59 'EnableUserEmail', 60 ]; 61 62 /** @var ServiceOptions */ 63 private $options; 64 65 /** @var UserFactory */ 66 private $userFactory; 67 68 /** 69 * @param ServiceOptions $options 70 * @param BlockUtils $blockUtils 71 * @param UserFactory $userFactory 72 * @param UserIdentity|string|null $target 73 * @param Authority $performer 74 */ 75 public function __construct( 76 ServiceOptions $options, 77 BlockUtils $blockUtils, 78 UserFactory $userFactory, 79 $target, 80 Authority $performer 81 ) { 82 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS ); 83 $this->options = $options; 84 $this->userFactory = $userFactory; 85 list( $this->target, $this->targetType ) = $blockUtils->parseBlockTarget( $target ); 86 $this->performer = $performer; 87 } 88 89 /** 90 * Check base permission that apply to either block or unblock 91 * 92 * @since 1.36 93 * @param bool $checkHideuser 94 * @return bool|string 95 */ 96 public function checkBasePermissions( $checkHideuser = false ) { 97 if ( !$this->performer->isAllowed( 'block' ) ) { 98 return 'badaccess-group0'; 99 } 100 101 if ( 102 $checkHideuser && 103 !$this->performer->isAllowed( 'hideuser' ) 104 ) { 105 return 'unblock-hideuser'; 106 } 107 108 return true; 109 } 110 111 /** 112 * Checks block-related permissions (doesn't check any other permissions) 113 * 114 * T17810: Sitewide blocked admins should not be able to block/unblock 115 * others with one exception; they can block the user who blocked them, 116 * to reduce advantage of a malicious account blocking all admins (T150826). 117 * 118 * T208965: Partially blocked admins can block and unblock others as normal. 119 * 120 * @return bool|string True when checks passed, message code for failures 121 */ 122 public function checkBlockPermissions() { 123 $performerIdentity = $this->performer->getUser(); 124 $legacyUser = $this->userFactory->newFromUserIdentity( $performerIdentity ); 125 126 $block = $legacyUser->getBlock(); 127 if ( !$block ) { 128 // User is not blocked, process as normal 129 return true; 130 } 131 132 if ( !$block->isSitewide() ) { 133 // T208965: Partially blocked admins should have full access 134 return true; 135 } 136 137 if ( 138 $this->target instanceof UserIdentity && 139 $this->target->getId() === $performerIdentity->getId() 140 ) { 141 // Blocked admin is trying to alter their own block 142 143 // Self-blocked admins can always remove or alter their block 144 if ( $block->getByName() === $performerIdentity->getName() ) { 145 return true; 146 } 147 148 // Users with 'unblockself' right can unblock themselves or alter their own block 149 if ( $this->performer->isAllowed( 'unblockself' ) ) { 150 return true; 151 } else { 152 return 'ipbnounblockself'; 153 } 154 } 155 156 if ( 157 $this->target instanceof UserIdentity && 158 $block->getByName() === $this->target->getName() 159 ) { 160 // T150826: Blocked admins can always block the admin who blocked them 161 return true; 162 } 163 164 // User is blocked and no exception took effect 165 return 'ipbblocked'; 166 } 167 168 /** 169 * Check permission to block emailing 170 * 171 * @since 1.36 172 * @return bool 173 */ 174 public function checkEmailPermissions() { 175 return $this->options->get( 'EnableUserEmail' ) && 176 $this->performer->isAllowed( 'blockemail' ); 177 } 178} 179