32use Psr\Log\LoggerInterface;
55 public const CONSTRUCTOR_OPTIONS = [
57 'CookieSetOnAutoblock',
117 $fromMaster = !$fromReplica;
123 $checkIpBlocks = $request &&
124 !$this->permissionManager->userHasRight( $user,
'ipblock-exempt' );
126 if ( $request && $checkIpBlocks ) {
129 $ip = $request->getIP();
135 } elseif ( $request ) {
154 if ( count( $blocks ) > 0 ) {
155 if ( count( $blocks ) === 1 ) {
156 $block = $blocks[ 0 ];
160 'byText' =>
'MediaWiki default',
161 'reason' =>
wfMessage(
'blockedtext-composite-reason' )->plain(),
162 'originalBlocks' => $blocks,
167 Hooks::run(
'GetUserBlock', [ clone $user, $ip, &$block ] );
183 $blocks[] = $cookieBlock;
197 $ip = $request->
getIP();
200 if ( !in_array( $ip, $this->options->get(
'ProxyWhitelist' ) ) ) {
204 'byText' =>
wfMessage(
'proxyblocker' )->text(),
205 'reason' =>
wfMessage(
'proxyblockreason' )->plain(),
207 'systemBlock' =>
'proxy',
211 'byText' =>
wfMessage(
'sorbs' )->text(),
212 'reason' =>
wfMessage(
'sorbsreason' )->plain(),
214 'systemBlock' =>
'dnsbl',
220 if ( $isAnon && IP::isInRanges( $ip, $this->options->get(
'SoftBlockRanges' ) ) ) {
223 'byText' =>
'MediaWiki default',
224 'reason' =>
wfMessage(
'softblockrangesreason', $ip )->plain(),
226 'systemBlock' =>
'wgSoftBlockRanges',
231 if ( $this->options->get(
'ApplyIpBlocksToXff' )
232 && !in_array( $ip, $this->options->get(
'ProxyWhitelist' ) )
234 $xff = $request->
getHeader(
'X-Forwarded-For' );
235 $xff = array_map(
'trim', explode(
',', $xff ) );
236 $xff = array_diff( $xff, [ $ip ] );
239 $blocks = array_merge( $blocks, $xffblocks );
255 $databaseBlocks = [];
257 foreach ( $blocks as $block ) {
259 $systemBlocks[] = $block;
262 '@phan-var DatabaseBlock $block';
263 if ( !isset( $databaseBlocks[$block->getParentBlockId()] ) ) {
264 $databaseBlocks[$block->getParentBlockId()] = $block;
267 $databaseBlocks[$block->getId()] = $block;
271 return array_values( array_merge( $systemBlocks, $databaseBlocks ) );
286 $cookieValue = $request->
getCookie(
'BlockID' );
287 if ( is_null( $cookieValue ) ) {
292 if ( !is_null( $blockCookieId ) ) {
323 $this->options->get(
'CookieSetOnIpBlock' );
326 $this->options->get(
'CookieSetOnAutoblock' );
341 $proxyList = $this->options->get(
'ProxyList' );
346 if ( !is_array( $proxyList ) ) {
348 $proxyList = array_map(
'trim', file( $proxyList ) );
351 $proxyListIPSet =
new IPSet( $proxyList );
352 return $proxyListIPSet->match( $ip );
363 if ( !$this->options->get(
'EnableDnsBlacklist' ) ||
364 ( $checkWhitelist && in_array( $ip, $this->options->get(
'ProxyWhitelist' ) ) )
369 return $this->
inDnsBlacklist( $ip, $this->options->get(
'DnsBlacklistUrls' ) );
382 if ( IP::isIPv4( $ip ) ) {
384 $ipReversed = implode(
'.', array_reverse( explode(
'.', $ip ) ) );
386 foreach ( $bases as
$base ) {
390 if ( is_array(
$base ) ) {
391 if ( count(
$base ) >= 2 ) {
393 $hostname =
"{$base[1]}.$ipReversed.{$base[0]}";
395 $hostname =
"$ipReversed.{$base[0]}";
397 $basename =
$base[0];
399 $hostname =
"$ipReversed.$base";
407 "Hostname $hostname is {$ipList[0]}, it's a proxy says $basename!"
413 $this->logger->debug(
"Requested $hostname, not found in $basename." );
427 return gethostbynamel( $hostname );
438 if ( $request->getCookie(
'BlockID' ) !==
null ) {
445 DeferredUpdates::addCallableUpdate(
446 function () use ( $user, $request ) {
449 $isAnon = $user->
isAnon();
454 foreach ( $block->getOriginalBlocks() as $originalBlock ) {
455 if ( $this->shouldTrackBlockWithCookie( $originalBlock, $isAnon ) ) {
456 '@phan-var DatabaseBlock $originalBlock';
457 $this->setBlockCookie( $originalBlock, $response );
463 '@phan-var DatabaseBlock $block';
469 DeferredUpdates::PRESEND
494 $expiryValue = DateTime::createFromFormat(
497 new DateTimeZone(
'UTC' )
499 $cookieOptions = [
'httpOnly' => false ];
500 $cookieValue = $this->getCookieValue( $block );
501 $response->setCookie(
'BlockID', $cookieValue, $expiryValue, $cookieOptions );
516 return $isAnon && $this->options->get(
'CookieSetOnIpBlock' );
519 $this->options->get(
'CookieSetOnAutoblock' ) &&
520 $block->isAutoblocking();
535 $response->clearCookie(
'BlockID', [
'httpOnly' =>
false ] );
550 if ( !is_numeric( substr( $cookieValue, 0, 1 ) ) ) {
555 $bangPos = strpos( $cookieValue,
'!' );
556 $id = ( $bangPos === false ) ? $cookieValue : substr( $cookieValue, 0, $bangPos );
557 if ( !$this->options->get(
'SecretKey' ) ) {
561 $storedHmac = substr( $cookieValue, $bangPos + 1 );
562 $calculatedHmac =
MWCryptHash::hmac( $id, $this->options->get(
'SecretKey' ),
false );
563 if ( $calculatedHmac === $storedHmac ) {
582 $id = $block->
getId();
583 if ( !$this->options->get(
'SecretKey' ) ) {
588 $cookieValue = $id .
'!' . $hmac;
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Class for managing the deferred updates.
A collection of public static functions to play with IP address and IP ranges.
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 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.
getBlock( $fromReplica=true)
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...
response()
Return a handle to WebResponse style object, for setting cookies, headers and other stuff,...
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 ...