MediaWiki REL1_37
BlockUtils.php
Go to the documentation of this file.
1<?php
2
22namespace MediaWiki\Block;
23
29use Status;
30use Wikimedia\IPUtils;
31
47 private $options;
48
51
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}
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
if(ini_get('mbstring.func_overload')) if(!defined('MW_ENTRY_POINT'))
Pre-config setup: Before loading LocalSettings.php.
Definition Setup.php:88
Backend class for blocking utils.
UserNameUtils $userNameUtils
parseBlockTarget( $target)
From an existing block, get the target and the type of target.
__construct(ServiceOptions $options, UserIdentityLookup $userIdentityLookup, UserNameUtils $userNameUtils)
UserIdentityLookup $userIdentityLookup
validateIPv4Range(int $range)
Validate an IPv4 range.
validateTarget( $value)
Validate block target.
validateIPv6Range(int $range)
Validate an IPv6 range.
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
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:44
Interface for objects representing user identity.