MediaWiki master
BlockUtils.php
Go to the documentation of this file.
1<?php
2
22namespace MediaWiki\Block;
23
31use Wikimedia\IPUtils;
32
49 private $options;
50
52 private $userIdentityLookup;
53
55 private $userNameUtils;
56
58 private $wikiId;
59
63 public const CONSTRUCTOR_OPTIONS = [
65 ];
66
73 public function __construct(
74 ServiceOptions $options,
75 UserIdentityLookup $userIdentityLookup,
76 UserNameUtils $userNameUtils,
77 $wikiId = Block::LOCAL
78 ) {
79 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
80 $this->options = $options;
81 $this->userIdentityLookup = $userIdentityLookup;
82 $this->userNameUtils = $userNameUtils;
83 $this->wikiId = $wikiId;
84 }
85
104 public function parseBlockTarget( $target ): array {
105 // We may have been through this before
106 if ( $target instanceof UserIdentity ) {
107 if ( IPUtils::isValid( $target->getName() ) ) {
108 return [ $target, AbstractBlock::TYPE_IP ];
109 } else {
110 return [ $target, AbstractBlock::TYPE_USER ];
111 }
112 } elseif ( $target === null ) {
113 return [ null, null ];
114 }
115
116 $target = trim( $target );
117
118 if ( IPUtils::isValid( $target ) ) {
119 return [
120 UserIdentityValue::newAnonymous( IPUtils::sanitizeIP( $target ), $this->wikiId ),
122 ];
123
124 } elseif ( IPUtils::isValidRange( $target ) ) {
125 // Can't create a UserIdentity from an IP range
126 return [ IPUtils::sanitizeRange( $target ), AbstractBlock::TYPE_RANGE ];
127 }
128
129 if ( preg_match( '/^#\d+$/', $target ) ) {
130 // Autoblock reference in the form "#12345"
131 return [ substr( $target, 1 ), AbstractBlock::TYPE_AUTO ];
132 }
133
134 $userFromDB = $this->userIdentityLookup->getUserIdentityByName( $target );
135 if ( $userFromDB instanceof UserIdentity ) {
136 // Note that since numbers are valid usernames, a $target of "12345" will be
137 // considered a UserIdentity. If you want to pass a block ID, prepend a hash "#12345",
138 // since hash characters are not valid in usernames or titles generally.
139 return [ $userFromDB, AbstractBlock::TYPE_USER ];
140 }
141
142 // Wrap the invalid user in a UserIdentityValue.
143 // This allows validateTarget() to return a "nosuchusershort" message,
144 // which is needed for Special:Block.
145 $canonicalName = $this->userNameUtils->getCanonical( $target );
146 if ( $canonicalName ) {
147 return [
148 new UserIdentityValue( 0, $canonicalName ),
150 ];
151 }
152
153 return [ null, null ];
154 }
155
164 public function parseBlockTargetRow( $row ) {
165 if ( $row->bt_auto ) {
166 return [ $row->bl_id, AbstractBlock::TYPE_AUTO ];
167 } elseif ( isset( $row->bt_user ) ) {
168 if ( isset( $row->bt_user_text ) ) {
169 $user = new UserIdentityValue( $row->bt_user, $row->bt_user_text, $this->wikiId );
170 } else {
171 $user = $this->userIdentityLookup->getUserIdentityByUserId( $row->bt_user );
172 }
173 return [ $user, AbstractBlock::TYPE_USER ];
174 } elseif ( $row->bt_address === null ) {
175 return [ null, null ];
176 } elseif ( IPUtils::isValid( $row->bt_address ) ) {
177 return [
178 UserIdentityValue::newAnonymous( IPUtils::sanitizeIP( $row->bt_address ), $this->wikiId ),
180 ];
181 } elseif ( IPUtils::isValidRange( $row->bt_address ) ) {
182 // Can't create a UserIdentity from an IP range
183 return [ IPUtils::sanitizeRange( $row->bt_address ), AbstractBlock::TYPE_RANGE ];
184 } else {
185 return [ null, null ];
186 }
187 }
188
196 public function validateTarget( $value ): Status {
197 [ $target, $type ] = $this->parseBlockTarget( $value );
198
199 $status = Status::newGood( $target );
200
201 switch ( $type ) {
203 if ( !$target->isRegistered() ) {
204 $status->fatal(
205 'nosuchusershort',
206 wfEscapeWikiText( $target->getName() )
207 );
208 }
209 break;
210
212 [ $ip, $range ] = explode( '/', $target, 2 );
213
214 if ( IPUtils::isIPv4( $ip ) ) {
215 $status->merge( $this->validateIPv4Range( (int)$range ) );
216 } elseif ( IPUtils::isIPv6( $ip ) ) {
217 $status->merge( $this->validateIPv6Range( (int)$range ) );
218 } else {
219 // Something is FUBAR
220 $status->fatal( 'badipaddress' );
221 }
222 break;
223
225 // All is well
226 break;
227
228 default:
229 $status->fatal( 'badipaddress' );
230 break;
231 }
232
233 return $status;
234 }
235
243 private function validateIPv4Range( int $range ): Status {
244 $status = Status::newGood();
245 $blockCIDRLimit = $this->options->get( MainConfigNames::BlockCIDRLimit );
246
247 if ( $blockCIDRLimit['IPv4'] == 32 ) {
248 // Range block effectively disabled
249 $status->fatal( 'range_block_disabled' );
250 } elseif ( $range > 32 ) {
251 // Such a range cannot exist
252 $status->fatal( 'ip_range_invalid' );
253 } elseif ( $range < $blockCIDRLimit['IPv4'] ) {
254 $status->fatal( 'ip_range_toolarge', $blockCIDRLimit['IPv4'] );
255 }
256
257 return $status;
258 }
259
267 private function validateIPv6Range( int $range ): Status {
268 $status = Status::newGood();
269 $blockCIDRLimit = $this->options->get( MainConfigNames::BlockCIDRLimit );
270
271 if ( $blockCIDRLimit['IPv6'] == 128 ) {
272 // Range block effectively disabled
273 $status->fatal( 'range_block_disabled' );
274 } elseif ( $range > 128 ) {
275 // Dodgy range - such a range cannot exist
276 $status->fatal( 'ip_range_invalid' );
277 } elseif ( $range < $blockCIDRLimit['IPv6'] ) {
278 $status->fatal( 'ip_range_toolarge', $blockCIDRLimit['IPv6'] );
279 }
280
281 return $status;
282 }
283}
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
Backend class for blocking utils.
__construct(ServiceOptions $options, UserIdentityLookup $userIdentityLookup, UserNameUtils $userNameUtils, $wikiId=Block::LOCAL)
parseBlockTarget( $target)
From string specification or UserIdentity, get the block target and the type of target.
parseBlockTargetRow( $row)
From a row which must contain bt_auto, bt_user, bt_address and bl_id, and optionally bt_user_text,...
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()
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:54
Value object representing a user's identity.
UserNameUtils service.
Interface for objects representing user identity.