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