Issues (9)

src/OAuth2/Provider/GitHub.php (1 issue)

1
<?php
2
/**
3
 * SocialConnect project
4
 * @author: Patsura Dmitry https://github.com/ovr <[email protected]>
5
 */
6
declare(strict_types=1);
7
8
namespace SocialConnect\OAuth2\Provider;
9
10
use SocialConnect\Common\ArrayHydrator;
11
use SocialConnect\OAuth2\AccessToken;
12
use SocialConnect\Provider\AccessTokenInterface;
13
use SocialConnect\Provider\Exception\InvalidAccessToken;
14
use SocialConnect\Provider\Exception\InvalidResponse;
15
use SocialConnect\Common\Entity\User;
16
17
class GitHub extends \SocialConnect\OAuth2\AbstractProvider
18
{
19
    const NAME = 'github';
20
21
    /**
22
     * @var array
23
     */
24
    protected $options = [
25
        /**
26
         * GitHub store only unverified and public email inside User
27
         * It's not possible to fetch user with email in GraphQL (new api)
28
         * For now, there is only one way, additional request for it by user/email API entrypoint
29
         *
30
         * It's disabled by default in SocialConnect 1.x, but you can enable it from configuration :)
31
         */
32
        'fetch_emails' => false
33
    ];
34
35 4
    public function getBaseUri()
36
    {
37 4
        return 'https://api.github.com/';
38
    }
39
40 2
    public function getAuthorizeUri()
41
    {
42 2
        return 'https://github.com/login/oauth/authorize';
43
    }
44
45 2
    public function getRequestTokenUri()
46
    {
47 2
        return 'https://github.com/login/oauth/access_token';
48
    }
49
50 3
    public function getName()
51
    {
52 3
        return self::NAME;
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58 4
    public function parseToken(string $body)
59
    {
60 4
        if (empty($body)) {
61 1
            throw new InvalidAccessToken('Provider response with empty body');
62
        }
63
64 3
        parse_str($body, $token);
65
66 3
        if (!isset($token['access_token'])) {
67 2
            throw new InvalidAccessToken('Provider API returned an unexpected response');
68
        }
69
70 1
        return new AccessToken($token);
71
    }
72
73
    /**
74
     * {@inheritDoc}
75
     */
76 3
    public function prepareRequest(string $method, string $uri, array &$headers, array &$query, ?AccessTokenInterface $accessToken = null): void
77
    {
78 3
        if ($accessToken) {
79 3
            $headers['Authorization'] = "bearer {$accessToken->getToken()}";
80
        }
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86 3
    public function getIdentity(AccessTokenInterface $accessToken)
87
    {
88 3
        $response = $this->request('GET', 'user', [], $accessToken);
89
90 1
        $hydrator = new ArrayHydrator([
91
            'id' => 'id',
92
            'login' => 'username',
93
            'email' => 'email',
94
            'avatar_url' => 'pictureURL',
95
            'name' => 'fullname'
96
        ]);
97
98
        /** @var User $user */
99 1
        $user = $hydrator->hydrate(new User(), $response);
100
101 1
        if ($this->getBoolOption('fetch_emails', false)) {
102
            $primaryEmail = $this->getPrimaryEmail($accessToken);
103
            if ($primaryEmail) {
104
                $user->email = $primaryEmail['email'];
105
                $user->emailVerified = $primaryEmail['verified'];
106
            }
107
        }
108
109 1
        return $user;
110
    }
111
112
    /**
113
     * @param AccessTokenInterface $accessToken
114
     * @return array|null
115
     * @throws InvalidResponse
116
     * @throws \Psr\Http\Client\ClientExceptionInterface
117
     */
118
    protected function getPrimaryEmail(AccessTokenInterface $accessToken)
119
    {
120
        $emails = $this->getEmails($accessToken);
121
        if ($emails) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $emails of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
122
            foreach ($emails as $email) {
123
                if ($email['primary']) {
124
                    return $email;
125
                }
126
            }
127
        }
128
129
        return null;
130
    }
131
132
    /**
133
     * @param AccessTokenInterface $accessToken
134
     * @return array
135
     * @throws InvalidResponse
136
     * @throws \Psr\Http\Client\ClientExceptionInterface
137
     */
138
    protected function getEmails(AccessTokenInterface $accessToken)
139
    {
140
        return $this->request('GET', 'user/emails', [], $accessToken);
141
    }
142
}
143