Completed
Push — master ( 736eaa...f4bae8 )
by Martijn van
02:32
created

IpAccess::respondNoAccess()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 3
eloc 5
nc 2
nop 1
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
 * @return false || string : entry the ip address was matched against
13
 */
14
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...
15
{
16
    /**
17
     * @var array
18
     */
19
    public $allowedIps = array();
20
21
    /**
22
     * @config
23
     * @var array
24
     */
25
    private static $allowed_ips = array();
0 ignored issues
show
Unused Code introduced by
The property $allowed_ips is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
26
27
    /**
28
     * @var string
29
     */
30
    private $ip = '';
31
32
    /**
33
     * IpAccess constructor.
34
     *
35
     * @param string $ip
36
     * @param array $allowedIps
37
     */
38
    public function __construct($ip = '', $allowedIps = array())
39
    {
40
        parent::__construct();
41
        $this->ip = $ip;
42
43
        self::config()->allowed_ips = $allowedIps;
44
    }
45
46
    /**
47
     * @param $ip
48
     */
49
    public function setIp($ip)
50
    {
51
        $this->ip = $ip;
52
    }
53
54
    /**
55
     * @return array
56
     */
57
    public function getAllowedIps()
58
    {
59
        if ($this->allowedIps) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->allowedIps of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
60
            Deprecation::notice('1.1', 'Use the "IpAccess.allowed_ips" config setting instead');
61
            self::config()->allowed_ips = $this->allowedIps;
62
        }
63
        return (array)self::config()->allowed_ips;
64
    }
65
66
    /**
67
     * @return bool
68
     */
69
    public function hasAccess()
70
    {
71
        if (!(bool)Config::inst()->get('IpAccess', 'enabled')
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !(bool) \Config::...$this->matchWildCard();.
Loading history...
72
            || empty($this->getAllowedIps())
73
            || $this->matchExact()
74
            || $this->matchRange()
75
            || $this->matchCIDR()
76
            || $this->matchWildCard())
77
        {
78
            return true;
79
        }
80
81
        return false;
82
    }
83
84
    /**
85
     * @param Controller $controller
86
     * @throws SS_HTTPResponse_Exception
87
     */
88
    public function respondNoAccess(Controller $controller)
89
    {
90
        $response = null;
91
        if (class_exists('ErrorPage', true)) {
92
            $response = ErrorPage::response_for(403);
93
        }
94
        $controller->httpError(403, $response ? $response : 'The requested page could not be found.');
95
    }
96
97
    /**
98
     * @return string
99
     */
100
    public function matchExact()
101
    {
102
        return in_array($this->ip, $this->getAllowedIps()) ? $this->ip : '';
103
    }
104
105
    /**
106
     * Try to match against a ip range
107
     *
108
     * Example : 192.168.1.50-100
109
     *
110
     * @return string
111
     */
112
    public function matchRange()
113
    {
114
        if ($ranges = array_filter($this->getAllowedIps(), function ($ip) {
115
            return strstr($ip, '-');
116
        })
117
        ) {
118
            foreach ($ranges as $range) {
119
                $first = substr($range, 0, strrpos($range, '.') + 1);
120
                $last  = substr(strrchr($range, '.'), 1);
121
                list ($start, $end) = explode('-', $last);
122
                for ($i = $start; $i <= $end; $i++) {
123
                    if ($this->ip === $first . $i) {
124
                        return $range;
125
                    }
126
                }
127
            }
128
        }
129
        return '';
130
    }
131
132
    /**
133
     * Try to match cidr range
134
     *
135
     * Example : 192.168.1.0/24
136
     *
137
     * @return string
138
     */
139
    public function matchCIDR()
140
    {
141
        if ($ranges = array_filter($this->getAllowedIps(), function ($ip) {
142
            return strstr($ip, '/');
143
        })
144
        ) {
145
            foreach ($ranges as $cidr) {
146
                list ($net, $mask) = explode('/', $cidr);
147
                if ((ip2long($this->ip) & ~((1 << (32 - $mask)) - 1)) == ip2long($net)) {
148
                    return $cidr;
149
                }
150
            }
151
        }
152
        return '';
153
    }
154
155
    /**
156
     * Try to match against a range that ends with a wildcard *
157
     *
158
     * Example : 192.168.1.*
159
     * Example : 192.168.*
160
     *
161
     * @return string
162
     */
163
    public function matchWildCard()
164
    {
165
        if ($ranges = array_filter($this->getAllowedIps(), function ($ip) {
166
            return substr($ip, -1) === '*';
167
        })
168
        ) {
169
            foreach ($ranges as $range) {
170
                if (substr($this->ip, 0, strlen(substr($range, 0, -1))) === substr($range, 0, -1)) {
171
                    return $range;
172
                }
173
            }
174
        }
175
        return '';
176
    }
177
178
}
179