Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.18% covered (success)
91.18%
31 / 34
80.00% covered (warning)
80.00%
8 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
RangeBlockTarget
91.18% covered (success)
91.18%
31 / 34
80.00% covered (warning)
80.00%
8 / 10
19.25
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLogPage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSpecificity
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 validateForCreation
93.75% covered (success)
93.75%
15 / 16
0.00% covered (danger)
0.00%
0 / 1
6.01
 toHexRange
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
5.02
 getHexRangeStart
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getHexRangeEnd
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLegacyUnion
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace MediaWiki\Block;
4
5use MediaWiki\DAO\WikiAwareEntity;
6use MediaWiki\Page\PageReference;
7use MediaWiki\Page\PageReferenceValue;
8use StatusValue;
9use Wikimedia\IPUtils;
10
11/**
12 * A block target for an IP address range
13 *
14 * @since 1.44
15 */
16class RangeBlockTarget extends BlockTarget implements BlockTargetWithIp {
17    private string $cidr;
18
19    /**
20     * @var array The minimum prefix lengths indexed by protocol (IPv4 or IPv6)
21     */
22    private array $limits;
23
24    /**
25     * @param string $cidr The range specification in CIDR notation
26     * @param array $limits The minimum prefix lengths indexed by protocol (IPv4 or IPv6)
27     * @param string|false $wikiId The wiki ID
28     */
29    public function __construct( string $cidr, array $limits, $wikiId = WikiAwareEntity::LOCAL ) {
30        parent::__construct( $wikiId );
31        $this->cidr = $cidr;
32        $this->limits = $limits;
33    }
34
35    public function toString(): string {
36        return $this->cidr;
37    }
38
39    public function getType(): int {
40        return Block::TYPE_RANGE;
41    }
42
43    public function getLogPage(): PageReference {
44        return new PageReferenceValue( NS_USER, $this->cidr, $this->wikiId );
45    }
46
47    public function getSpecificity() {
48        // This is the number of bits that are allowed to vary in the block, give
49        // or take some floating point errors
50        [ $ip, $bits ] = explode( '/', $this->cidr, 2 );
51        $max = IPUtils::isIPv6( $ip ) ? 128 : 32;
52        $size = $max - (int)$bits;
53
54        // Rank a range block covering a single IP equally with a single-IP block
55        return 2 + ( $size / $max );
56    }
57
58    public function validateForCreation(): StatusValue {
59        $status = StatusValue::newGood();
60        [ $ip, $prefixLength ] = explode( '/', $this->cidr, 2 );
61
62        if ( IPUtils::isIPv4( $ip ) ) {
63            $minLength = $this->limits['IPv4'];
64            $totalLength = 32;
65        } elseif ( IPUtils::isIPv6( $ip ) ) {
66            $minLength = $this->limits['IPv6'];
67            $totalLength = 128;
68        } else {
69            // The factory should not have called the constructor with an invalid range
70            throw new \RuntimeException( 'invalid IP range' );
71        }
72
73        if ( $minLength == $totalLength ) {
74            // Range block effectively disabled
75            $status->fatal( 'range_block_disabled' );
76        } elseif ( $prefixLength > $totalLength ) {
77            // Such a range cannot exist
78            $status->fatal( 'ip_range_invalid' );
79        } elseif ( $prefixLength < $minLength ) {
80            $status->fatal( 'ip_range_toolarge', $minLength );
81        }
82
83        return $status;
84    }
85
86    public function toHexRange() {
87        $range = IPUtils::parseRange( $this->cidr );
88        if ( count( $range ) !== 2 || !is_string( $range[0] ) || !is_string( $range[1] ) ) {
89            throw new \RuntimeException(
90                'Failed to parse range: constructor caller should have validated it' );
91        }
92        return $range;
93    }
94
95    /**
96     * Get the start of the range in hexadecimal form.
97     *
98     * @return string
99     */
100    public function getHexRangeStart(): string {
101        return $this->toHexRange()[0];
102    }
103
104    /**
105     * Get the end of the range in hexadecimal form.
106     *
107     * @return string
108     */
109    public function getHexRangeEnd(): string {
110        return $this->toHexRange()[1];
111    }
112
113    protected function getLegacyUnion() {
114        return $this->cidr;
115    }
116
117}