Completed
Push — master ( 3df6d0...513e0e )
by Hans
06:54 queued 05:39
created

Authentication   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 72.21%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 8
dl 0
loc 238
ccs 52
cts 72
cp 0.7221
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A withAccessToken() 0 11 1
A onlyAccessToken() 0 9 1
A getBaseUriWithVersion() 0 4 1
A getAuthenticationUrl() 0 17 1
A assertValidScopes() 0 23 5
A requestAccessToken() 0 30 4
A execute() 0 14 1
A getAccessToken() 0 4 1
1
<?php
2
3
/*
4
 * This file is part of the Pinterest PHP library.
5
 *
6
 * (c) Hans Ott <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.md.
10
 *
11
 * Source: https://github.com/hansott/pinterest-php
12
 */
13
14
namespace Pinterest;
15
16
use Pinterest\App\Scope;
17
use Pinterest\Http\Request;
18
use Pinterest\Http\ClientInterface;
19
use Pinterest\Api\Exceptions\TokenMissing;
20
use Pinterest\Api\Exceptions\TooManyScopesGiven;
21
use Pinterest\Api\Exceptions\AtLeastOneScopeNeeded;
22
use Pinterest\Api\Exceptions\InvalidScopeException;
23
use Pinterest\Http\Exceptions\RateLimitedReached;
24
25
/**
26
 * This class is responsible for authenticating requests.
27
 *
28
 * @author Toon Daelman <[email protected]>
29
 */
