GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 540f8b...ab9b1d )
by Carsten
03:30
created

IpstackMiddleware::__invoke()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3.009

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 9
cts 10
cp 0.9
rs 9.552
c 0
b 0
f 0
cc 3
nc 3
nop 3
crap 3.009
1
<?php
2
namespace Germania\IpstackClient;
3
4
use Germania\IpstackClient\IpstackClientInterface;
5
use Germania\IpstackClient\IpstackExceptionInterface;
6
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
10
use Psr\Log\LoggerInterface;
11
use Psr\Log\LoggerAwareTrait;
12
use Psr\Log\NullLogger;
13
14
15
/**
16
 * This Slim middlware class finds out the country where the client comes from
17
 * and stores the country code (DE or CH) with PSR-7 Request attribute.
18
 *
19
 * Requirement:
20
 *
21
 *     This middleware requires a ServerRequest attribute called "ip_address"
22
 *     as provided by akrabat's Slim Client IP address middleware 
23
 *     - which therefore must be executed before this one!
24
 *     
25
 *     https://github.com/akrabat/ip-address-middleware
26
 * 
27
 * Basic conecpts:
28
 *
29
 * IP to Geolocation:
30
 *     This class requires an IpstackClient instance provided by germania-kg/ipstack.
31
 *     which asks the "IP to Geolocation" API from ipstack (https://ipstack.com). 
32
 *     Since we currently are using the "free plan", usage is limited to 10.000 API calls per month.
33
 */
