MediaWiki master
BlockUtils.php
Go to the documentation of this file.
1<?php
2
22namespace MediaWiki\Block;
23
31use Wikimedia\IPUtils;
32
48 private ServiceOptions $options;
49 private UserIdentityLookup $userIdentityLookup;
50 private UserNameUtils $userNameUtils;
51
53 private $wikiId;
54
58 public const CONSTRUCTOR_OPTIONS = [
60 ];
61
62 public function __construct(
63 ServiceOptions $options,
64 UserIdentityLookup $userIdentityLookup,
65 UserNameUtils $userNameUtils,
66 /* string|false */ $wikiId = Block::LOCAL
67 ) {
68 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
69 $this->options = $options;
70 $this->userIdentityLookup = $userIdentityLookup;
71 $this->userNameUtils = $userNameUtils;
72 $this->wikiId = $wikiId;
73 }
74
93 public function parseBlockTarget( $target ): array {
94 // We may have been through this before
95 if ( $target instanceof UserIdentity ) {
96 if ( IPUtils::isValid( $target->getName() ) ) {
97 return [ $target, AbstractBlock::TYPE_IP ];
98 } else {
99 return [ $target, AbstractBlock::TYPE_USER ];
100 }
101 } elseif ( $target === null ) {
102 return [ null, null ];
103 }
104
105 $target = trim( $target );
106
107 if ( IPUtils::isValid( $target ) ) {
108 return [
109 UserIdentityValue::newAnonymous( IPUtils::sanitizeIP( $target ), $this->wikiId ),
111 ];
112
113 } elseif ( IPUtils::isValidRange( $target ) ) {
114 // Can't create a UserIdentity from an IP range
115 return [ IPUtils::sanitizeRange( $target ), AbstractBlock::TYPE_RANGE ];
116 }
117
118 if ( preg_match( '/^#\d+$/', $target ) ) {
119 // Autoblock reference in the form "#12345"
120 return [ substr( $target, 1 ), AbstractBlock::TYPE_AUTO ];
121 }
122
123 $userFromDB = $this->userIdentityLookup->getUserIdentityByName( $target );
124 if ( $userFromDB instanceof UserIdentity ) {
125 // Note that since numbers are valid usernames, a $target of "12345" will be
126 // considered a UserIdentity. If you want to pass a block ID, prepend a hash "#12345",
127 // since hash characters are not valid in usernames or titles generally.
128 return [ $userFromDB, AbstractBlock::TYPE_USER ];
129 }
130
131 // Wrap the invalid user in a UserIdentityValue.
132 // This allows validateTarget() to return a "nosuchusershort" message,
133 // which is needed for Special:Block.
134 $canonicalName = $this->userNameUtils->getCanonical( $target );
135 if ( $canonicalName !== false ) {
136 return [
137 new UserIdentityValue( 0, $canonicalName ),
139 ];
140 }
141
142 return [ null, null ];
143 }
144
153 public function parseBlockTargetRow( $row ) {
154 if ( $row->bt_auto ) {
155 return [ $row->bl_id, AbstractBlock::TYPE_AUTO ];
156 } elseif ( isset( $row->bt_user ) ) {
157 if ( isset( $row->bt_user_text ) ) {
158 $user = new UserIdentityValue( $row->bt_user, $row->bt_user_text, $this->wikiId );
159 } else {
160 $user = $this->userIdentityLookup->getUserIdentityByUserId( $row->bt_user );
161 }
162 return [ $user, AbstractBlock::TYPE_USER ];
163 } elseif ( $row->bt_address === null ) {
164 return [ null, null ];
165 } elseif ( IPUtils::isValid( $row->bt_address ) ) {
166 return [
167 UserIdentityValue::newAnonymous( IPUtils::sanitizeIP( $row->bt_address ), $this->wikiId ),
169 ];
170 } elseif ( IPUtils::isValidRange( $row->bt_address ) ) {
171 // Can't create a UserIdentity from an IP range
172 return [ IPUtils::sanitizeRange( $row->bt_address ), AbstractBlock::TYPE_RANGE ];
173 } else {
174 return [ null, null ];
175 }
176 }
177
185 public function validateTarget( $value ): Status {
186 [ $target, $type ] = $this->parseBlockTarget( $value );
187
188 $status = Status::newGood( $target );
189
190 switch ( $type ) {
192 if ( !$target->isRegistered() ) {
193 $status->fatal(
194 'nosuchusershort',
195 wfEscapeWikiText( $target->getName() )
196 );
197 }
198 break;
199
201 [ $ip, $range ] = explode( '/', $target, 2 );
202
203 if ( IPUtils::isIPv4( $ip ) ) {
204 $status->merge( $this->validateIPv4Range( (int)$range ) );
205 } elseif ( IPUtils::isIPv6( $ip ) ) {
206 $status->merge( $this->validateIPv6Range( (int)$range ) );
207 } else {
208 // Something is FUBAR
209 $status->fatal( 'badipaddress' );
210 }
211 break;
212
214 // All is well
215 break;
216
217 default:
218 $status->fatal( 'badipaddress' );
219 break;
220 }
221
222 return $status;
223 }
224
232 private function validateIPv4Range( int $range ): Status {
233 $status = Status::newGood();
234 $blockCIDRLimit = $this->options->get( MainConfigNames::BlockCIDRLimit );
235
236 if ( $blockCIDRLimit['IPv4'] == 32 ) {
237 // Range block effectively disabled
238 $status->fatal( 'range_block_disabled' );
239 } elseif ( $range > 32 ) {
240 // Such a range cannot exist
241 $status->fatal( 'ip_range_invalid' );
242 } elseif ( $range < $blockCIDRLimit['IPv4'] ) {
243 $status->fatal( 'ip_range_toolarge', $blockCIDRLimit['IPv4'] );
244 }
245
246 return $status;
247 }
248
256 private function validateIPv6Range( int $range ): Status {
257 $status = Status::newGood();
258 $blockCIDRLimit = $this->options->get( MainConfigNames::BlockCIDRLimit );
259
260 if ( $blockCIDRLimit['IPv6'] == 128 ) {
261 // Range block effectively disabled
262 $status->fatal( 'range_block_disabled' );
263 } elseif ( $range > 128 ) {
264 // Dodgy range - such a range cannot exist
265 $status->fatal( 'ip_range_invalid' );
266 } elseif ( $range < $blockCIDRLimit['IPv6'] ) {
267 $status->fatal( 'ip_range_toolarge', $blockCIDRLimit['IPv6'] );
268 }
269
270 return $status;
271 }
272}
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.