30
final class Authentication implements ClientInterface
31
{
32
    /**
33
     * The API base uri.
34
     *
35
     * @var string
36
     */
37
    const BASE_URI = 'https://api.pinterest.com';
38
39
    /**
40
     * The API version.
41
     *
42
     * @var string
43
     */
44
    const API_VERSION = 'v1';
45
46
    /**
47
     * The HTTP client.
48
     *
49
     * @var ClientInterface
50
     */
51
    private $http;
52
53
    /**
54
     * The client ID.
55
     *
56
     * @var string
57
     */
58
    private $clientId;
59
60
    /**
61
     * The client secret.
62
     *
63
     * @var string
64
     */
65
    private $clientSecret;
66
67
    /**
68
     * The access token.
69
     *
70
     * @var string
71
     */
72
    private $accessToken;
73
74
    /**
75
     * The Constructor.
76
     *
77
     * @param ClientInterface $client       The http client.
78
     * @param string          $clientId     The client id.
79
     * @param string          $clientSecret The client secret.
80
     */
81 60
    public function __construct(ClientInterface $client, $clientId, $clientSecret)
82
    {
83 60
        $this->http = $client;
84 60
        $this->clientId = (string) $clientId;
85 60
        $this->clientSecret = (string) $clientSecret;
86 60
    }
87
88
    /**
89
     * Alternative constructor for when we already have an accessToken.
90
     *
91
     * @param ClientInterface $client       The (un-authenticated) HTTP client.
92
     * @param string          $clientId     The client id.
93
     * @param string          $clientSecret The client secret.
94
     * @param string          $accessToken  The OAuth access token.
95
     *
96
     * @return static
97
     */
98 56
    public static function withAccessToken(
99
        ClientInterface $client,
100
        $clientId,
101
        $clientSecret,
102
        $accessToken
103
    ) {
104 56
        $authentication = new static($client, $clientId, $clientSecret);
105 56
        $authentication->accessToken = (string) $accessToken;
106
107 56
        return $authentication;
108
    }
109
110
    /**
111
     * Alternative constructor for when we only have an accessToken.
112
     *
113
     * ATTENTION: only the execute method will work, as the others need client id and secret.
114
     *
115
     * @param ClientInterface $client      The HTTP client.
116
     * @param string          $accessToken The OAuth access token.
117
     *
118
     * @return static
119
     */
120 2
    public static function onlyAccessToken(
121
        ClientInterface $client,
122
        $accessToken
123
    ) {
124 2
        $authentication = new static($client, null, null);
125 2
        $authentication->accessToken = (string) $accessToken;
126
127 2
        return $authentication;
128
    }
129
130 34
    private function getBaseUriWithVersion()
131
    {
132 34
        return sprintf('%s/%s/', static::BASE_URI, static::API_VERSION);
133
    }
134
135
    /**
136
     * First step of the OAuth process.
137
     *
138
     * @param string $redirectUrl The OAuth redirect url (where code gets sent).
139
     * @param array  $scopes      An array of scopes (see assertValidScopes).
140
     * @param string $state       A unique code you can use to check if the redirect is not spoofed.
141
     *
142
     * @return string The redirect url.
143
     */
144 2
    public function getAuthenticationUrl($redirectUrl, array $scopes, $state)
145
    {
146 2
        $this->assertValidScopes($scopes);
147
148
        $params = array(
149 2
            'response_type' => 'code',
150 2
            'redirect_uri' => (string) $redirectUrl,
151 2
            'client_id' => $this->clientId,
152 2
            'scope' => implode(',', $scopes),
153 2
            'state' => (string) $state,
154 1
        );
155
156 2
        return sprintf(
157 2
            'https://api.pinterest.com/oauth/?%s',
158 2
            http_build_query($params)
159 1
        );
160
    }
161
162
    /**
163
     * Checks if an array of given scopes contains only valid scopes (and at least one).
164
     *
165
     * @param array $scopes The array of scopes to check.
166
     *
167
     * @throws InvalidScopeException When invalid scope in the given array.
168
     * @throws AtLeastOneScopeNeeded When no scopes given.
169
     * @throws TooManyScopesGiven    When double scopes in the list.
170
     */
171 2
    private function assertValidScopes(array $scopes)
172
    {
173
        $allowedScopes = array(
174 2
            Scope::READ_PUBLIC,
175 2
            Scope::WRITE_PUBLIC,
176 2
            Scope::READ_RELATIONSHIPS,
177 2
            Scope::WRITE_RELATIONSHIPS,
178 1
        );
179
180 2
        foreach ($scopes as $scope) {
181 2
            if (!in_array($scope, $allowedScopes, true)) {
182 2
                throw new InvalidScopeException($scope);
183
            }
184 1
        }
185
186 2
        if (count($scopes) < 1) {
187
            throw new AtLeastOneScopeNeeded();
188
        }
189
190 2
        if (count($scopes) > count($allowedScopes)) {
191
            throw new TooManyScopesGiven();
192
        }
193 2
    }
194
195
    /**
196
     * Second step of the OAuth process.
197
     *
198
     * @param string $code The OAuth code, caught from the redirect page.
199
     *
200
     * @return string The OAuth access token.
201
     *
202
     * @throws TokenMissing
203
     * @throws RateLimitedReached
204
     */
205
    public function requestAccessToken($code)
206
    {
207
        $request = new Request(
208
            'POST',
209
            $this->getBaseUriWithVersion().'oauth/token',
210
            array(
211
                'grant_type' => 'authorization_code',
212
                'client_id' => $this->clientId,
213
                'client_secret' => $this->clientSecret,
214
                'code' => (string) $code,
215
            )
216
        );
217
218
        $response = $this->http->execute($request);
219
220
        if ($response->rateLimited()) {
221
            throw new RateLimitedReached($response);
222
        }
223
224
        if (
225
            !isset($response->body)
226
            || !isset($response->body->access_token)
227
        ) {
228
            throw new TokenMissing();
229
        }
230
231
        $this->accessToken = $response->body->access_token;
232
233
        return $this->accessToken;
234
    }
235
236
    /**
237
     * Executes a http request.
238
     *
239
     * @param Request $request The http request.
240
     *
241
     * @return Http\Response The http response.
242
     */
243 34
    public function execute(Request $request)
244
    {
245 34
        $headers = $request->getHeaders();
246 34
        $headers['Authorization'] = sprintf('BEARER %s', $this->accessToken);
247
248 34
        $authenticatedRequest = new Request(
249 34
            $request->getMethod(),
250 34
            $this->getBaseUriWithVersion().$request->getEndpoint(),
251 34
            $request->getParams(),
252 17
            $headers
253 17
        );
254
255 34
        return $this->http->execute($authenticatedRequest);
256
    }
257
258
    /**
259
     * Returns the access token for persisting in some storage.
260
     *
261
     * @return string The OAuth access token.
262
     */
263 4
    public function getAccessToken()
264
    {
265 4
        return $this->accessToken;
266
    }
267
}
268