Issues (10)

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 (!is_array($token) || !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 getIdentity(AccessTokenInterface $accessToken)
77
    {
78 3
        $response = $this->request('GET', 'user', [], $accessToken);
79
80 1
        $hydrator = new ArrayHydrator([
81 1
            'id' => 'id',
82
            'login' => 'username',
83
            'email' => 'email',
84
            'avatar_url' => 'pictureURL',
85
            'name' => 'fullname'
86
        ]);
87
88
        /** @var User $user */
89 1
        $user = $hydrator->hydrate(new User(), $response);
90
91 1
        if ($this->getBoolOption('fetch_emails', false)) {
92
            $primaryEmail = $this->getPrimaryEmail($accessToken);
93
            if ($primaryEmail) {
94
                $user->email = $primaryEmail['email'];
95
                $user->emailVerified = $primaryEmail['verified'];
96
            }
97
        }
98
99 1
        return $user;
100
    }
101
102
    /**
103
     * @param AccessTokenInterface $accessToken
104
     * @return array|null
105
     * @throws InvalidResponse
106
     * @throws \Psr\Http\Client\ClientExceptionInterface
107
     */
108
    protected function getPrimaryEmail(AccessTokenInterface $accessToken)
109
    {
110
        $emails = $this->getEmails($accessToken);
111
        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...
112
            foreach ($emails as $email) {
113
                if ($email['primary']) {
114
                    return $email;
115
                }
116
            }
117
        }
118
119
        return null;
120
    }
121
122
    /**
123
     * @param AccessTokenInterface $accessToken
124
     * @return array
125
     * @throws InvalidResponse
126
     * @throws \Psr\Http\Client\ClientExceptionInterface
127
     */
128
    protected function getEmails(AccessTokenInterface $accessToken)
129
    {
130
        return $this->request('GET', 'user/emails', [], $accessToken);
131
    }
132
}
133