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.

WebhookRequestHandler   A
last analyzed

Complexity

Total Complexity 35

Size/Duplication

Total Lines 248
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 89.61%

Importance

Changes 0
Metric Value
wmc 35
lcom 1
cbo 10
dl 0
loc 248
ccs 69
cts 77
cp 0.8961
rs 9
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A handleRequest() 0 4 1
B isValidCallbackRequest() 0 13 5
A getAllCallbackEvents() 0 10 2
A getEntries() 0 4 1
A getHydratedEntries() 0 17 3
A __construct() 0 6 2
A isValidVerifyTokenRequest() 0 14 3
A getChallenge() 0 6 2
A isValid() 0 4 1
A getRequest() 0 8 2
A getDecodedBody() 0 10 3
B dispatchCallbackEvents() 0 16 5
A addEventSubscriber() 0 4 1
A getBody() 0 10 2
A isValidHubSignature() 0 12 2
1
<?php
2
3
namespace Tgallice\FBMessenger;
4
5
use GuzzleHttp\Psr7\ServerRequest;
6
use Psr\Http\Message\ServerRequestInterface;
7
use Symfony\Component\EventDispatcher\EventDispatcher;
8
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
9
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
10
use Tgallice\FBMessenger\Callback\CallbackEvent;
11
use Tgallice\FBMessenger\Callback\MessageEvent;
12
use Tgallice\FBMessenger\Callback\PostbackEvent;
13
use Tgallice\FBMessenger\Model\Callback\Entry;
14
15
class WebhookRequestHandler
16
{
17
    /**
18
     * @var ServerRequestInterface
19
     */
20
    private $request;
21
22
    /**
23
     * App secret used to verify the request sha1
24
     *
25
     * @var string
26
     */
27
    private $secret;
28
29
    /**
30
     * @var array
31
     */
32
    private $decodedBody;
33
34
    /**
35
     * @var Entry[]
36
     */
37
    private $hydratedEntries;
38
39
    /**
40
     * @var string
41
     */
42
    private $body;
43
44
    /**
45
     * @var string
46
     */
47
    private $verifyToken;
48
49
    /**
50
     * @var EventDispatcherInterface
51
     */
52
    private $dispatcher;
53
54
    /**
55
     * @param $secret
56
     * @param $verifyToken
57
     * @param EventDispatcherInterface|null $dispatcher
58
     */
59 12
    public function __construct($secret, $verifyToken, EventDispatcherInterface $dispatcher = null)
60
    {
61 12
        $this->secret = $secret;
62 12
        $this->verifyToken = $verifyToken;
63 12
        $this->dispatcher = $dispatcher ?: new EventDispatcher();
64 12
    }
65
66
    /**
67
     * @param ServerRequestInterface $request
68
     */
69 12
    public function handleRequest(ServerRequestInterface $request)
70
    {
71 12
        $this->request = $request;
72 12
    }
73
74
    /**
75
     * Check if the token match with the given verify token.
76
     * This is useful in the webhook setup process.
77
     *
78
     * @return bool
79
     */
80 1
    public function isValidVerifyTokenRequest()
81
    {
82 1
        if ($this->getRequest()->getMethod() !== 'GET') {
83
            return false;
84
        }
85
86 1
        $params = $this->getRequest()->getQueryParams();
87
88 1
        if (!isset($params['hub_verify_token'])) {
89
            return false;
90
        }
91
92 1
        return  $params['hub_verify_token'] === $this->verifyToken;
93
    }
94
95
    /**
96
     * @return null|string
97
     */
98 1
    public function getChallenge()
99
    {
100 1
        $params = $this->getRequest()->getQueryParams();
101
102 1
        return isset($params['hub_challenge']) ? $params['hub_challenge'] : null;
103
    }
104
105
    /**
106
     * Check if the request is a valid webhook request
107
     *
108
     * @return bool
109
     */
110 3
    public function isValidCallbackRequest()
111
    {
112 3
        if (!$this->isValidHubSignature()) {
113 2
            return false;
114
        }
115
116 1
        $decoded = $this->getDecodedBody();
117
118 1
        $object = isset($decoded['object']) ? $decoded['object'] : null;
119 1
        $entry = isset($decoded['entry']) ? $decoded['entry'] : null;
120
121 1
        return $object === 'page' && null !== $entry;
122
    }
123
124
    /**
125
     * Check if the request is a valid webhook request
126
     *
127
     * @deprecated use WebhookRequestHandler::isValidCallbackRequest() instead
128
     *
129
     * @return bool
130
     */
131
    public function isValid()
132
    {
133
        return $this->isValidCallbackRequest();
134
    }
135
136
    /**
137
     * @return CallbackEvent[]
138
     */
139 2
    public function getAllCallbackEvents()
140
    {
141 2
        $events = [];
142
143 2
        foreach ($this->getHydratedEntries() as $hydratedEntry) {
144 2
            $events = array_merge($events, $hydratedEntry->getCallbackEvents());
145 2
        }
146
147 2
        return $events;
148
    }
149
150
    /**
151
     * @return Entry[]
152
     */
153 1
    public function getEntries()
154
    {
155 1
        return $this->getHydratedEntries();
156
    }
157
158
    /**
159
     * @return ServerRequestInterface
160
     */
161 10
    public function getRequest()
162
    {
163 10
        if ($this->request) {
164 10
            return $this->request;
165
        }
166
167
        return $this->request = ServerRequest::fromGlobals();
168
    }
169
170
    /**
171
     * @return array
172
     */
173 5
    public function getDecodedBody()
174
    {
175 5
        if (isset($this->decodedBody)) {
176
            return $this->decodedBody;
177
        }
178
179 5
        $decoded = @json_decode($this->getBody(), true);
180
181 5
        return $this->decodedBody = null === $decoded ? [] : $decoded;
182
    }
183
184
    /**
185
     * Dispatch events to listeners
186
     */
187 1
    public function dispatchCallbackEvents()
188
    {
189 1
        foreach ($this->getAllCallbackEvents() as $event) {
190 1
            $this->dispatcher->dispatch($event->getName(), $event);
191
192 1
            if ($event instanceof PostbackEvent) {
193
                // Dispatch postback payload
194
                $this->dispatcher->dispatch($event->getPostback()->getPayload(), $event);
195
            }
196
197 1
            if ($event instanceof MessageEvent && $event->isQuickReply()) {
198
                // Dispatch quick reply payload
199 1
                $this->dispatcher->dispatch($event->getQuickReplyPayload(), $event);
200 1
            }
201 1
        }
202 1
    }
203
204
    /**
205
     * @param EventSubscriberInterface $subscriber
206
     */
207 1
    public function addEventSubscriber(EventSubscriberInterface $subscriber)
208
    {
209 1
        $this->dispatcher->addSubscriber($subscriber);
210 1
    }
211
212
    /**
213
     * @return Entry[]
214
     */
215 3
    private function getHydratedEntries()
216
    {
217 3
        if (isset($this->hydratedEntries)) {
218
            return $this->hydratedEntries;
219
        }
220
221 3
        $decodedBody = $this->getDecodedBody();
222 3
        $entries = $decodedBody['entry'];
223
224 3
        $hydrated = [];
225
226 3
        foreach ($entries as $entry) {
227 3
            $hydrated[] = Entry::create($entry);
228 3
        }
229
230 3
        return $this->hydratedEntries = $hydrated;
231
    }
232
233
    /**
234
     * @return string
235
     */
236 7
    private function getBody()
237
    {
238 7
        if (isset($this->body)) {
239 1
            return $this->body;
240
        }
241
242 7
        $this->body = (string) $this->getRequest()->getBody();
243
244 7
        return $this->body;
245
    }
246
247
    /**
248
     * @return bool
249
     */
250 3
    private function isValidHubSignature()
251
    {
252 3
        $headers = $this->getRequest()->getHeader('X-Hub-Signature');
253
254 3
        if (empty($headers)) {
255
            return false;
256
        }
257
258 3
        $signature = XHubSignature::parseHeader($headers[0]);
259
260 3
        return XHubSignature::validate($this->getBody(), $this->secret, $signature);
261
    }
262
}
263