33use Psr\Log\LoggerInterface;
57 public const CONSTRUCTOR_OPTIONS = [
59 'CookieSetOnAutoblock',
91 $this->hookRunner =
new HookRunner( $hookContainer );
126 public function getUserBlock(
User $user, $request, $fromReplica, $disableIpBlockExemptChecking =
false ) {
127 $fromMaster = !$fromReplica;
133 $checkIpBlocks = $request &&
138 !$disableIpBlockExemptChecking &&
139 !$this->permissionManager->userHasRight( $user,
'ipblock-exempt' );
141 if ( $request && $checkIpBlocks ) {
144 $ip = $request->getIP();
164 if ( count( $blocks ) > 0 ) {
165 if ( count( $blocks ) === 1 ) {
166 $block = $blocks[ 0 ];
170 'reason' =>
new Message(
'blockedtext-composite-reason' ),
171 'originalBlocks' => $blocks,
176 $this->hookRunner->onGetUserBlock( clone $user, $ip, $block );
192 $blocks[] = $cookieBlock;
206 $ip = $request->
getIP();
209 if ( !in_array( $ip, $this->options->get(
'ProxyWhitelist' ) ) ) {
213 'reason' =>
new Message(
'proxyblockreason' ),
215 'systemBlock' =>
'proxy',
219 'reason' =>
new Message(
'sorbsreason' ),
221 'systemBlock' =>
'dnsbl',
227 if ( $isAnon && IPUtils::isInRanges( $ip, $this->options->get(
'SoftBlockRanges' ) ) ) {
230 'reason' =>
new Message(
'softblockrangesreason', [ $ip ] ),
232 'systemBlock' =>
'wgSoftBlockRanges',
237 if ( $this->options->get(
'ApplyIpBlocksToXff' )
238 && !in_array( $ip, $this->options->get(
'ProxyWhitelist' ) )
240 $xff = $request->
getHeader(
'X-Forwarded-For' );
241 $xff = array_map(
'trim', explode(
',', $xff ) );
242 $xff = array_diff( $xff, [ $ip ] );
245 $blocks = array_merge( $blocks, $xffblocks );
261 $databaseBlocks = [];
263 foreach ( $blocks as $block ) {
265 $systemBlocks[] = $block;
268 '@phan-var DatabaseBlock $block';
269 if ( !isset( $databaseBlocks[$block->getParentBlockId()] ) ) {
270 $databaseBlocks[$block->getParentBlockId()] = $block;
273 $databaseBlocks[$block->getId()] = $block;
277 return array_values( array_merge( $systemBlocks, $databaseBlocks ) );
295 $cookieValue = $request->
getCookie(
'BlockID' );
296 if ( $cookieValue ===
null ) {
301 if ( $blockCookieId !==
null ) {
330 $this->options->get(
'CookieSetOnIpBlock' );
333 $this->options->get(
'CookieSetOnAutoblock' );
348 $proxyList = $this->options->get(
'ProxyList' );
353 if ( !is_array( $proxyList ) ) {
355 $proxyList = array_map(
'trim', file( $proxyList ) );
358 $proxyListIPSet =
new IPSet( $proxyList );
359 return $proxyListIPSet->match( $ip );
370 if ( !$this->options->get(
'EnableDnsBlacklist' ) ||
371 ( $checkWhitelist && in_array( $ip, $this->options->get(
'ProxyWhitelist' ) ) )
376 return $this->
inDnsBlacklist( $ip, $this->options->get(
'DnsBlacklistUrls' ) );
389 if ( IPUtils::isIPv4( $ip ) ) {
391 $ipReversed = implode(
'.', array_reverse( explode(
'.', $ip ) ) );
393 foreach ( $bases as
$base ) {
397 if ( is_array(
$base ) ) {
398 if ( count(
$base ) >= 2 ) {
400 $hostname =
"{$base[1]}.$ipReversed.{$base[0]}";
402 $hostname =
"$ipReversed.{$base[0]}";
404 $basename =
$base[0];
406 $hostname =
"$ipReversed.$base";
414 "Hostname $hostname is {$ipList[0]}, it's a proxy says $basename!"
420 $this->logger->debug(
"Requested $hostname, not found in $basename." );
434 return gethostbynamel( $hostname );
459 if ( $request->getCookie(
'BlockID' ) !==
null ) {
473 throw new LogicException( __METHOD__ .
' requires a loaded User object' );
476 throw new LogicException( __METHOD__ .
' must be called pre-send' );
480 $isAnon = $user->
isAnon();
485 foreach ( $block->getOriginalBlocks() as $originalBlock ) {
487 '@phan-var DatabaseBlock $originalBlock';
494 '@phan-var DatabaseBlock $block';
517 if ( $expiryTime ===
'infinity' || $expiryTime > $maxExpiryTime ) {
518 $expiryTime = $maxExpiryTime;
522 $expiryValue = DateTime::createFromFormat(
525 new DateTimeZone(
'UTC' )
527 $cookieOptions = [
'httpOnly' => false ];
529 $response->
setCookie(
'BlockID', $cookieValue, $expiryValue, $cookieOptions );
544 return $isAnon && $this->options->get(
'CookieSetOnIpBlock' );
547 $this->options->get(
'CookieSetOnAutoblock' ) &&
548 $block->isAutoblocking();
563 $response->
clearCookie(
'BlockID', [
'httpOnly' =>
false ] );
578 if ( !is_numeric( substr( $cookieValue, 0, 1 ) ) ) {
583 $bangPos = strpos( $cookieValue,
'!' );
584 $id = ( $bangPos === false ) ? $cookieValue : substr( $cookieValue, 0, $bangPos );
585 if ( !$this->options->get(
'SecretKey' ) ) {
589 $storedHmac = substr( $cookieValue, $bangPos + 1 );
590 $calculatedHmac =
MWCryptHash::hmac( $id, $this->options->get(
'SecretKey' ),
false );
591 if ( $calculatedHmac === $storedHmac ) {
610 $id = $block->
getId();
611 if ( !$this->options->get(
'SecretKey' ) ) {
616 $cookieValue = $id .
'!' . $hmac;
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
static hmac( $data, $key, $raw=true)
Generate an acceptably unstable one-way-hmac of some text making use of the best hash algorithm that ...
The Message class deals with fetching and processing of interface message into a variety of formats.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
getRequest()
Get the WebRequest object to use with this object.
isRegistered()
Alias of isLoggedIn() with a name that describes its actual functionality.
isSafeToLoad()
Test if it's safe to load this User object.
getBlock( $fromReplica=true, $disableIpBlockExemptChecking=false)
Get the block affecting the user, or null if the user is not blocked.
isAnon()
Get whether the user is anonymous.
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
getIP()
Work out the IP address based on various globals For trusted proxies, use the XFF client IP (first of...
getCookie( $key, $prefix=null, $default=null)
Get a cookie from the $_COOKIE jar.
getHeader( $name, $flags=0)
Get a request header, or false if it isn't set.
Allow programs to request this object from WebRequest::response() and handle all outputting (or lack ...
setCookie( $name, $value, $expire=0, $options=[])
Set the browser cookie.
clearCookie( $name, $options=[])
Unset a browser cookie.
headersSent()
Test if headers have been sent.