34
class IpstackMiddleware
35
{
36
    use LoggerAwareTrait;
37
38
39
    /**
40
     * Maps ipstack response fields to Request attribute Names. 
41
     * 
42
     * Array keys are ipstack fields, values are attribute names,
43
     * for example:
44
     *
45
     *     array(
46
     *          "country_code" => "X-IpstackCountryCode",
47
     *          "language"     => "X-IpstackLanguage"
48
     *     );
49
     * 
50
     * @var array
51
     */
52
    public $ipstack_attributes = array();
53
54
55
    /**
56
     * Specifies the ipstack response fields that will be requested always.
57
     * 
58
     * @see https://ipstack.com/documentation#fields
59
     * @var array
60
     */
61
    public $ipstack_default_fields = array("ip", "country_code", "country_name");
62
63
64
    /**
65
     * Request attribute with IP address as described here:
66
     * http://www.slimframework.com/docs/v3/cookbook/ip-address.html
67
     * 
68
     * @var string
69
     */
70
    public $ip_address_attribute = "ip_address";
71
72
73
    /**
74
     * Request attribute to store the full ipstack information
75
     * 
76
     * @var string
77
     */
78
    public $ipstack_attribute = "ipstack";
79
80
81
    /**
82
     * @var IpstackClientInterface
83
     */
84
    public $ipstack_client;
85
86
87
    /**
88
     * @param IpstackClientInterface $ipstack_client       IpstackClient
89
     * @param string                 $ip_address_attribute Optional: Request attribute name with Client IP address
90
     * @param array                  $request_attributes   Optional: Map ipstack fields to request attributes
0 ignored issues
show
Bug introduced by
There is no parameter named $request_attributes. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
91
     * @param LoggerInterface|null   $logger               Optional: PSR-3 Logger
92
     */
93 48
    public function __construct( IpstackClientInterface $ipstack_client, string $ip_address_attribute = null, array $ipstack_attributes = array(), LoggerInterface $logger = null )
94
    {
95 48
        $this->ipstack_client       = $ipstack_client;        
96 48
        $this->ip_address_attribute = $ip_address_attribute;        
97 48
        $this->ipstack_attributes   = $ipstack_attributes;
98
        
99 48
        $this->setLogger( $logger ?: new NullLogger );
100 48
    }
101
102
103
    /**
104
     * @param  ServerRequestInterface $request
105
     * @param  ResponseInterface      $response
106
     * @param  callable               $next
107
     *
108
     * @return ResponseInterface
109
     */
110 40
    public function __invoke( ServerRequestInterface $request, ResponseInterface $response, callable $next )
111
    {
112
113
        // Get IP address
114 40
        $client_ip = $this->getClientIp( $request );
115
116 40
        if (!$valid = $this->assertClientIp( $client_ip )):
117 24
            $this->logger->info("Force Status 400 response");
118 24
            return $response->withStatus( 400 );
119
        endif;
120
121
        // Ask IpstackClient and store result in Request
122 16
        $ipstack = $this->askIpStack( $client_ip );
123 16
        $request = $request->withAttribute( $this->ipstack_attribute, $ipstack);
124
125
        // Map certain ipstack fields to custom request attributes
126 16
        foreach( $this->ipstack_attributes as $field => $attr_name):
127
            $request = $request->withAttribute($attr_name, $ipstack[ $field ] ?? null );
128
        endforeach;
129
130
        // Call $next middleware, return response
131 16
        return $next($request, $response);
132
    }
133
134
135
136
    /**
137
     * Returns the client's IP, either from request attribute name or REMOTE_ADDR.
138
     * 
139
     * @param  ServerRequestInterface $request The request
140
     * @return string                          Client IP address string
141
     */
142 40
	protected function getClientIp(ServerRequestInterface $request) : string
143
    {
144 40
        if (!empty($this->ip_address_attribute)):
145 20
        	$client_ip = $request->getAttribute( $this->ip_address_attribute );
146 20
        	$log_msg = "Use IP from Request attribute";
147 20
        	$ip_src  = $this->ip_address_attribute;
148
        else:
149 20
	    	$serverParams = $request->getServerParams();
150 20
	    	$client_ip = $serverParams['REMOTE_ADDR'] ?? "";
151
152 20
        	$log_msg = "Use IP from SERVER";
153 20
        	$ip_src  = "REMOTE_ADDR";
154
        endif;
155
156 40
    	$this->logger->debug($log_msg, [
157 40
			'src' => $ip_src,
158 40
			'ip' => $client_ip
159
    	]);        	
160
161 40
        return $client_ip ?: "";
162
    }
163
164
165
166
    /**
167
     * Asks the ipstack API about information for the given IP.
168
     * 
169
     * If something goes wrong, an array with default values
170
     * will be returned.
171
     *
172
     * @param  string $client_ip
173
     * @return array  ipstack response excerpt.
174
     */
175 16
    protected function askIpStack( string $client_ip ) : array
176
    {
177
    	// Prepare result set
178 16
    	$custom_fields  = array_keys( $this->ipstack_attributes );
179 16
    	$fields         = array_merge($custom_fields, $this->ipstack_default_fields);
180
181 16
    	$default_return = array_fill_keys($fields, null);
182 16
    	$default_return['ip'] = $client_ip;
183
184
    	// The business
185
        try {
186 16
            $ipstack = $this->ipstack_client->get( $client_ip, [
0 ignored issues
show
Unused Code introduced by
The call to IpstackClientInterface::get() has too many arguments starting with array('fields' => join('...s), 'language' => 'de').

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
187 16
                "fields"     => join(",", $fields),
188 16
                "language"   => "de"
189
            ]);
190
191
            // Log things. Make sure to log only default fields
192
            // See "$ipstack_default_fields"
193 16
            $this->logger->notice("Success: ipstack response", [
194 16
                'client_ip'     => $ipstack['ip'],
195 16
                'country_code'  => $ipstack['country_code'],
196 16
                'country_name'  => $ipstack['country_name'],
197
            ]);
198
199
            // Merge ipstack response 
200 16
            $result = array_merge($default_return, $ipstack);
201 16
            return $result;
202
203
        }
204
        catch (IpstackExceptionInterface $e) {
205
        	// At least: 
206
            return $default_return;
207
        }
208
209
    }
210
211
212
213
    /**
214
     * Checks wether a given IP address is not empty and valid IPv4 or IP46.
215
     *
216
     * @param  string $client_ip
217
     * @return bool
218
     */
219 40
    protected function assertClientIp( string $client_ip ) : bool
220
    {
221
222 40
        if (!$client_ip) :
223 16
            $this->logger->error("Empty IP given?!");
224 16
            return false;
225
        endif;
226
        
227 24
        if( filter_var($client_ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) :
228 8
            $this->logger->debug("Valid IPv4 address");
229 8
            return true;
230
        
231 16
        elseif( filter_var($client_ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) :
232 8
            $this->logger->debug("Valid IPv6 address");
233 8
            return true;
234
235
        endif;
236
237 8
        $this->logger->warning("Client IP is neither IPv4 nor IPv6");
238 8
        return false;
239
    }
240
241
}
242