Completed
Push — master ( 28c804...53b125 )
by Ehsan
02:55
created

OAuth::getAccessToken()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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