Issues (186)

Branch: master

includes/Providers/XffTrustProvider.php (4 issues)

1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 * ACC Development Team. Please see team.json for a list of contributors.     *
5
 *                                                                            *
6
 * This is free and unencumbered software released into the public domain.    *
7
 * Please see LICENSE.md for the full licencing statement.                    *
8
 ******************************************************************************/
9
10
namespace Waca\Providers;
11
12
use PDOStatement;
13
use Waca\PdoDatabase;
14
use Waca\Providers\Interfaces\IXffTrustProvider;
15
16
/**
17
 * XffTrustProvider short summary.
18
 *
19
 * XffTrustProvider description.
20
 *
21
 * @version 1.0
22
 * @author  stwalkerster
23
 */
24
class XffTrustProvider implements IXffTrustProvider
25
{
26
    /**
27
     * Array of IP addresses which are TRUSTED proxies
28
     * @var string[]
29
     */
30
    private $trustedCache;
31
    /**
32
     * Array of IP addresses which are UNTRUSTED proxies
33
     * @var string[]
34
     */
35
    private $untrustedCache = array();
36
    /** @var PDOStatement */
37
    private $trustedQuery;
38
    /**
39
     * @var PdoDatabase
40
     */
41
    private $database;
42
43
    /**
44
     * Creates a new instance of the trust provider
45
     *
46
     * @param string[]    $squidIpList List of IP addresses to pre-approve
47
     * @param PdoDatabase $database
48
     */
49
    public function __construct($squidIpList, PdoDatabase $database)
50
    {
51
        $this->trustedCache = $squidIpList;
52
        $this->database = $database;
53
    }
54
55
    /**
56
     * Returns a value if the IP address is a trusted proxy
57
     *
58
     * @param string $ip
59
     *
60
     * @return bool
61
     */
62
    public function isTrusted($ip)
63
    {
64
        if (in_array($ip, $this->trustedCache)) {
65
            return true;
66
        }
67
68
        if (in_array($ip, $this->untrustedCache)) {
69
            return false;
70
        }
71
72
        if ($this->trustedQuery === null) {
73
            $query = "SELECT COUNT(id) FROM xfftrustcache WHERE ip = :ip;";
74
            $this->trustedQuery = $this->database->prepare($query);
75
        }
76
77
        $this->trustedQuery->execute(array(":ip" => $ip));
78
        $result = $this->trustedQuery->fetchColumn();
79
        $this->trustedQuery->closeCursor();
80
81
        if ($result == 0) {
82
            $this->untrustedCache[] = $ip;
83
84
            return false;
85
        }
86
87
        if ($result >= 1) {
88
            $this->trustedCache[] = $ip;
89
90
            return true;
91
        }
92
93
        // something weird has happened if we've got here.
94
        // default to untrusted.
95
        return false;
96
    }
97
98
    /**
99
     * Gets the last trusted IP in the proxy chain.
100
     *
101
     * @param string $ip      The IP address from REMOTE_ADDR
102
     * @param string $proxyIp The contents of the XFF header.
103
     *
104
     * @return string Trusted source IP address
105
     */
106
    public function getTrustedClientIp($ip, $proxyIp)
107
    {
108
        $clientIpAddress = $ip;
109
        if ($proxyIp) {
110
            $ipList = explode(",", $proxyIp);
111
            $ipList[] = $clientIpAddress;
112
            $ipList = array_reverse($ipList);
113
114
            foreach ($ipList as $ipNumber => $ipAddress) {
115
                if ($this->isTrusted(trim($ipAddress)) && $ipNumber < (count($ipList) - 1)) {
116
                    continue;
117
                }
118
119
                $clientIpAddress = $ipAddress;
120
                break;
121
            }
122
        }
123
124
        return trim($clientIpAddress);
125
    }
126
127
    /**
128
     * Takes an array( "low" => "high" ) values, and returns true if $needle is in at least one of them.
129
     *
130
     * @param array  $haystack
131
     * @param string $ip
132
     *
133
     * @return bool
134
     */
135
    public function ipInRange($haystack, $ip)
136
    {
137
        $needle = ip2long($ip);
138
139
        foreach ($haystack as $low => $high) {
140
            if (ip2long($low) <= $needle && ip2long($high) >= $needle) {
141
                return true;
142
            }
143
        }
144
145
        return false;
146
    }
147
148
    /**
149
     * Explodes a CIDR range into an array of addresses
150
     *
151
     * @param string $range A CIDR-format range
152
     *
153
     * @return array An array containing every IP address in the range
154
     */
155
    public function explodeCidr($range)
156
    {
157
        $cidrData = explode('/', $range);
158
159
        if (!isset($cidrData[1])) {
160
            return array($range);
161
        }
162
163
        $blow = (
164
            str_pad(decbin(ip2long($cidrData[0])), 32, "0", STR_PAD_LEFT) &
0 ignored issues
show
Are you sure you want to use the bitwise & or did you mean &&?
Loading history...
165
            str_pad(str_pad("", $cidrData[1], "1"), 32, "0")
0 ignored issues
show
$cidrData[1] of type string is incompatible with the type integer expected by parameter $length of str_pad(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

165
            str_pad(str_pad("", /** @scrutinizer ignore-type */ $cidrData[1], "1"), 32, "0")
Loading history...
166
        );
167
        $bhigh = ($blow | str_pad(str_pad("", $cidrData[1], "0"), 32, "1"));
0 ignored issues
show
Are you sure you want to use the bitwise | or did you mean ||?
Loading history...
168
169
        $list = array();
170
171
        $bindecBHigh = bindec($bhigh);
172
        for ($x = bindec($blow); $x <= $bindecBHigh; $x++) {
173
            $list[] = long2ip($x);
0 ignored issues
show
It seems like $x can also be of type double; however, parameter $ip of long2ip() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

173
            $list[] = long2ip(/** @scrutinizer ignore-type */ $x);
Loading history...
174
        }
175
176
        return $list;
177
    }
178
}
179