OAuth::getBotAccessToken()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Botonomous;
4
5
use Botonomous\client\ApiClient;
6
use Botonomous\utility\RequestUtility;
7
use Botonomous\utility\SecurityUtility;
8
use Botonomous\utility\SessionUtility;
9
10
/**
11
 * Class OAuth.
12
 */
13
class OAuth
14
{
15
    const AUTHORIZATION_URL = 'https://slack.com/oauth/authorize';
16
    const SESSION_STATE_KEY = 'state';
17
18
    private $clientId;
19
    private $clientSecret;
20
    private $scopes;
21
    private $redirectUri;
22
    private $state;
23
    private $teamId;
24
    private $apiClient;
25
    private $sessionUtility;
26
    private $requestUtility;
27
28
    /**
29
     * @var string configuration_url will be the URL that you can point your user to if they'd like to edit
30
     *             or remove this integration in Slack
31
     */
32
    private $configurationUrl;
33
34
    /**
35
     * @var string The team_name field will be the name of the team that installed your app
36
     */
37
    private $teamName;
38
    private $accessToken;
39
40
    /**
41
     * @var string the channel will be the channel name that they have chosen to post to
42
     */
43
    private $channel;
44
45
    /**
46
     * @var string you will need to use bot_user_id and bot_access_token whenever you are acting on behalf of
47
     *             that bot user for that team context.
48
     *             Use the top-level access_token value for other integration points.
49
     */
50
    private $botUserId;
51
    private $botAccessToken;
52
53
    private $config;
54
55
    /**
56
     * OAuth constructor.
57
     *
58
     * @param       $clientId
59
     * @param       $clientSecret
60
     * @param array $scopes
61
     */
62 25
    public function __construct($clientId = '', $clientSecret = '', array $scopes = [])
63
    {
64 25
        $this->setClientId($clientId);
65 25
        $this->setClientSecret($clientSecret);
66 25
        $this->setScopes($scopes);
67 25
    }
68
69
    /**
70
     * @throws \Exception
71
     *
72
     * @return string
73
     */
74 6
    public function getClientId(): string
75
    {
76 6
        if (empty($this->clientId)) {
77 3
            $this->setClientId($this->getConfig()->get('clientId'));
78
        }
79
80 6
        return $this->clientId;
81
    }
82
83
    /**
84
     * @param string $clientId
85
     */
86 25
    public function setClientId(string $clientId)
87
    {
88 25
        $this->clientId = $clientId;
89 25
    }
90
91
    /**
92
     * @throws \Exception
93
     *
94
     * @return array
95
     */
96 2
    public function getScopes(): array
97
    {
98 2
        if (empty($this->scopes)) {
99 1
            $this->setScopes($this->getConfig()->get('scopes'));
100
        }
101
102 2
        return $this->scopes;
103
    }
104
105
    /**
106
     * @param array $scopes
107
     */
108 25
    public function setScopes(array $scopes)
109
    {
110 25
        $this->scopes = $scopes;
111 25
    }
112
113
    /**
114
     * @return string
115
     */
116 1
    public function getRedirectUri(): string
117
    {
118 1
        return $this->redirectUri;
119
    }
120
121
    /**
122
     * @param string $redirectUri
123
     */
124 1
    public function setRedirectUri(string $redirectUri)
125
    {
126 1
        $this->redirectUri = $redirectUri;
127 1
    }
128
129
    /**
130
     * @throws \Exception
131
     *
132
     * @return string
133
     */
134 2
    public function getState(): string
135
    {
136 2
        if (!isset($this->state)) {
137 2
            $this->setState((new SecurityUtility())->generateToken());
138
        }
139
140 2
        return $this->state;
141
    }
142
143
    /**
144
     * @param string $state
145
     */
146 2
    public function setState(string $state)
147
    {
148 2
        $this->getSessionUtility()->set(self::SESSION_STATE_KEY, $state);
149 2
        $this->state = $state;
150 2
    }
151
152
    /**
153
     * @param $state
154
     *
155
     * @return bool
156
     */
157 5
    public function verifyState($state): bool
158
    {
159 5
        if (empty($state)) {
160 2
            return false;
161
        }
162
163 3
        return $state === $this->getSessionUtility()->get(self::SESSION_STATE_KEY) ? true : false;
164
    }
165
166
    /**
167
     * @return string
168
     */
169 1
    public function getTeamId(): string
170
    {
171 1
        return $this->teamId;
172
    }
173
174
    /**
175
     * @param string $teamId
176
     */
177 2
    public function setTeamId(string $teamId)
178
    {
179 2
        $this->teamId = $teamId;
180 2
    }
181
182
    /**
183
     * @param string $height
184
     * @param string $weight
185
     * @param string $cssClass
186
     *
187
     * @throws \Exception
188
     *
189
     * @return string
190
     */
191 1
    public function generateAddButton($height = '40', $weight = '139', $cssClass = ''): string
192
    {
193 1
        $authorizationUrl = self::AUTHORIZATION_URL;
194 1
        $scope = implode(',', $this->getScopes());
195 1
        $clientId = $this->getClientId();
196
197 1
        $stateQueryString = '';
198 1
        if (!empty($this->getState())) {
199 1
            $state = $this->getState();
200 1
            $stateQueryString = "&state={$state}";
201
        }
202
203 1
        $href = "{$authorizationUrl}?scope={$scope}&client_id={$clientId}{$stateQueryString}";
204
205 1
        $html = "<a href='{$href}'>
206 1
<img alt='Add to Slack' class='{$cssClass}' height='{$height}' width='{$weight}'
207
src='https://platform.slack-edge.com/img/add_to_slack.png'
208
srcset='https://platform.slack-edge.com/img/add_to_slack.png 1x,
209
https://platform.slack-edge.com/img/[email protected] 2x' /></a>";
210
211 1
        return $html;
212
    }
213
214
    /**
215
     * @param      $code
216
     * @param bool $verifyState State is checked against the value in the session
217
     * @param null $state
218
     *
219
     * @throws \Exception
220
     *
221
     * @return mixed
222
     */
223 10
    public function getAccessToken($code, $verifyState = true, $state = null)
224
    {
225 10
        if (!isset($this->accessToken)) {
226 7
            if ($verifyState === true && $this->verifyState($state) !== true) {
227 3
                throw new BotonomousException("State: '{$state}' is not valid");
228
            }
229
230
            try {
231 4
                $this->handleRequestAccessTokenResponse($this->requestAccessToken($code));
232 3
            } catch (\Exception $e) {
233 3
                throw $e;
234
            }
235
        }
236
237 4
        return $this->accessToken;
238
    }
239
240
    /**
241
     * @param $response
242
     *
243
     * @throws \Exception
244
     */
245 2
    private function handleRequestAccessTokenResponse($response)
246
    {
247 2
        if ($response['ok'] !== true) {
248 1
            throw new BotonomousException($response['error']);
249
        }
250
251 1
        $this->setAccessToken($response['access_token']);
252 1
        $this->setTeamId($response['team_id']);
253 1
        $this->setBotUserId($response['bot']['bot_user_id']);
254 1
        $this->setBotAccessToken($response['bot']['bot_access_token']);
255
256 1
        $channel = '';
257 1
        if (isset($response['incoming_webhook']['channel'])) {
258 1
            $channel = $response['incoming_webhook']['channel'];
259
        }
260
261 1
        $this->setChannel($channel);
262 1
    }
263
264
    /**
265
     * @param $code
266
     *
267
     * @throws \Exception
268
     *
269
     * @return mixed
270
     */
271 4
    private function requestAccessToken($code)
272
    {
273 4
        if (empty($code)) {
274 1
            throw new BotonomousException('Code must be provided to get the access token');
275
        }
276
277
        try {
278 3
            return $this->getApiClient()->oauthAccess([
279 3
                'client_id'     => $this->getClientId(),
280 3
                'client_secret' => $this->getClientSecret(),
281 3
                'code'          => $code,
282
            ]);
283 1
        } catch (\Exception $e) {
284 1
            throw $e;
285
        }
286
    }
287
288
    /**
289
     * @param $accessToken
290
     */
291 4
    public function setAccessToken(string $accessToken)
292
    {
293 4
        $this->accessToken = $accessToken;
294 4
    }
295
296
    /**
297
     * @throws \Exception
298
     *
299
     * @return string
300
     */
301 4
    public function getClientSecret(): string
302
    {
303 4
        if (empty($this->clientSecret)) {
304 3
            $this->setClientSecret($this->getConfig()->get('clientSecret'));
305
        }
306
307 4
        return $this->clientSecret;
308
    }
309
310
    /**
311
     * @param string $clientSecret
312
     */
313 25
    public function setClientSecret(string $clientSecret)
314
    {
315 25
        $this->clientSecret = $clientSecret;
316 25
    }
317
318
    /**
319
     * @return string
320
     */
321 1
    public function getBotUserId(): string
322
    {
323 1
        return $this->botUserId;
324
    }
325
326
    /**
327
     * @param string $botUserId
328
     */
329 2
    public function setBotUserId(string $botUserId)
330
    {
331 2
        $this->botUserId = $botUserId;
332 2
    }
333
334
    /**
335
     * @return string
336
     */
337 1
    public function getBotAccessToken(): string
338
    {
339 1
        return $this->botAccessToken;
340
    }
341
342
    /**
343
     * @param string $botAccessToken
344
     */
345 2
    public function setBotAccessToken(string $botAccessToken)
346
    {
347 2
        $this->botAccessToken = $botAccessToken;
348 2
    }
349
350
    /**
351
     * @return string
352
     */
353 1
    public function getChannel(): string
354
    {
355 1
        return $this->channel;
356
    }
357
358
    /**
359
     * @param string $channel
360
     */
361 2
    public function setChannel(string $channel)
362
    {
363 2
        $this->channel = $channel;
364 2
    }
365
366
    /**
367
     * @return string
368
     */
369 1
    public function getTeamName(): string
370
    {
371 1
        return $this->teamName;
372
    }
373
374
    /**
375
     * @param string $teamName
376
     */
377 1
    public function setTeamName(string $teamName)
378
    {
379 1
        $this->teamName = $teamName;
380 1
    }
381
382
    /**
383
     * @return string
384
     */
385 1
    public function getConfigurationUrl(): string
386
    {
387 1
        return $this->configurationUrl;
388
    }
389
390
    /**
391
     * @param string $configurationUrl
392
     */
393 1
    public function setConfigurationUrl(string $configurationUrl)
394
    {
395 1
        $this->configurationUrl = $configurationUrl;
396 1
    }
397
398
    /**
399
     * @return ApiClient
400
     */
401 4
    public function getApiClient(): ApiClient
402
    {
403 4
        if (!isset($this->apiClient)) {
404 2
            $this->setApiClient(new ApiClient());
405
        }
406
407 4
        return $this->apiClient;
408
    }
409
410
    /**
411
     * @param ApiClient $apiClient
412
     */
413 4
    public function setApiClient(ApiClient $apiClient)
414
    {
415 4
        $this->apiClient = $apiClient;
416 4
    }
417
418
    /**
419
     * @param SessionUtility $sessionUtility
420
     */
421 4
    public function setSessionUtility(SessionUtility $sessionUtility)
422
    {
423 4
        $this->sessionUtility = $sessionUtility;
424 4
    }
425
426
    /**
427
     * @return SessionUtility|null
428
     */
429 4
    public function getSessionUtility(): SessionUtility
430
    {
431 4
        if (!isset($this->sessionUtility)) {
432 2
            $this->setSessionUtility(new SessionUtility());
433
        }
434
435 4
        return $this->sessionUtility;
436
    }
437
438
    /**
439
     * @return Config
440
     */
441 5
    public function getConfig(): Config
442
    {
443 5
        if (!isset($this->config)) {
444 4
            $this->setConfig(new Config());
445
        }
446
447 5
        return $this->config;
448
    }
449
450
    /**
451
     * @param Config $config
452
     */
453 5
    public function setConfig(Config $config)
454
    {
455 5
        $this->config = $config;
456 5
    }
457
458
    /**
459
     * @param null $code
460
     * @param null $state
461
     *
462
     * @throws \Exception
463
     *
464
     * @return bool
465
     */
466 4
    public function doOauth($code = null, $state = null)
467
    {
468 4
        $getRequest = $this->getRequestUtility()->getGet();
469
470
        // get code from GET request if $code is null
471 4
        $code = $code === null && isset($getRequest['code']) ? $getRequest['code'] : $code;
472
473
        // get state from GET request if $state is null
474 4
        $stateKey = 'state';
475 4
        $state = $state === null && isset($getRequest[$stateKey]) ? $getRequest[$stateKey] : $state;
476
477
        try {
478 4
            $this->processAccessToken($this->getAccessToken($code, true, $state));
479 4
        } catch (\Exception $e) {
480 4
            throw $e;
481
        }
482
483
        return true;
484
    }
485
486
    /**
487
     * @param $accessToken
488
     *
489
     * @throws \Exception
490
     */
491 1
    private function processAccessToken($accessToken)
492
    {
493 1
        if (empty($accessToken)) {
494 1
            throw new BotonomousException('Access token is not provided');
495
        }
496
497
        // do whatever you want with the access token
498
    }
499
500
    /**
501
     * @return RequestUtility
502
     */
503 5
    public function getRequestUtility(): RequestUtility
504
    {
505 5
        if (!isset($this->requestUtility)) {
506 1
            $this->setRequestUtility((new RequestUtility()));
507
        }
508
509 5
        return $this->requestUtility;
510
    }
511
512
    /**
513
     * @param RequestUtility $requestUtility
514
     */
515 5
    public function setRequestUtility(RequestUtility $requestUtility)
516
    {
517 5
        $this->requestUtility = $requestUtility;
518 5
    }
519
}
520