GithubOAuth   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 2
dl 0
loc 117
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A start() 0 19 3
A isStateValid() 0 14 3
A getAccessTokenFromCode() 0 32 4
1
<?php
2
3
namespace BWC\Share\Github;
4
5
use BWC\Share\Net\HttpClient\HttpClientInterface;
6
use BWC\Share\Net\HttpStatusCode;
7
use Symfony\Component\HttpFoundation\RedirectResponse;
8
use Symfony\Component\HttpFoundation\Session\SessionInterface;
9
use Symfony\Component\HttpKernel\Exception\HttpException;
10
11
class GithubOAuth
12
{
13
    const STATE_SESSION_KEY = 'github_state';
14
15
16
    /** @var  string */
17
    protected $clientId;
18
19
    /** @var string  */
20
    protected $secret;
21
22
    /** @var \Symfony\Component\HttpFoundation\Session\SessionInterface */
23
    protected $session;
24
25
    /** @var \BWC\Share\Net\HttpClient\HttpClientInterface  */
26
    protected $httpClient;
27
28
29
30
    /**
31
     * @param string $clientId
32
     * @param string $secret
33
     * @param SessionInterface $session
34
     * @param \BWC\Share\Net\HttpClient\HttpClientInterface $httpClient
35
     */
36
    public function __construct($clientId, $secret, SessionInterface $session, HttpClientInterface $httpClient)
37
    {
38
        $this->clientId = $clientId;
39
        $this->secret = $secret;
40
        $this->session = $session;
41
        $this->httpClient = $httpClient;
42
    }
43
44
45
    /**
46
     * @param array $scopes
47
     * @param null|string $redirectUri
48
     * @return RedirectResponse
49
     */
50
    public function start(array $scopes = null, $redirectUri = null)
51
    {
52
        $state = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
53
        $this->session->set(self::STATE_SESSION_KEY, $state);
54
55
        $params = array(
56
            'client_id' => $this->clientId,
57
            'state' => $state
58
        );
59
60
        if ($redirectUri) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $redirectUri of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
61
            $params['redirect_uri'] = $redirectUri;
62
        }
63
        if ($scopes) {
64
            $params['scope'] = implode(',', $scopes);
65
        }
66
67
        return new RedirectResponse('https://github.com/login/oauth/authorize?'.http_build_query($params));
68
    }
69
70
    /**
71
     * @param string $state
72
     * @return bool
73
     */
74
    public function isStateValid($state)
75
    {
76
        if (!$state) {
77
            return false;
78
        }
79
80
        $sessionState = $this->session->get(self::STATE_SESSION_KEY);
81
        $this->session->remove(self::STATE_SESSION_KEY);
82
        if ($state != $sessionState) {
83
            return false;
84
        }
85
86
        return true;
87
    }
88
89
    /**
90
     * @param string $code
91
     * @throws \Symfony\Component\HttpKernel\Exception\HttpException
92
     * @return GithubAccessResponse
93
     */
94
    public function getAccessTokenFromCode($code)
95
    {
96
        $json = $this->httpClient->post(
97
            'https://github.com/login/oauth/access_token',
98
            array(),
99
            array(
100
                'client_id' => $this->clientId,
101
                'client_secret' => $this->secret,
102
                'code' => $code
103
            ),
104
            null,
105
            array(
106
                'Accept: application/json'
107
            )
108
        );
109
110
        if ($this->httpClient->getStatusCode() != HttpStatusCode::OK) {
111
            throw new HttpException($this->httpClient->getStatusCode(), $this->httpClient->getErrorText() . ' : '. $json);
112
        }
113
114
        /** @var GithubAccessResponse $result */
115
        $result = GithubAccessResponse::deserialize($json);
116
117
        if (!$result) {
118
            new \LogicException('Unable to parse github response: '.$json);
119
        }
120
        if ($result->error) {
121
            throw new HttpException(HttpStatusCode::INTERNAL_SERVER_ERROR, $result->error.': '.$result->error_description);
122
        }
123
124
        return $result;
125
    }
126
127
}