Completed
Push — master ( 4962bf...d1af8f )
by Martijn van
02:36
created

IpAccess::isEnabled()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
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 (!empty($this->allowedIps)) {
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 isEnabled()
70
    {
71
        return (bool)Config::inst()->get('IpAccess', 'enabled');
72
    }
73
74
    /**
75
     * @return bool
76
     */
77
    public function hasAccess()
78
    {
79
        if(!$this->isEnabled() || empty($this->getAllowedIps())) {
80
            return true;
81
        }
82
83
        return ($this->matchExact() || $this->matchRange() || $this->matchCIDR() || $this->matchWildCard());
84
    }
85
86
    /**
87
     * @param Controller $controller
88
     * @throws SS_HTTPResponse_Exception
89
     */
90
    public function respondNoAccess(Controller $controller)
91
    {
92
        $response = null;
93
        if (class_exists('ErrorPage', true)) {
94
            $response = ErrorPage::response_for(403);
95
        }
96
        $controller->httpError(403, $response ? $response : 'The requested page could not be found.');
97
    }
98
99
    /**
100
     * @return string
101
     */
102
    public function matchExact()
103
    {
104
        return in_array($this->ip, $this->getAllowedIps()) ? $this->ip : '';
105
    }
106
107
    /**
108
     * Try to match against a ip range
109
     *
110
     * Example : 192.168.1.50-100
111
     *
112
     * @return string
113
     */
114
    public function matchRange()
115
    {
116
        $ranges = array_filter($this->getAllowedIps(), function ($ip) {
117
            return strstr($ip, '-');
118
        });
119
120
        if (!$ranges) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ranges 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...
121
            return '';
122
        }
123
124
        $ipFirstPart = substr($this->ip, 0, strrpos($this->ip, '.') + 1);
125
        $ipLastpart  = substr(strrchr($this->ip, '.'), 1);
126
127
        foreach ($ranges as $range) {
128
            $rangeFirstPart = substr($range, 0, strrpos($range, '.') + 1);
129
            list ($start, $end) = explode('-', substr(strrchr($range, '.'), 1));
130
            if($ipFirstPart === $rangeFirstPart && $ipLastpart >= $start && $ipLastpart <= $end) {
131
                return $range;
132
            }
133
        }
134
    }
135
136
    /**
137
     * Try to match cidr range
138
     *
139
     * Example : 192.168.1.0/24
140
     *
141
     * @return string
142
     */
143
    public function matchCIDR()
144
    {
145
        if ($ranges = array_filter($this->getAllowedIps(), function ($ip) {
146
            return strstr($ip, '/');
147
        })
148
        ) {
149
            foreach ($ranges as $cidr) {
150
                list ($net, $mask) = explode('/', $cidr);
151
                if ((ip2long($this->ip) & ~((1 << (32 - $mask)) - 1)) == ip2long($net)) {
152
                    return $cidr;
153
                }
154
            }
155
        }
156
        return '';
157
    }
158
159
    /**
160
     * Try to match against a range that ends with a wildcard *
161
     *
162
     * Example : 192.168.1.*
163
     * Example : 192.168.*
164
     *
165
     * @return string
166
     */
167
    public function matchWildCard()
168
    {
169
        if ($ranges = array_filter($this->getAllowedIps(), function ($ip) {
170
            return substr($ip, -1) === '*';
171
        })
172
        ) {
173
            foreach ($ranges as $range) {
174
                if (substr($this->ip, 0, strlen(substr($range, 0, -1))) === substr($range, 0, -1)) {
175
                    return $range;
176
                }
177
            }
178
        }
179
        return '';
180
    }
181
182
}
183