Completed
Push — master ( 5c380a...3df6d0 )
by Hans
04:19
created

Authentication::assertValidScopes()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5.0909

Importance

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