Issues (4)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Wheedle/TwitterClient.php (3 issues)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Wheedle;
3
4
use \GuzzleHttp\Client;
5
use \GuzzleHttp\Exception\ClientException;
6
use \Snaggle\Client\Header\Header;
7
use \Snaggle\Client\Signatures\HmacSha1;
8
use \Snaggle\Client\Signatures\SignatureInterface;
9
use \Snaggle\Client\Credentials\AccessCredentials;
10
use \Snaggle\Client\Credentials\ConsumerCredentials;
11
use \Wheedle\Exceptions\UnauthorizedRequestException;
12
use \Wheedle\Exceptions\MissingResourceException;
13
use \Wheedle\Exceptions\RateLimitExceededException;
14
use \RuntimeException;
15
16
/**
17
 * A Twitter client that extends Guzzle or encapsulates the OAuth madness
18
 *
19
 * @author Matt Frost
20
 * @license http://opensource.org/licenses/MIT MIT
21
 * @package Wheedle
22
 */
23
class TwitterClient
24
{
25
    /**
26
     * HTTP Client capable of making HTTP Requests
27
     *
28
     * @var \GuzzleHttp\Client $client
29
     */
30
    private $client;
31
32
    /**
33
     * Header object that is used to generate the OAuth 1.0 header
34
      *
35
     * @var \Snaggle\Client\Header\Header $header
36
     */
37
    private $header;
38
39
    /**
40
     * A signature type used to generate the OAuth 1.0 signature
41
     *
42
     * @var \Snaggle\Client\Signatures\SignatureInterface $signature
43
     */
44
    private $signature;
45
46
    /**
47
     * A Snaggle\AccessCredentials instance with the appropriate key/secret
48
     *
49
     * @var \Snaggle\Client\Credentials\AccessCredentials
50
     */
51
    private $accessCredentials;
52
53
    /**
54
     * A Snaggle\ConsumerCredentials instance with the appropriate key/secret
55
     *
56
     * @var \Snaggle\Client\Credentials\ConsumerCredentials
57
     */
58
    private $consumerCredentials;
59
60
    /**
61
     * String representing the location of the resource
62
     *
63
     * @var string $resourceUrl
64
     */
65
    private $resourceUrl;
66
67
    /**
68
     * String representing the HTTP method with which to use the request
69
     *
70
     * @var string $httpMethod
71
     */
72
    private $httpMethod;
73
74
    /**
75
     * A timestamp for the request
76
     *
77
     * @var int $timestamp
78
     */
79
    private $timestamp = 0;
80
81
    /**
82
     * A nonce for the request
83
     *
84
     * @var string $nonce
85
     */
86
    private $nonce = null;
87
88
    /**
89
     * Verifier that is part of the temporary token exchange
90
     *
91
     * @var string $verifier
92
     */
93
    private $verifier = null;
94
95
    /**
96
     * Post requests require any form fields to be included for the signature, you can set them here
97
     *
98
     * @var Array $postFields
99
     */
100
    private $postFields = [];
101
102
    /**
103
     * Base Twitter API Endpoint
104
     *
105
     * @var const string $baseEndpoint
106
     */
107
    const TWITTER_BASE_ENDPOINT = 'https://api.twitter.com/1.1/';
108
109
    /**
110
     * @param AccessCredentials $accessCredentials
111
     * @param ConsumerCredentials $consumerCredentials
112
     */
113
    public function __construct(AccessCredentials $accessCredentials, ConsumerCredentials $consumerCredentials)
114
    {
115
        $this->accessCredentials = $accessCredentials;
116
        $this->consumerCredentials = $consumerCredentials;
117
        $this->client = new Client();
118
    }
119
120
    /**
121
     * Method set an instance of Guzzle HTTP client
122
     *
123
     * @param Client $client
124
     */
125
    public function setClient(Client $client)
126
    {
127
        $this->client = $client;
128
    }
129
130
    /**
131
     * Accessor method to retrieve a set header or create a new instance of header
132
     *
133
     * @return Header
134
     */
135
    public function getHeader()
136
    {
137
        if (!$this->header instanceof Header) {
138
            $this->header = new Header;
139
        }
140
        return $this->header;
141
    }
142
143
    /**
144
     * Access method to set an instance of header
145
     *
146
     * @param Header $header
147
     */
148
    public function setHeader(Header $header)
149
    {
150
        $this->header = $header;
151
    }
152
153
    /**
154
     * Accessor method to retrieve a set Signature or create a new instance
155
     *
156
     */
157
    public function getSignature()
158
    {
159
        if (!$this->signature instanceof HmacSha1) {
160
            $this->signature = new HmacSha1($this->consumerCredentials, $this->accessCredentials);
161
        }
162
        return $this->signature;
163
    }
164
165
    /**
166
     * Accessor method for setting a preconfigured signature which will set the other
167
     * properties from the data contained in the signature
168
     *
169
     * @param HmacSha1 $signature
170
     */
171
    public function setSignature(HmacSha1 $signature)
172
    {
173
        $this->signature = $signature;
174
        $this->resourceUrl = $signature->getResourceURL();
175
        $this->httpMethod = $signature->getHttpMethod();
176
        $this->nonce = $signature->getNonce();
177
        $this->timestamp = $signature->getTimestamp();
178
        $this->verifier = $signature->getVerifier();
179
        $this->postFields = $signature->getPostFields();
180
    }
181
182
    /**
183
     * Method to set the resource url
184
     *
185
     * @param string $url
186
     */
187
    public function setResourceUrl($url)
188
    {
189
        $this->resourceUrl = $url;
190
    }
191
192
    /**
193
     * Method to set the Http Method
194
     *
195
     * @param string $httpMethod
196
     */
197
    public function setHttpMethod($httpMethod)
198
    {
199
        $this->httpMethod = strtoupper($httpMethod);
200
    }
201
202
    /**
203
     * Method to set a timestamp
204
     *
205
     * @param int $timestamp
206
     */
207
    public function setTimestamp($timestamp)
208
    {
209
        $this->timestamp = $timestamp;
210
    }
211
212
    /**
213
     * Method to set a nonce
214
     *
215
     * @param string $nonce
216
     */
217
    public function setNonce($nonce)
218
    {
219
        $this->nonce = $nonce;
220
    }
221
222
    /**
223
     * Method to set the verifier for token requests
224
     *
225
     * @param string $verifier
226
     */
227
    public function setVerifier($verifier)
228
    {
229
        $this->verifier = $verifier;
230
    }
231
232
    /**
233
     * Method for setting the post fields
234
     *
235
     * @param Array $postFields
236
     */
237
    public function setPostFields(Array $postFields)
238
    {
239
        array_walk($postFields, function ($value, $key) use (&$postFields) {
240
            $postFields[$key] = rawurlencode($value);
241
        });
242
        $this->postFields = $postFields;
243
    }
244
245
    /**
246
     * Method to build the Authorization Header
247
     *
248
     * @return string
249
     */
250
    public function getAuthorizationHeader()
251
    {
252
        $header = $this->getHeader();
253
        $signature = $this->prepareSignature();
254
        $header->setSignature($signature);
255
        return $header->createAuthorizationHeader();
256
    }
257
258
    /**
259
     * Prepare the signature for use in the Authorization header
260
     *
261
     * @return Signature
262
     */
263
    private function prepareSignature()
264
    {
265
        $signature = $this->getSignature();
266
        $signature->setResourceURL($this->resourceUrl);
267
        $signature->setHttpMethod($this->httpMethod);
268
        $signature->setPostFields($this->postFields);
269
270
        if ($this->timestamp !== 0) {
271
            $signature->setTimestamp($this->timestamp);
272
        }
273
274
        if ($this->nonce !== null) {
275
            $signature->setNonce($this->nonce);
276
        }
277
278
        if ($this->verifier !== null) {
279
            $signature->setVerifier($this->verifier);
280
        }
281
282
        return $signature;
283
    }
284
285
    /**
286
     * Method to execute a GET request
287
     *
288
     * @param string $endpoint - endpoint to hit
289
     * @param Array $options parameters for the query string
290
     * @return string response from the Twitter endpoint
291
     * @throws UnauthorizedRequestException
292
     * @throws RateLimitExceededException
293
     * @throws RuntimeException
294
     */
295
    public function makeGetRequest($endpoint, $options)
296
    {
297
        $queryString = (empty($options)) ? '' : '?';
298
        $queryString .= http_build_query($options);
299
        $endpoint = self::TWITTER_BASE_ENDPOINT . $endpoint . $queryString;
300
        $this->setHttpMethod('GET');
301
        $this->setResourceUrl($endpoint);
302
        try {
303
            $response = $this->client->get($endpoint, [
304
                'headers' => [
305
                    'Authorization' => $this->getAuthorizationHeader()
306
                ]
307
            ]);
308
            return $response->getBody();
309
        } catch (\GuzzleHttp\Exception\ClientException $e) {
310
            // protected method - used to throw exception based on status code
311
            $exception = $this->handleException($e);
312
            throw $exception;
313
        }
314
    }
315
316
    /**
317
     * Method to execute a POST request
318
     *
319
     * @param string $endpoint - end point to hit
320
     * @param Array $options - parameters/post body
321
     * @return string response from Twitter Endpoint
322
     * @throws UnauthorizedRequestException
323
     * @throws RateLimitExceededException
324
     * @throws RuntimeException
325
     */
326
    public function makePostRequest($endpoint, $options)
327
    {
328
        $this->setHttpMethod('POST');
329
        $this->setResourceUrl(self::TWITTER_BASE_ENDPOINT . $endpoint);
330
        $this->setPostFields($this->preparePostOptions($options));
331
        try {
332
            $response = $this->client->post($endpoint, [
333
                'headers' => [
334
                    'Authorization' => $this->getAuthorizationHeader()
335
                ],
336
                'body' => $options
337
            ]);
338
            return $response->getBody();
339
        } catch (\GuzzleHttp\Exception\ClientException $e) {
340
            // protected method - used to throw exception based on status code
341
            $exception = $this->handleException($e);
342
            throw $exception;
343
        }
344
    }
345
346
    /**
347
     * Method to handle the selection of the correct exception to throw
348
     *
349
     * @param \GuzzleHttp\Exception\ClientException $e - Guzzle Client Exception
350
     * @return mixed - Exception to throw
351
     */
352
    protected function handleException(ClientException $e)
353
    {
354
        switch ($e->getCode()) {
355
            case 401:
356
                return new UnauthorizedRequestException($e->getMessage());
357
                break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
358
            case 404:
359
                return new MissingResourceException($e->getMessage());
360
                break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
361
            case 429:
362
                return new RateLimitExceededException($e->getMessage());
363
                break;
0 ignored issues
show
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
364
            default:
365
                return new RuntimeException($e->getMessage());
366
        }
367
    }
368
369
    /**
370
     * Method to prepare parameters for the base string by rawurlencoding them
371
     *
372
     * @param Array $options parameters or post body
373
     * @return Array array of options rawurlencoded
374
     */
375
    protected function preparePostOptions(Array $options)
376
    {
377
        array_walk($options, function ($value, $key) use (&$options) {
378
            $options[$key] = rawurlencode($value);
379
        });
380
        return $options;
381
    }
382
383
    /**
384
     * Wrapper method for makeGetRequest
385
     *
386
     * @param string $endpoint end point to hit
387
     * @param Array $options parameters
388
     * @return string response from Twitter Endpoint
389
     */
390
    public function get($endpoint, $options = [])
391
    {
392
        return $this->makeGetRequest($endpoint, $options);
393
    }
394
395
    /**
396
     * Wrapper method for makePostRequest
397
     *
398
     * @param string $endpoint endpoint to hit
399
     * @param Array $options parameters/post body
400
     * @return string response from endpoint
401
     */
402
    public function post($endpoint, $options = [])
403
    {
404
        return $this->makePostRequest($endpoint, $options);
405
    }
406
}
407