WebhookNotification   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 74
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 14
dl 0
loc 74
rs 10
c 1
b 0
f 1
wmc 8

6 Methods

Rating   Name   Duplication   Size   Complexity  
A hasValidSignature() 0 12 1
A getWebhookId() 0 4 2
A __construct() 0 5 1
A getNotifications() 0 6 2
A getData() 0 3 1
A sendData() 0 3 1
1
<?php
2
3
namespace Omnipay\GoCardless\Message;
4
5
use Omnipay\Common\Http\ClientInterface;
6
use Omnipay\Common\Message\AbstractRequest;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Omnipay\GoCardless\Message\AbstractRequest. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use Symfony\Component\HttpFoundation\Request as HttpRequest;
8
9
/**
10
 * @todo do we want to implement ResponseInterface so we have a getMessage() in case of error?
11
 */
12
class WebhookNotification extends AbstractRequest
13
{
14
    /**
15
     * @var mixed The data contained in the request.
16
     */
17
    protected $data;
18
19
    /**
20
     * @inheritDoc
21
     */
22
    public function __construct(ClientInterface $httpClient, HttpRequest $httpRequest)
23
    {
24
        parent::__construct($httpClient, $httpRequest);
25
        // fetch POST stream directly
26
        $this->data = json_decode($httpRequest->getContent(), true);
27
    }
28
29
    /**
30
     * @return null|mixed
31
     */
32
    public function getData()
33
    {
34
        return $this->data;
35
    }
36
    
37
38
    /**
39
     * @return array
40
     */
41
    public function getNotifications()
42
    {
43
        if (isset($this->data['events'])) {
44
            return $this->data['events'];
45
        }
46
        return [];
47
    }
48
49
    /**
50
     * @return null|string
51
     */
52
    public function getWebhookId()
53
    {
54
        if (isset($this->data['meta']['webhook_id'])) {
55
            return $this->data['meta']['webhook_id'];
56
        }
57
    }
58
59
    /**
60
     * Given a secret, is the signature on this webhook valid?
61
     *
62
     * Note: request bodies are minified JSON, so strip superfluous whitespace when testing, including trailing newlines
63
     *
64
     * @return bool  Application should return '498 Token Invalid' if false
65
     */
66
    public function hasValidSignature($secret)
67
    {
68
        $supplied = $this->httpRequest->headers->get('Webhook-Signature');
69
70
        // DEBUG: strip whitespace from body (minify JSON), including trailing newlines
71
        // $rawBody = $this->httpRequest->getContent();
72
        // $minified = json_encode(json_decode($rawBody));
73
        // echo "\nSTART\n{$rawBody}\nSTOP\n";
74
        // echo "\nSTART\n{$minified}\nSTOP\n";
75
76
        $calculated = hash_hmac('sha256', $this->httpRequest->getContent(), $secret);
77
        return $supplied === $calculated;
78
    }
79
80
    /**
81
     * Implemented as part of {@see AbstractRequest}} for legacy support
82
     */
83
    public function sendData($data)
84
    {
85
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Omnipay\GoCardless\Message\WebhookNotification which is incompatible with the return type mandated by Omnipay\Common\Message\R...stInterface::sendData() of Omnipay\Common\Message\ResponseInterface.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
86
    }
87
}
88