Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
AutoblockExemptionList
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
4 / 4
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getOnWikiExemptionList
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 getExemptionList
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isExempt
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace MediaWiki\Block;
4
5use Generator;
6use MediaWiki\Config\ServiceOptions;
7use MediaWiki\MainConfigNames;
8use Psr\Log\LoggerInterface;
9use Wikimedia\IPUtils;
10use Wikimedia\Message\ITextFormatter;
11use Wikimedia\Message\MessageValue;
12
13/**
14 * Provides access to the wiki's autoblock exemption list.
15 * @since 1.42
16 */
17class AutoblockExemptionList {
18    /** @internal */
19    public const CONSTRUCTOR_OPTIONS = [
20        MainConfigNames::AutoblockExemptions,
21    ];
22
23    private ServiceOptions $options;
24    private LoggerInterface $logger;
25    /** Should be for the wiki's content language */
26    private ITextFormatter $textFormatter;
27
28    public function __construct(
29        ServiceOptions $options,
30        LoggerInterface $logger,
31        ITextFormatter $textFormatter
32    ) {
33        $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
34        $this->options = $options;
35        $this->logger = $logger;
36        $this->textFormatter = $textFormatter;
37    }
38
39    /** @return Generator<string> */
40    private function getOnWikiExemptionList() {
41        $list = $this->textFormatter->format(
42            MessageValue::new( 'block-autoblock-exemptionlist' )
43        );
44        $lines = explode( "\n", $list );
45
46        foreach ( $lines as $line ) {
47            // List items only
48            if ( !str_starts_with( $line, '*' ) ) {
49                continue;
50            }
51
52            $wlEntry = substr( $line, 1 );
53            $wlEntry = trim( $wlEntry );
54            yield $wlEntry;
55        }
56    }
57
58    /** @return Generator<string> */
59    private function getExemptionList() {
60        // @phan-suppress-next-line PhanTypeInvalidYieldFrom
61        yield from $this->options->get( MainConfigNames::AutoblockExemptions );
62        yield from $this->getOnWikiExemptionList();
63    }
64
65    /**
66     * Checks whether a given IP is on the autoblock exemption list.
67     *
68     * @param string $ip The IP to check
69     * @return bool
70     */
71    public function isExempt( $ip ) {
72        $this->logger->debug( "Checking the autoblock exemption list.." );
73        foreach ( $this->getExemptionList() as $wlEntry ) {
74            $this->logger->debug( "Checking $ip against $wlEntry..." );
75
76            // Is the IP in this range?
77            if ( IPUtils::isInRange( $ip, $wlEntry ) ) {
78                $this->logger->debug( " IP $ip matches $wlEntry, not autoblocking" );
79                return true;
80            } else {
81                $this->logger->debug( " No match" );
82            }
83        }
84
85        return false;
86    }
87}