MediaWiki  master
BlockUtils.php
Go to the documentation of this file.
1 <?php
2 
22 namespace MediaWiki\Block;
23 
29 use Status;
30 use Wikimedia\IPUtils;
31 
45 class BlockUtils {
47  private $options;
48 
51 
53  private $userNameUtils;
54 
58  public const CONSTRUCTOR_OPTIONS = [
59  'BlockCIDRLimit',
60  ];
61 
67  public function __construct(
71  ) {
72  $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
73  $this->options = $options;
74  $this->userIdentityLookup = $userIdentityLookup;
75  $this->userNameUtils = $userNameUtils;
76  }
77 
91  public function parseBlockTarget( $target ): array {
92  // We may have been through this before
93  if ( $target instanceof UserIdentity ) {
94  if ( IPUtils::isValid( $target->getName() ) ) {
95  return [ $target, AbstractBlock::TYPE_IP ];
96  } else {
97  return [ $target, AbstractBlock::TYPE_USER ];
98  }
99  } elseif ( $target === null ) {
100  return [ null, null ];
101  }
102 
103  $target = trim( $target );
104 
105  if ( IPUtils::isValid( $target ) ) {
106  return [
107  UserIdentityValue::newAnonymous( IPUtils::sanitizeIP( $target ) ),
109  ];
110 
111  } elseif ( IPUtils::isValidRange( $target ) ) {
112  // Can't create a UserIdentity from an IP range
113  return [ IPUtils::sanitizeRange( $target ), AbstractBlock::TYPE_RANGE ];
114  }
115 
116  // Consider the possibility that this is not a username at all
117  // but actually an old subpage (T31797)
118  if ( strpos( $target, '/' ) !== false ) {
119  // An old subpage, drill down to the user behind it
120  $target = explode( '/', $target )[0];
121  }
122 
123  if ( preg_match( '/^#\d+$/', $target ) ) {
124  // Autoblock reference in the form "#12345"
125  return [ substr( $target, 1 ), AbstractBlock::TYPE_AUTO ];
126  }
127 
128  $userFromDB = $this->userIdentityLookup->getUserIdentityByName( $target );
129  if ( $userFromDB instanceof UserIdentity ) {
130  // Note that since numbers are valid usernames, a $target of "12345" will be
131  // considered a UserIdentity. If you want to pass a block ID, prepend a hash "#12345",
132  // since hash characters are not valid in usernames or titles generally.
133  return [ $userFromDB, AbstractBlock::TYPE_USER ];
134  }
135 
136  // TODO: figure out if it makes sense to have users that do not exist in the DB here
137  $canonicalName = $this->userNameUtils->getCanonical( $target );
138  if ( $canonicalName ) {
139  return [
140  new UserIdentityValue( 0, $canonicalName ),
142  ];
143  }
144 
145  return [ null, null ];
146  }
147 
155  public function validateTarget( $value ): Status {
156  list( $target, $type ) = $this->parseBlockTarget( $value );
157 
158  $status = Status::newGood( $target );
159 
160  switch ( $type ) {
162  if ( !$target->isRegistered() ) {
163  $status->fatal(
164  'nosuchusershort',
165  wfEscapeWikiText( $target->getName() )
166  );
167  }
168  break;
169 
171  list( $ip, $range ) = explode( '/', $target, '2' );
172 
173  if ( IPUtils::isIPv4( $ip ) ) {
174  $status->merge( $this->validateIPv4Range( $range ) );
175  } elseif ( IPUtils::isIPv6( $ip ) ) {
176  $status->merge( $this->validateIPv6Range( $range ) );
177  } else {
178  // Something is FUBAR
179  $status->fatal( 'badipaddress' );
180  }
181  break;
182 
184  // All is well
185  break;
186 
187  default:
188  $status->fatal( 'badipaddress' );
189  break;
190  }
191 
192  return $status;
193  }
194 
202  private function validateIPv4Range( int $range ): Status {
203  $status = Status::newGood();
204  $blockCIDRLimit = $this->options->get( 'BlockCIDRLimit' );
205 
206  if ( $blockCIDRLimit['IPv4'] == 32 ) {
207  // Range block effectively disabled
208  $status->fatal( 'range_block_disabled' );
209  } elseif ( $range > 32 ) {
210  // Such a range cannot exist
211  $status->fatal( 'ip_range_invalid' );
212  } elseif ( $range < $blockCIDRLimit['IPv4'] ) {
213  $status->fatal( 'ip_range_toolarge', $blockCIDRLimit['IPv4'] );
214  }
215 
216  return $status;
217  }
218 
226  private function validateIPv6Range( int $range ): Status {
227  $status = Status::newGood();
228  $blockCIDRLimit = $this->options->get( 'BlockCIDRLimit' );
229 
230  if ( $blockCIDRLimit['IPv6'] == 128 ) {
231  // Range block effectively disabled
232  $status->fatal( 'range_block_disabled' );
233  } elseif ( $range > 128 ) {
234  // Dodgy range - such a range cannot exist
235  $status->fatal( 'ip_range_invalid' );
236  } elseif ( $range < $blockCIDRLimit['IPv6'] ) {
237  $status->fatal( 'ip_range_toolarge', $blockCIDRLimit['IPv6'] );
238  }
239 
240  return $status;
241  }
242 }
MediaWiki\User\UserIdentityValue
Value object representing a user's identity.
Definition: UserIdentityValue.php:35
MediaWiki\Block
Definition: AbstractBlock.php:21
MediaWiki\Block\BlockUtils
Backend class for blocking utils.
Definition: BlockUtils.php:45
MediaWiki\Block\BlockUtils\__construct
__construct(ServiceOptions $options, UserIdentityLookup $userIdentityLookup, UserNameUtils $userNameUtils)
Definition: BlockUtils.php:67
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:39
MediaWiki\Block\BlockUtils\$userIdentityLookup
UserIdentityLookup $userIdentityLookup
Definition: BlockUtils.php:50
Status
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:44
MediaWiki\Block\BlockUtils\validateTarget
validateTarget( $value)
Validate block target.
Definition: BlockUtils.php:155
MediaWiki\Config\ServiceOptions
A class for passing options to services.
Definition: ServiceOptions.php:27
MediaWiki\Block\BlockUtils\validateIPv4Range
validateIPv4Range(int $range)
Validate an IPv4 range.
Definition: BlockUtils.php:202
MediaWiki\Block\BlockUtils\$userNameUtils
UserNameUtils $userNameUtils
Definition: BlockUtils.php:53
MediaWiki\Block\Block\TYPE_RANGE
const TYPE_RANGE
Definition: Block.php:43
MediaWiki\Block\BlockUtils\$options
ServiceOptions $options
Definition: BlockUtils.php:47
MediaWiki\User\UserIdentityValue\newAnonymous
static newAnonymous(string $name, $wikiId=self::LOCAL)
Create UserIdentity for an anonymous user.
Definition: UserIdentityValue.php:92
MediaWiki\User\UserIdentityLookup
Definition: UserIdentityLookup.php:33
MediaWiki\Block\BlockUtils\validateIPv6Range
validateIPv6Range(int $range)
Validate an IPv6 range.
Definition: BlockUtils.php:226
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:82
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1459
MediaWiki\Block\Block\TYPE_AUTO
const TYPE_AUTO
Definition: Block.php:44
MediaWiki\Block\Block\TYPE_USER
const TYPE_USER
Definition: Block.php:41
MediaWiki\User\UserNameUtils
UserNameUtils service.
Definition: UserNameUtils.php:42
MediaWiki\Block\BlockUtils\CONSTRUCTOR_OPTIONS
const CONSTRUCTOR_OPTIONS
Definition: BlockUtils.php:58
MediaWiki\Block\BlockUtils\parseBlockTarget
parseBlockTarget( $target)
From an existing block, get the target and the type of target.
Definition: BlockUtils.php:91
MediaWiki\Block\Block\TYPE_IP
const TYPE_IP
Definition: Block.php:42
MediaWiki\Config\ServiceOptions\assertRequiredOptions
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
Definition: ServiceOptions.php:71
$type
$type
Definition: testCompression.php:52