IpAccess   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 4
dl 0
loc 179
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A setIp() 0 4 1
A getAllowedIps() 0 9 3
A isEnabled() 0 4 1
A hasAccess() 0 8 3
A matchIp() 0 4 4
A respondNoAccess() 0 8 3
A matchExact() 0 4 2
A matchRange() 0 20 3
A matchCIDR() 0 17 4
A matchWildCard() 0 16 4
1
<?php
2
3
/**
4
 * Check Access based on remote IP address.
5
 *
6
 * @Example entries :
7
 * 192.168.178.8
8
 * 192.168.178.0/24
9
 * 192.168.178.0-50
10
 * 192.168.178.*
11
 * 192.168.*
12
 *
13
 * @return false || string : entry the ip address was matched against
14
 */
15
class IpAccess extends Object
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
16
{
17
    /**
18
     * @var array
19
     */
20
    public $allowedIps = [];
21
22
    /**
23
     * @config
24
     *
25
     * @var array
26
     */
27
    private static $allowed_ips = [];
28
29
    /**
30
     * @var string
31
     */
32
    private $ip = '';
33
34
    /**
35
     * IpAccess constructor.
36
     *
37
     * @param string $ip
38
     * @param array  $allowedIps
39
     */
40
    public function __construct($ip = '', $allowedIps = [])
41
    {
42
        parent::__construct();
43
        $this->ip = $ip;
44
45
        self::config()->allowed_ips = $allowedIps;
46
    }
47
48
    /**
49
     * @param $ip
50
     */
51
    public function setIp($ip)
52
    {
53
        $this->ip = $ip;
54
    }
55
56
    /**
57
     * @return array
58
     */
59
    public function getAllowedIps()
60
    {
61
        if (!empty($this->allowedIps)) {
62
            Deprecation::notice('1.1', 'Use the "IpAccess.allowed_ips" config setting instead');
63
            self::config()->allowed_ips = $this->allowedIps;
64
        }
65
66
        return self::$allowed_ips ? self::$allowed_ips : (array) self::config()->allowed_ips;
67
    }
68
69
    /**
70
     * @return bool
71
     */
72
    public function isEnabled()
73
    {
74
        return (bool) Config::inst()->get('IpAccess', 'enabled');
75
    }
76
77
    /**
78
     * @return bool
79
     */
80
    public function hasAccess()
81
    {
82
        if (!$this->isEnabled() || !(bool) $this->getAllowedIps()) {
83
            return true;
84
        }
85
86
        return $this->matchIp();
87
    }
88
89
    /**
90
     * @return bool
91
     */
92
    public function matchIp()
93
    {
94
        return $this->matchExact() || $this->matchRange() || $this->matchCIDR() || $this->matchWildCard();
95
    }
96
97
    /**
98
     * @param Controller $controller
99
     *
100
     * @throws SS_HTTPResponse_Exception
101
     */
102
    public function respondNoAccess(Controller $controller)
103
    {
104
        $response = null;
105
        if (class_exists('ErrorPage', true)) {
106
            $response = ErrorPage::response_for(403);
107
        }
108
        $controller->httpError(403, $response ? $response : 'The requested page could not be found.');
109
    }
110
111
    /**
112
     * @return string
113
     */
114
    public function matchExact()
115
    {
116
        return in_array($this->ip, $this->getAllowedIps()) ? $this->ip : '';
117
    }
118
119
    /**
120
     * Try to match against a ip range
121
     * Example : 192.168.1.50-100.
122
     *
123
     * @return string
124
     */
125
    public function matchRange()
126
    {
127
        $ranges = array_filter($this->getAllowedIps(), function ($ip) {
128
            return strstr($ip, '-');
129
        });
130
131
        $ip = $this->ip;
132
133
        $matches = array_filter($ranges, function ($range) use ($ip) {
134
            $ipFirstPart = substr($ip, 0, strrpos($ip, '.') + 1);
135
            $ipLastPart = substr(strrchr($ip, '.'), 1);
136
            $rangeFirstPart = substr($range, 0, strrpos($range, '.') + 1);
137
138
            list($start, $end) = explode('-', substr(strrchr($range, '.'), 1));
139
140
            return $ipFirstPart === $rangeFirstPart && $ipLastPart >= $start && $ipLastPart <= $end;
141
        });
142
143
        return array_shift($matches);
144
    }
145
146
    /**
147
     * Try to match cidr range
148
     * Example : 192.168.1.0/24.
149
     *
150
     * @return string
151
     */
152
    public function matchCIDR()
153
    {
154
        $ranges = array_filter($this->getAllowedIps(), function ($ip) {
155
            return strstr($ip, '/');
156
        });
157
158
        if (!empty($ranges)) {
159
            foreach ($ranges as $range) {
160
                list($net, $mask) = explode('/', $range);
161
                if ((ip2long($this->ip) & ~((1 << (32 - $mask)) - 1)) == ip2long($net)) {
162
                    return $range;
163
                }
164
            }
165
        }
166
167
        return '';
168
    }
169
170
    /**
171
     * Try to match against a range that ends with a wildcard *
172
     * Example : 192.168.1.*
173
     * Example : 192.168.*.
174
     *
175
     * @return string
176
     */
177
    public function matchWildCard()
178
    {
179
        $ranges = array_filter($this->getAllowedIps(), function ($ip) {
180
            return substr($ip, -1) === '*';
181
        });
182
183
        if (!empty($ranges)) {
184
            foreach ($ranges as $range) {
185
                if (substr($this->ip, 0, strlen(substr($range, 0, -1))) === substr($range, 0, -1)) {
186
                    return $range;
187
                }
188
            }
189
        }
190
191
        return '';
192
    }
193
}
194