Passed
Push — master ( 14fbd7...a7a005 )
by
unknown
55s queued 15s
created
src/Provider/Mastodon.php 2 patches
Indentation   +110 added lines, -110 removed lines patch added patch discarded remove patch
@@ -10,114 +10,114 @@
 block discarded – undo
10 10
 
11 11
 class Mastodon extends OAuth2
12 12
 {
13
-    /**
14
-     * {@inheritdoc}
15
-     */
16
-    public $scope = 'read';
17
-
18
-    /**
19
-     * {@inheritdoc}
20
-     */
21
-    protected $apiDocumentation = 'https://docs.joinmastodon.org/spec/oauth/';
22
-
23
-    /**
24
-     * {@inheritdoc}
25
-     */
26
-    protected function configure()
27
-    {
28
-        parent::configure();
29
-
30
-        if (!$this->config->exists('url')) {
31
-            throw new InvalidApplicationCredentialsException(
32
-                'You must define a Mastodon instance url'
33
-            );
34
-        }
35
-        $url = $this->config->get('url');
36
-
37
-        $this->apiBaseUrl = $url . '/api/v1';
38
-
39
-        $this->authorizeUrl = $url . '/oauth/authorize';
40
-        $this->accessTokenUrl = $url . '/oauth/token';
41
-    }
42
-
43
-    /**
44
-     * {@inheritdoc}
45
-     */
46
-    public function getUserProfile()
47
-    {
48
-        $response = $this->apiRequest('accounts/verify_credentials', 'GET', []);
49
-
50
-        $data = new Data\Collection($response);
51
-
52
-        if (!$data->exists('id') || !$data->get('id')) {
53
-            throw new UnexpectedApiResponseException(
54
-                'Provider API returned an unexpected response.'
55
-            );
56
-        }
57
-
58
-        $userProfile = new Profile();
59
-
60
-        $userProfile->identifier = $data->get('id');
61
-        $userProfile->displayName = $data->get('username');
62
-        $userProfile->photoURL =
63
-            $data->get('avatar') ?: $data->get('avatar_static');
64
-        $userProfile->webSiteURL = $data->get('url');
65
-        $userProfile->description = $data->get('note');
66
-        $userProfile->firstName = $data->get('display_name');
67
-
68
-        return $userProfile;
69
-    }
70
-
71
-    public function setUserStatus($status)
72
-    {
73
-        // Prepare request parameters.
74
-        $params = [];
75
-        if (isset($status['message'])) {
76
-            $params['status'] = $status['message'];
77
-        }
78
-
79
-        if (isset($status['picture'])) {
80
-            $headers = [
81
-                'Content-Type' => 'multipart/form-data',
82
-            ];
83
-
84
-            $pictures = $status['picture'];
85
-
86
-            $ids = [];
87
-
88
-            foreach ($pictures as $picture) {
89
-                $images = $this->apiRequest(
90
-                    $this->config->get('url') . '/api/v2/media',
91
-                    'POST',
92
-                    [
93
-                        'file' => new \CurlFile(
94
-                            $picture,
95
-                            'image/jpg',
96
-                            'filename'
97
-                        ),
98
-                    ],
99
-                    $headers,
100
-                    true
101
-                );
102
-
103
-                $ids[] = $images->id;
104
-            }
105
-
106
-            $params['media_ids'] = $ids;
107
-        }
108
-
109
-        $headers = [
110
-            'Content-Type' => 'application/json',
111
-        ];
112
-
113
-        $response = $this->apiRequest(
114
-            'statuses',
115
-            'POST',
116
-            $params,
117
-            $headers,
118
-            false
119
-        );
120
-
121
-        return $response;
122
-    }
13
+	/**
14
+	 * {@inheritdoc}
15
+	 */
16
+	public $scope = 'read';
17
+
18
+	/**
19
+	 * {@inheritdoc}
20
+	 */
21
+	protected $apiDocumentation = 'https://docs.joinmastodon.org/spec/oauth/';
22
+
23
+	/**
24
+	 * {@inheritdoc}
25
+	 */
26
+	protected function configure()
27
+	{
28
+		parent::configure();
29
+
30
+		if (!$this->config->exists('url')) {
31
+			throw new InvalidApplicationCredentialsException(
32
+				'You must define a Mastodon instance url'
33
+			);
34
+		}
35
+		$url = $this->config->get('url');
36
+
37
+		$this->apiBaseUrl = $url . '/api/v1';
38
+
39
+		$this->authorizeUrl = $url . '/oauth/authorize';
40
+		$this->accessTokenUrl = $url . '/oauth/token';
41
+	}
42
+
43
+	/**
44
+	 * {@inheritdoc}
45
+	 */
46
+	public function getUserProfile()
47
+	{
48
+		$response = $this->apiRequest('accounts/verify_credentials', 'GET', []);
49
+
50
+		$data = new Data\Collection($response);
51
+
52
+		if (!$data->exists('id') || !$data->get('id')) {
53
+			throw new UnexpectedApiResponseException(
54
+				'Provider API returned an unexpected response.'
55
+			);
56
+		}
57
+
58
+		$userProfile = new Profile();
59
+
60
+		$userProfile->identifier = $data->get('id');
61
+		$userProfile->displayName = $data->get('username');
62
+		$userProfile->photoURL =
63
+			$data->get('avatar') ?: $data->get('avatar_static');
64
+		$userProfile->webSiteURL = $data->get('url');
65
+		$userProfile->description = $data->get('note');
66
+		$userProfile->firstName = $data->get('display_name');
67
+
68
+		return $userProfile;
69
+	}
70
+
71
+	public function setUserStatus($status)
72
+	{
73
+		// Prepare request parameters.
74
+		$params = [];
75
+		if (isset($status['message'])) {
76
+			$params['status'] = $status['message'];
77
+		}
78
+
79
+		if (isset($status['picture'])) {
80
+			$headers = [
81
+				'Content-Type' => 'multipart/form-data',
82
+			];
83
+
84
+			$pictures = $status['picture'];
85
+
86
+			$ids = [];
87
+
88
+			foreach ($pictures as $picture) {
89
+				$images = $this->apiRequest(
90
+					$this->config->get('url') . '/api/v2/media',
91
+					'POST',
92
+					[
93
+						'file' => new \CurlFile(
94
+							$picture,
95
+							'image/jpg',
96
+							'filename'
97
+						),
98
+					],
99
+					$headers,
100
+					true
101
+				);
102
+
103
+				$ids[] = $images->id;
104
+			}
105
+
106
+			$params['media_ids'] = $ids;
107
+		}
108
+
109
+		$headers = [
110
+			'Content-Type' => 'application/json',
111
+		];
112
+
113
+		$response = $this->apiRequest(
114
+			'statuses',
115
+			'POST',
116
+			$params,
117
+			$headers,
118
+			false
119
+		);
120
+
121
+		return $response;
122
+	}
123 123
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -27,17 +27,17 @@  discard block
 block discarded – undo
27 27
     {
28 28
         parent::configure();
29 29
 
30
-        if (!$this->config->exists('url')) {
30
+        if ( ! $this->config->exists('url')) {
31 31
             throw new InvalidApplicationCredentialsException(
32 32
                 'You must define a Mastodon instance url'
33 33
             );
34 34
         }
35 35
         $url = $this->config->get('url');
36 36
 
37
-        $this->apiBaseUrl = $url . '/api/v1';
37
+        $this->apiBaseUrl = $url.'/api/v1';
38 38
 
39
-        $this->authorizeUrl = $url . '/oauth/authorize';
40
-        $this->accessTokenUrl = $url . '/oauth/token';
39
+        $this->authorizeUrl = $url.'/oauth/authorize';
40
+        $this->accessTokenUrl = $url.'/oauth/token';
41 41
     }
42 42
 
43 43
     /**
@@ -49,7 +49,7 @@  discard block
 block discarded – undo
49 49
 
50 50
         $data = new Data\Collection($response);
51 51
 
52
-        if (!$data->exists('id') || !$data->get('id')) {
52
+        if ( ! $data->exists('id') || ! $data->get('id')) {
53 53
             throw new UnexpectedApiResponseException(
54 54
                 'Provider API returned an unexpected response.'
55 55
             );
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
 
88 88
             foreach ($pictures as $picture) {
89 89
                 $images = $this->apiRequest(
90
-                    $this->config->get('url') . '/api/v2/media',
90
+                    $this->config->get('url').'/api/v2/media',
91 91
                     'POST',
92 92
                     [
93 93
                         'file' => new \CurlFile(
Please login to merge, or discard this patch.
src/Provider/Apple.php 2 patches
Indentation   +274 added lines, -274 removed lines patch added patch discarded remove patch
@@ -64,278 +64,278 @@
 block discarded – undo
64 64
  */
65 65
 class Apple extends OAuth2
66 66
 {
67
-    /**
68
-     * {@inheritdoc}
69
-     */
70
-    protected $scope = 'name email';
71
-
72
-    /**
73
-     * {@inheritdoc}
74
-     */
75
-    protected $apiBaseUrl = 'https://appleid.apple.com/auth/';
76
-
77
-    /**
78
-     * {@inheritdoc}
79
-     */
80
-    protected $authorizeUrl = 'https://appleid.apple.com/auth/authorize';
81
-
82
-    /**
83
-     * {@inheritdoc}
84
-     */
85
-    protected $accessTokenUrl = 'https://appleid.apple.com/auth/token';
86
-
87
-    /**
88
-     * {@inheritdoc}
89
-     */
90
-    protected $apiDocumentation = 'https://developer.apple.com/documentation/sign_in_with_apple';
91
-
92
-    /**
93
-     * {@inheritdoc}
94
-     * The Sign in with Apple servers require percent encoding (or URL encoding)
95
-     * for its query parameters. If you are using the Sign in with Apple REST API,
96
-     * you must provide values with encoded spaces (`%20`) instead of plus (`+`) signs.
97
-     */
98
-    protected $AuthorizeUrlParametersEncType = PHP_QUERY_RFC3986;
99
-
100
-    /**
101
-     * {@inheritdoc}
102
-     */
103
-    protected function initialize()
104
-    {
105
-        parent::initialize();
106
-        $this->AuthorizeUrlParameters['response_mode'] = 'form_post';
107
-
108
-        if ($this->isRefreshTokenAvailable()) {
109
-            $this->tokenRefreshParameters += [
110
-                'client_id' => $this->clientId,
111
-                'client_secret' => $this->clientSecret,
112
-            ];
113
-        }
114
-    }
115
-
116
-    /**
117
-     * {@inheritdoc}
118
-     * @throws InvalidApplicationCredentialsException
119
-     */
120
-    protected function configure()
121
-    {
122
-        $keys = $this->config->get('keys');
123
-        $keys['secret'] = $this->getSecret();
124
-        $this->config->set('keys', $keys);
125
-        parent::configure();
126
-    }
127
-
128
-    /**
129
-     * {@inheritdoc}
130
-     *
131
-     * include id_token $tokenNames
132
-     */
133
-    public function getAccessToken()
134
-    {
135
-        $tokenNames = [
136
-            'access_token',
137
-            'id_token',
138
-            'access_token_secret',
139
-            'token_type',
140
-            'refresh_token',
141
-            'expires_in',
142
-            'expires_at',
143
-        ];
144
-
145
-        $tokens = [];
146
-
147
-        foreach ($tokenNames as $name) {
148
-            if ($this->getStoredData($name)) {
149
-                $tokens[$name] = $this->getStoredData($name);
150
-            }
151
-        }
152
-
153
-        return $tokens;
154
-    }
155
-
156
-    /**
157
-     * {@inheritdoc}
158
-     */
159
-    protected function validateAccessTokenExchange($response)
160
-    {
161
-        $collection = parent::validateAccessTokenExchange($response);
162
-
163
-        $this->storeData('id_token', $collection->get('id_token'));
164
-
165
-        return $collection;
166
-    }
167
-
168
-    /**
169
-     * Get the user profile
170
-     *
171
-     * @throws HttpClientFailureException
172
-     * @throws InvalidAccessTokenException
173
-     * @throws UnexpectedValueException
174
-     * @throws HttpRequestFailedException
175
-     * @throws Exception
176
-     */
177
-    public function getUserProfile()
178
-    {
179
-        $id_token = $this->getStoredData('id_token');
180
-
181
-        $verifyTokenSignature =
182
-            $this->config->exists('verifyTokenSignature') ? $this->config->get('verifyTokenSignature') : true;
183
-
184
-        if (!$verifyTokenSignature) {
185
-            // payload extraction by https://github.com/omidborjian
186
-            // https://github.com/hybridauth/hybridauth/issues/1095#issuecomment-626479263
187
-            // JWT splits the string to 3 components 1) first is header 2) is payload 3) is signature
188
-            $payload = explode('.', $id_token)[1];
189
-            $payload = json_decode(base64_decode($payload));
190
-        } else {
191
-            // validate the token signature and get the payload
192
-            $publicKeys = $this->apiRequest('keys');
193
-
194
-            JWT::$leeway = 120;
195
-
196
-            $error = false;
197
-            $payload = null;
198
-
199
-            foreach ($publicKeys->keys as $publicKey) {
200
-                try {
201
-                    $jwk = (array)$publicKey;
202
-
203
-                    $key = PublicKeyLoader::load(
204
-                        [
205
-                            'e' => new BigInteger(base64_decode($jwk['e']), 256),
206
-                            'n' => new BigInteger(base64_decode(strtr($jwk['n'], '-_', '+/'), true), 256)
207
-                        ]
208
-                    )
209
-                        ->withHash('sha1')
210
-                        ->withMGFHash('sha1');
211
-
212
-                    $pem = (string)$key;
213
-
214
-                    $payload = (version_compare($this->getJwtVersion(), '6.2') < 0) ?
215
-                        JWT::decode($id_token, $pem, ['RS256']) :
216
-                        JWT::decode($id_token, new Key($pem, 'RS256'));
217
-                    break;
218
-                } catch (Exception $e) {
219
-                    $error = $e->getMessage();
220
-                    if ($e instanceof ExpiredException) {
221
-                        break;
222
-                    }
223
-                }
224
-            }
225
-
226
-            if ($error && !$payload) {
227
-                throw new Exception($error);
228
-            }
229
-        }
230
-
231
-        $data = new Data\Collection($payload);
232
-
233
-        if (!$data->exists('sub')) {
234
-            throw new UnexpectedValueException('Missing token payload.');
235
-        }
236
-
237
-        $userProfile = new User\Profile();
238
-        $userProfile->identifier = $data->get('sub');
239
-        $userProfile->email = $data->get('email');
240
-        $this->storeData('expires_at', $data->get('exp'));
241
-
242
-        if (!empty($_REQUEST['user'])) {
243
-            $objUser = json_decode($_REQUEST['user']);
244
-            $user = new Data\Collection($objUser);
245
-            if (!$user->isEmpty()) {
246
-                $name = $user->get('name');
247
-                if (!empty($name->firstName)) {
248
-                    $userProfile->firstName = $name->firstName;
249
-                    $userProfile->lastName = $name->lastName;
250
-                    $userProfile->displayName = join(' ', [$userProfile->firstName, $userProfile->lastName]);
251
-                }
252
-            }
253
-        }
254
-
255
-        return $userProfile;
256
-    }
257
-
258
-    /**
259
-     * Get the Apple secret as a JWT token
260
-     *
261
-     * @return string secret token
262
-     * @throws InvalidApplicationCredentialsException
263
-     */
264
-    private function getSecret()
265
-    {
266
-        // Your 10-character Team ID
267
-        $team_id = $this->config->filter('keys')->get('team_id');
268
-
269
-        if (!$team_id) {
270
-            throw new InvalidApplicationCredentialsException(
271
-                'Missing parameter team_id: your team id is required to generate the JWS token.'
272
-            );
273
-        }
274
-
275
-        // Your Services ID, e.g. com.aaronparecki.services
276
-        $client_id = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
277
-
278
-        if (!$client_id) {
279
-            throw new InvalidApplicationCredentialsException(
280
-                'Missing parameter id: your client id is required to generate the JWS token.'
281
-            );
282
-        }
283
-
284
-        // Find the 10-char Key ID value from the portal
285
-        $key_id = $this->config->filter('keys')->get('key_id');
286
-
287
-        if (!$key_id) {
288
-            throw new InvalidApplicationCredentialsException(
289
-                'Missing parameter key_id: your key id is required to generate the JWS token.'
290
-            );
291
-        }
292
-
293
-        // Find the 10-char Key ID value from the portal
294
-        $key_content = $this->config->filter('keys')->get('key_content');
295
-
296
-        // Save your private key from Apple in a file called `key.txt`
297
-        if (!$key_content) {
298
-            $key_file = $this->config->filter('keys')->get('key_file');
299
-
300
-            if (!$key_file) {
301
-                throw new InvalidApplicationCredentialsException(
302
-                    'Missing parameter key_content or key_file: your key is required to generate the JWS token.'
303
-                );
304
-            }
305
-
306
-            if (!file_exists($key_file)) {
307
-                throw new InvalidApplicationCredentialsException(
308
-                    "Your key file $key_file does not exist."
309
-                );
310
-            }
311
-
312
-            $key_content = file_get_contents($key_file);
313
-        }
314
-
315
-        $data = [
316
-            'iat' => time(),
317
-            'exp' => time() + 86400 * 180,
318
-            'iss' => $team_id,
319
-            'aud' => 'https://appleid.apple.com',
320
-            'sub' => $client_id
321
-        ];
322
-
323
-        return JWT::encode($data, $key_content, 'ES256', $key_id);
324
-    }
325
-
326
-    /**
327
-     * Try to get the installed JWT version
328
-     *
329
-     * If composer 2 is installed use InstalledVersions::getVersion,
330
-     * otherwise return an empty string because no version check is available
331
-     *
332
-     * @return string|null
333
-     */
334
-    private function getJwtVersion()
335
-    {
336
-        // assume old JWT version if no version check is possible because composer 1 is installed
337
-        return class_exists('Composer\InstalledVersions') ?
338
-            InstalledVersions::getVersion('firebase/php-jwt') :
339
-            '';
340
-    }
67
+	/**
68
+	 * {@inheritdoc}
69
+	 */
70
+	protected $scope = 'name email';
71
+
72
+	/**
73
+	 * {@inheritdoc}
74
+	 */
75
+	protected $apiBaseUrl = 'https://appleid.apple.com/auth/';
76
+
77
+	/**
78
+	 * {@inheritdoc}
79
+	 */
80
+	protected $authorizeUrl = 'https://appleid.apple.com/auth/authorize';
81
+
82
+	/**
83
+	 * {@inheritdoc}
84
+	 */
85
+	protected $accessTokenUrl = 'https://appleid.apple.com/auth/token';
86
+
87
+	/**
88
+	 * {@inheritdoc}
89
+	 */
90
+	protected $apiDocumentation = 'https://developer.apple.com/documentation/sign_in_with_apple';
91
+
92
+	/**
93
+	 * {@inheritdoc}
94
+	 * The Sign in with Apple servers require percent encoding (or URL encoding)
95
+	 * for its query parameters. If you are using the Sign in with Apple REST API,
96
+	 * you must provide values with encoded spaces (`%20`) instead of plus (`+`) signs.
97
+	 */
98
+	protected $AuthorizeUrlParametersEncType = PHP_QUERY_RFC3986;
99
+
100
+	/**
101
+	 * {@inheritdoc}
102
+	 */
103
+	protected function initialize()
104
+	{
105
+		parent::initialize();
106
+		$this->AuthorizeUrlParameters['response_mode'] = 'form_post';
107
+
108
+		if ($this->isRefreshTokenAvailable()) {
109
+			$this->tokenRefreshParameters += [
110
+				'client_id' => $this->clientId,
111
+				'client_secret' => $this->clientSecret,
112
+			];
113
+		}
114
+	}
115
+
116
+	/**
117
+	 * {@inheritdoc}
118
+	 * @throws InvalidApplicationCredentialsException
119
+	 */
120
+	protected function configure()
121
+	{
122
+		$keys = $this->config->get('keys');
123
+		$keys['secret'] = $this->getSecret();
124
+		$this->config->set('keys', $keys);
125
+		parent::configure();
126
+	}
127
+
128
+	/**
129
+	 * {@inheritdoc}
130
+	 *
131
+	 * include id_token $tokenNames
132
+	 */
133
+	public function getAccessToken()
134
+	{
135
+		$tokenNames = [
136
+			'access_token',
137
+			'id_token',
138
+			'access_token_secret',
139
+			'token_type',
140
+			'refresh_token',
141
+			'expires_in',
142
+			'expires_at',
143
+		];
144
+
145
+		$tokens = [];
146
+
147
+		foreach ($tokenNames as $name) {
148
+			if ($this->getStoredData($name)) {
149
+				$tokens[$name] = $this->getStoredData($name);
150
+			}
151
+		}
152
+
153
+		return $tokens;
154
+	}
155
+
156
+	/**
157
+	 * {@inheritdoc}
158
+	 */
159
+	protected function validateAccessTokenExchange($response)
160
+	{
161
+		$collection = parent::validateAccessTokenExchange($response);
162
+
163
+		$this->storeData('id_token', $collection->get('id_token'));
164
+
165
+		return $collection;
166
+	}
167
+
168
+	/**
169
+	 * Get the user profile
170
+	 *
171
+	 * @throws HttpClientFailureException
172
+	 * @throws InvalidAccessTokenException
173
+	 * @throws UnexpectedValueException
174
+	 * @throws HttpRequestFailedException
175
+	 * @throws Exception
176
+	 */
177
+	public function getUserProfile()
178
+	{
179
+		$id_token = $this->getStoredData('id_token');
180
+
181
+		$verifyTokenSignature =
182
+			$this->config->exists('verifyTokenSignature') ? $this->config->get('verifyTokenSignature') : true;
183
+
184
+		if (!$verifyTokenSignature) {
185
+			// payload extraction by https://github.com/omidborjian
186
+			// https://github.com/hybridauth/hybridauth/issues/1095#issuecomment-626479263
187
+			// JWT splits the string to 3 components 1) first is header 2) is payload 3) is signature
188
+			$payload = explode('.', $id_token)[1];
189
+			$payload = json_decode(base64_decode($payload));
190
+		} else {
191
+			// validate the token signature and get the payload
192
+			$publicKeys = $this->apiRequest('keys');
193
+
194
+			JWT::$leeway = 120;
195
+
196
+			$error = false;
197
+			$payload = null;
198
+
199
+			foreach ($publicKeys->keys as $publicKey) {
200
+				try {
201
+					$jwk = (array)$publicKey;
202
+
203
+					$key = PublicKeyLoader::load(
204
+						[
205
+							'e' => new BigInteger(base64_decode($jwk['e']), 256),
206
+							'n' => new BigInteger(base64_decode(strtr($jwk['n'], '-_', '+/'), true), 256)
207
+						]
208
+					)
209
+						->withHash('sha1')
210
+						->withMGFHash('sha1');
211
+
212
+					$pem = (string)$key;
213
+
214
+					$payload = (version_compare($this->getJwtVersion(), '6.2') < 0) ?
215
+						JWT::decode($id_token, $pem, ['RS256']) :
216
+						JWT::decode($id_token, new Key($pem, 'RS256'));
217
+					break;
218
+				} catch (Exception $e) {
219
+					$error = $e->getMessage();
220
+					if ($e instanceof ExpiredException) {
221
+						break;
222
+					}
223
+				}
224
+			}
225
+
226
+			if ($error && !$payload) {
227
+				throw new Exception($error);
228
+			}
229
+		}
230
+
231
+		$data = new Data\Collection($payload);
232
+
233
+		if (!$data->exists('sub')) {
234
+			throw new UnexpectedValueException('Missing token payload.');
235
+		}
236
+
237
+		$userProfile = new User\Profile();
238
+		$userProfile->identifier = $data->get('sub');
239
+		$userProfile->email = $data->get('email');
240
+		$this->storeData('expires_at', $data->get('exp'));
241
+
242
+		if (!empty($_REQUEST['user'])) {
243
+			$objUser = json_decode($_REQUEST['user']);
244
+			$user = new Data\Collection($objUser);
245
+			if (!$user->isEmpty()) {
246
+				$name = $user->get('name');
247
+				if (!empty($name->firstName)) {
248
+					$userProfile->firstName = $name->firstName;
249
+					$userProfile->lastName = $name->lastName;
250
+					$userProfile->displayName = join(' ', [$userProfile->firstName, $userProfile->lastName]);
251
+				}
252
+			}
253
+		}
254
+
255
+		return $userProfile;
256
+	}
257
+
258
+	/**
259
+	 * Get the Apple secret as a JWT token
260
+	 *
261
+	 * @return string secret token
262
+	 * @throws InvalidApplicationCredentialsException
263
+	 */
264
+	private function getSecret()
265
+	{
266
+		// Your 10-character Team ID
267
+		$team_id = $this->config->filter('keys')->get('team_id');
268
+
269
+		if (!$team_id) {
270
+			throw new InvalidApplicationCredentialsException(
271
+				'Missing parameter team_id: your team id is required to generate the JWS token.'
272
+			);
273
+		}
274
+
275
+		// Your Services ID, e.g. com.aaronparecki.services
276
+		$client_id = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
277
+
278
+		if (!$client_id) {
279
+			throw new InvalidApplicationCredentialsException(
280
+				'Missing parameter id: your client id is required to generate the JWS token.'
281
+			);
282
+		}
283
+
284
+		// Find the 10-char Key ID value from the portal
285
+		$key_id = $this->config->filter('keys')->get('key_id');
286
+
287
+		if (!$key_id) {
288
+			throw new InvalidApplicationCredentialsException(
289
+				'Missing parameter key_id: your key id is required to generate the JWS token.'
290
+			);
291
+		}
292
+
293
+		// Find the 10-char Key ID value from the portal
294
+		$key_content = $this->config->filter('keys')->get('key_content');
295
+
296
+		// Save your private key from Apple in a file called `key.txt`
297
+		if (!$key_content) {
298
+			$key_file = $this->config->filter('keys')->get('key_file');
299
+
300
+			if (!$key_file) {
301
+				throw new InvalidApplicationCredentialsException(
302
+					'Missing parameter key_content or key_file: your key is required to generate the JWS token.'
303
+				);
304
+			}
305
+
306
+			if (!file_exists($key_file)) {
307
+				throw new InvalidApplicationCredentialsException(
308
+					"Your key file $key_file does not exist."
309
+				);
310
+			}
311
+
312
+			$key_content = file_get_contents($key_file);
313
+		}
314
+
315
+		$data = [
316
+			'iat' => time(),
317
+			'exp' => time() + 86400 * 180,
318
+			'iss' => $team_id,
319
+			'aud' => 'https://appleid.apple.com',
320
+			'sub' => $client_id
321
+		];
322
+
323
+		return JWT::encode($data, $key_content, 'ES256', $key_id);
324
+	}
325
+
326
+	/**
327
+	 * Try to get the installed JWT version
328
+	 *
329
+	 * If composer 2 is installed use InstalledVersions::getVersion,
330
+	 * otherwise return an empty string because no version check is available
331
+	 *
332
+	 * @return string|null
333
+	 */
334
+	private function getJwtVersion()
335
+	{
336
+		// assume old JWT version if no version check is possible because composer 1 is installed
337
+		return class_exists('Composer\InstalledVersions') ?
338
+			InstalledVersions::getVersion('firebase/php-jwt') :
339
+			'';
340
+	}
341 341
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -18 removed lines patch added patch discarded remove patch
@@ -181,7 +181,7 @@  discard block
 block discarded – undo
181 181
         $verifyTokenSignature =
182 182
             $this->config->exists('verifyTokenSignature') ? $this->config->get('verifyTokenSignature') : true;
183 183
 
184
-        if (!$verifyTokenSignature) {
184
+        if ( ! $verifyTokenSignature) {
185 185
             // payload extraction by https://github.com/omidborjian
186 186
             // https://github.com/hybridauth/hybridauth/issues/1095#issuecomment-626479263
187 187
             // JWT splits the string to 3 components 1) first is header 2) is payload 3) is signature
@@ -198,7 +198,7 @@  discard block
 block discarded – undo
198 198
 
199 199
             foreach ($publicKeys->keys as $publicKey) {
200 200
                 try {
201
-                    $jwk = (array)$publicKey;
201
+                    $jwk = (array) $publicKey;
202 202
 
203 203
                     $key = PublicKeyLoader::load(
204 204
                         [
@@ -209,11 +209,10 @@  discard block
 block discarded – undo
209 209
                         ->withHash('sha1')
210 210
                         ->withMGFHash('sha1');
211 211
 
212
-                    $pem = (string)$key;
212
+                    $pem = (string) $key;
213 213
 
214 214
                     $payload = (version_compare($this->getJwtVersion(), '6.2') < 0) ?
215
-                        JWT::decode($id_token, $pem, ['RS256']) :
216
-                        JWT::decode($id_token, new Key($pem, 'RS256'));
215
+                        JWT::decode($id_token, $pem, ['RS256']) : JWT::decode($id_token, new Key($pem, 'RS256'));
217 216
                     break;
218 217
                 } catch (Exception $e) {
219 218
                     $error = $e->getMessage();
@@ -223,14 +222,14 @@  discard block
 block discarded – undo
223 222
                 }
224 223
             }
225 224
 
226
-            if ($error && !$payload) {
225
+            if ($error && ! $payload) {
227 226
                 throw new Exception($error);
228 227
             }
229 228
         }
230 229
 
231 230
         $data = new Data\Collection($payload);
232 231
 
233
-        if (!$data->exists('sub')) {
232
+        if ( ! $data->exists('sub')) {
234 233
             throw new UnexpectedValueException('Missing token payload.');
235 234
         }
236 235
 
@@ -239,12 +238,12 @@  discard block
 block discarded – undo
239 238
         $userProfile->email = $data->get('email');
240 239
         $this->storeData('expires_at', $data->get('exp'));
241 240
 
242
-        if (!empty($_REQUEST['user'])) {
241
+        if ( ! empty($_REQUEST['user'])) {
243 242
             $objUser = json_decode($_REQUEST['user']);
244 243
             $user = new Data\Collection($objUser);
245
-            if (!$user->isEmpty()) {
244
+            if ( ! $user->isEmpty()) {
246 245
                 $name = $user->get('name');
247
-                if (!empty($name->firstName)) {
246
+                if ( ! empty($name->firstName)) {
248 247
                     $userProfile->firstName = $name->firstName;
249 248
                     $userProfile->lastName = $name->lastName;
250 249
                     $userProfile->displayName = join(' ', [$userProfile->firstName, $userProfile->lastName]);
@@ -266,7 +265,7 @@  discard block
 block discarded – undo
266 265
         // Your 10-character Team ID
267 266
         $team_id = $this->config->filter('keys')->get('team_id');
268 267
 
269
-        if (!$team_id) {
268
+        if ( ! $team_id) {
270 269
             throw new InvalidApplicationCredentialsException(
271 270
                 'Missing parameter team_id: your team id is required to generate the JWS token.'
272 271
             );
@@ -275,7 +274,7 @@  discard block
 block discarded – undo
275 274
         // Your Services ID, e.g. com.aaronparecki.services
276 275
         $client_id = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
277 276
 
278
-        if (!$client_id) {
277
+        if ( ! $client_id) {
279 278
             throw new InvalidApplicationCredentialsException(
280 279
                 'Missing parameter id: your client id is required to generate the JWS token.'
281 280
             );
@@ -284,7 +283,7 @@  discard block
 block discarded – undo
284 283
         // Find the 10-char Key ID value from the portal
285 284
         $key_id = $this->config->filter('keys')->get('key_id');
286 285
 
287
-        if (!$key_id) {
286
+        if ( ! $key_id) {
288 287
             throw new InvalidApplicationCredentialsException(
289 288
                 'Missing parameter key_id: your key id is required to generate the JWS token.'
290 289
             );
@@ -294,16 +293,16 @@  discard block
 block discarded – undo
294 293
         $key_content = $this->config->filter('keys')->get('key_content');
295 294
 
296 295
         // Save your private key from Apple in a file called `key.txt`
297
-        if (!$key_content) {
296
+        if ( ! $key_content) {
298 297
             $key_file = $this->config->filter('keys')->get('key_file');
299 298
 
300
-            if (!$key_file) {
299
+            if ( ! $key_file) {
301 300
                 throw new InvalidApplicationCredentialsException(
302 301
                     'Missing parameter key_content or key_file: your key is required to generate the JWS token.'
303 302
                 );
304 303
             }
305 304
 
306
-            if (!file_exists($key_file)) {
305
+            if ( ! file_exists($key_file)) {
307 306
                 throw new InvalidApplicationCredentialsException(
308 307
                     "Your key file $key_file does not exist."
309 308
                 );
@@ -335,7 +334,6 @@  discard block
 block discarded – undo
335 334
     {
336 335
         // assume old JWT version if no version check is possible because composer 1 is installed
337 336
         return class_exists('Composer\InstalledVersions') ?
338
-            InstalledVersions::getVersion('firebase/php-jwt') :
339
-            '';
337
+            InstalledVersions::getVersion('firebase/php-jwt') : '';
340 338
     }
341 339
 }
Please login to merge, or discard this patch.
src/Adapter/OAuth2.php 2 patches
Indentation   +716 added lines, -716 removed lines patch added patch discarded remove patch
@@ -24,721 +24,721 @@
 block discarded – undo
24 24
  */
25 25
 abstract class OAuth2 extends AbstractAdapter implements AdapterInterface
26 26
 {
27
-    /**
28
-     * Client Identifier
29
-     *
30
-     * RFC6749: client_id REQUIRED. The client identifier issued to the client during
31
-     * the registration process described by Section 2.2.
32
-     *
33
-     * http://tools.ietf.org/html/rfc6749#section-2.2
34
-     *
35
-     * @var string
36
-     */
37
-    protected $clientId = '';
38
-
39
-    /**
40
-     * Client Secret
41
-     *
42
-     * RFC6749: client_secret REQUIRED. The client secret. The client MAY omit the
43
-     * parameter if the client secret is an empty string.
44
-     *
45
-     * http://tools.ietf.org/html/rfc6749#section-2.2
46
-     *
47
-     * @var string
48
-     */
49
-    protected $clientSecret = '';
50
-
51
-    /**
52
-     * Access Token Scope
53
-     *
54
-     * RFC6749: The authorization and token endpoints allow the client to specify the
55
-     * scope of the access request using the "scope" request parameter.
56
-     *
57
-     * http://tools.ietf.org/html/rfc6749#section-3.3
58
-     *
59
-     * @var string
60
-     */
61
-    protected $scope = '';
62
-
63
-    /**
64
-     * Base URL to provider API
65
-     *
66
-     * This var will be used to build urls when sending signed requests
67
-     *
68
-     * @var string
69
-     */
70
-    protected $apiBaseUrl = '';
71
-
72
-    /**
73
-     * Authorization Endpoint
74
-     *
75
-     * RFC6749: The authorization endpoint is used to interact with the resource
76
-     * owner and obtain an authorization grant.
77
-     *
78
-     * http://tools.ietf.org/html/rfc6749#section-3.1
79
-     *
80
-     * @var string
81
-     */
82
-    protected $authorizeUrl = '';
83
-
84
-    /**
85
-     * Access Token Endpoint
86
-     *
87
-     * RFC6749: The token endpoint is used by the client to obtain an access token by
88
-     * presenting its authorization grant or refresh token.
89
-     *
90
-     * http://tools.ietf.org/html/rfc6749#section-3.2
91
-     *
92
-     * @var string
93
-     */
94
-    protected $accessTokenUrl = '';
95
-
96
-    /**
97
-     * TokenInfo endpoint
98
-     *
99
-     * Access token validation. OPTIONAL.
100
-     *
101
-     * @var string
102
-     */
103
-    protected $accessTokenInfoUrl = '';
104
-
105
-    /**
106
-     * IPD API Documentation
107
-     *
108
-     * OPTIONAL.
109
-     *
110
-     * @var string
111
-     */
112
-    protected $apiDocumentation = '';
113
-
114
-    /**
115
-     * Redirection Endpoint or Callback
116
-     *
117
-     * RFC6749: After completing its interaction with the resource owner, the
118
-     * authorization server directs the resource owner's user-agent back to
119
-     * the client.
120
-     *
121
-     * http://tools.ietf.org/html/rfc6749#section-3.1.2
122
-     *
123
-     * @var string
124
-     */
125
-    protected $callback = '';
126
-
127
-    /**
128
-     * Authorization Url Parameters
129
-     *
130
-     * @var array
131
-     */
132
-    protected $AuthorizeUrlParameters = [];
133
-
134
-
135
-    /**
136
-     * Authorization Url Parameter encoding type
137
-     * @see https://www.php.net/manual/de/function.http-build-query.php
138
-     *
139
-     * @var string
140
-     */
141
-    protected $AuthorizeUrlParametersEncType = PHP_QUERY_RFC1738;
142
-
143
-    /**
144
-     * Authorization Request State
145
-     *
146
-     * @var bool
147
-     */
148
-    protected $supportRequestState = true;
149
-
150
-    /**
151
-     * Access Token name
152
-     *
153
-     * While most providers will use 'access_token' as name for the Access Token attribute, other do not.
154
-     * On the latter case, this should be set by sub classes.
155
-     *
156
-     * @var string
157
-     */
158
-    protected $accessTokenName = 'access_token';
159
-
160
-    /**
161
-     * Authorization Request HTTP method.
162
-     *
163
-     * @see exchangeCodeForAccessToken()
164
-     *
165
-     * @var string
166
-     */
167
-    protected $tokenExchangeMethod = 'POST';
168
-
169
-    /**
170
-     * Authorization Request URL parameters.
171
-     *
172
-     * Sub classes may change add any additional parameter when necessary.
173
-     *
174
-     * @see exchangeCodeForAccessToken()
175
-     *
176
-     * @var array
177
-     */
178
-    protected $tokenExchangeParameters = [];
179
-
180
-    /**
181
-     * Authorization Request HTTP headers.
182
-     *
183
-     * Sub classes may add any additional header when necessary.
184
-     *
185
-     * @see exchangeCodeForAccessToken()
186
-     *
187
-     * @var array
188
-     */
189
-    protected $tokenExchangeHeaders = [];
190
-
191
-    /**
192
-     * Refresh Token Request HTTP method.
193
-     *
194
-     * @see refreshAccessToken()
195
-     *
196
-     * @var string
197
-     */
198
-    protected $tokenRefreshMethod = 'POST';
199
-
200
-    /**
201
-     * Refresh Token Request URL parameters.
202
-     *
203
-     * Sub classes may change add any additional parameter when necessary.
204
-     *
205
-     * @see refreshAccessToken()
206
-     *
207
-     * @var array|null
208
-     */
209
-    protected $tokenRefreshParameters = null;
210
-
211
-    /**
212
-     * Refresh Token Request HTTP headers.
213
-     *
214
-     * Sub classes may add any additional header when necessary.
215
-     *
216
-     * @see refreshAccessToken()
217
-     *
218
-     * @var array
219
-     */
220
-    protected $tokenRefreshHeaders = [];
221
-
222
-    /**
223
-     * Authorization Request URL parameters.
224
-     *
225
-     * Sub classes may change add any additional parameter when necessary.
226
-     *
227
-     * @see apiRequest()
228
-     *
229
-     * @var array
230
-     */
231
-    protected $apiRequestParameters = [];
232
-
233
-    /**
234
-     * Authorization Request HTTP headers.
235
-     *
236
-     * Sub classes may add any additional header when necessary.
237
-     *
238
-     * @see apiRequest()
239
-     *
240
-     * @var array
241
-     */
242
-    protected $apiRequestHeaders = [];
243
-
244
-    /**
245
-     * {@inheritdoc}
246
-     */
247
-    protected function configure()
248
-    {
249
-        $this->clientId = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
250
-        $this->clientSecret = $this->config->filter('keys')->get('secret');
251
-
252
-        if (!$this->clientId || !$this->clientSecret) {
253
-            throw new InvalidApplicationCredentialsException(
254
-                'Your application id is required in order to connect to ' . $this->providerId
255
-            );
256
-        }
257
-
258
-        $this->scope = $this->config->exists('scope') ? $this->config->get('scope') : $this->scope;
259
-
260
-        if ($this->config->exists('tokens')) {
261
-            $this->setAccessToken($this->config->get('tokens'));
262
-        }
27
+	/**
28
+	 * Client Identifier
29
+	 *
30
+	 * RFC6749: client_id REQUIRED. The client identifier issued to the client during
31
+	 * the registration process described by Section 2.2.
32
+	 *
33
+	 * http://tools.ietf.org/html/rfc6749#section-2.2
34
+	 *
35
+	 * @var string
36
+	 */
37
+	protected $clientId = '';
38
+
39
+	/**
40
+	 * Client Secret
41
+	 *
42
+	 * RFC6749: client_secret REQUIRED. The client secret. The client MAY omit the
43
+	 * parameter if the client secret is an empty string.
44
+	 *
45
+	 * http://tools.ietf.org/html/rfc6749#section-2.2
46
+	 *
47
+	 * @var string
48
+	 */
49
+	protected $clientSecret = '';
50
+
51
+	/**
52
+	 * Access Token Scope
53
+	 *
54
+	 * RFC6749: The authorization and token endpoints allow the client to specify the
55
+	 * scope of the access request using the "scope" request parameter.
56
+	 *
57
+	 * http://tools.ietf.org/html/rfc6749#section-3.3
58
+	 *
59
+	 * @var string
60
+	 */
61
+	protected $scope = '';
62
+
63
+	/**
64
+	 * Base URL to provider API
65
+	 *
66
+	 * This var will be used to build urls when sending signed requests
67
+	 *
68
+	 * @var string
69
+	 */
70
+	protected $apiBaseUrl = '';
71
+
72
+	/**
73
+	 * Authorization Endpoint
74
+	 *
75
+	 * RFC6749: The authorization endpoint is used to interact with the resource
76
+	 * owner and obtain an authorization grant.
77
+	 *
78
+	 * http://tools.ietf.org/html/rfc6749#section-3.1
79
+	 *
80
+	 * @var string
81
+	 */
82
+	protected $authorizeUrl = '';
83
+
84
+	/**
85
+	 * Access Token Endpoint
86
+	 *
87
+	 * RFC6749: The token endpoint is used by the client to obtain an access token by
88
+	 * presenting its authorization grant or refresh token.
89
+	 *
90
+	 * http://tools.ietf.org/html/rfc6749#section-3.2
91
+	 *
92
+	 * @var string
93
+	 */
94
+	protected $accessTokenUrl = '';
95
+
96
+	/**
97
+	 * TokenInfo endpoint
98
+	 *
99
+	 * Access token validation. OPTIONAL.
100
+	 *
101
+	 * @var string
102
+	 */
103
+	protected $accessTokenInfoUrl = '';
104
+
105
+	/**
106
+	 * IPD API Documentation
107
+	 *
108
+	 * OPTIONAL.
109
+	 *
110
+	 * @var string
111
+	 */
112
+	protected $apiDocumentation = '';
113
+
114
+	/**
115
+	 * Redirection Endpoint or Callback
116
+	 *
117
+	 * RFC6749: After completing its interaction with the resource owner, the
118
+	 * authorization server directs the resource owner's user-agent back to
119
+	 * the client.
120
+	 *
121
+	 * http://tools.ietf.org/html/rfc6749#section-3.1.2
122
+	 *
123
+	 * @var string
124
+	 */
125
+	protected $callback = '';
126
+
127
+	/**
128
+	 * Authorization Url Parameters
129
+	 *
130
+	 * @var array
131
+	 */
132
+	protected $AuthorizeUrlParameters = [];
133
+
134
+
135
+	/**
136
+	 * Authorization Url Parameter encoding type
137
+	 * @see https://www.php.net/manual/de/function.http-build-query.php
138
+	 *
139
+	 * @var string
140
+	 */
141
+	protected $AuthorizeUrlParametersEncType = PHP_QUERY_RFC1738;
142
+
143
+	/**
144
+	 * Authorization Request State
145
+	 *
146
+	 * @var bool
147
+	 */
148
+	protected $supportRequestState = true;
149
+
150
+	/**
151
+	 * Access Token name
152
+	 *
153
+	 * While most providers will use 'access_token' as name for the Access Token attribute, other do not.
154
+	 * On the latter case, this should be set by sub classes.
155
+	 *
156
+	 * @var string
157
+	 */
158
+	protected $accessTokenName = 'access_token';
159
+
160
+	/**
161
+	 * Authorization Request HTTP method.
162
+	 *
163
+	 * @see exchangeCodeForAccessToken()
164
+	 *
165
+	 * @var string
166
+	 */
167
+	protected $tokenExchangeMethod = 'POST';
168
+
169
+	/**
170
+	 * Authorization Request URL parameters.
171
+	 *
172
+	 * Sub classes may change add any additional parameter when necessary.
173
+	 *
174
+	 * @see exchangeCodeForAccessToken()
175
+	 *
176
+	 * @var array
177
+	 */
178
+	protected $tokenExchangeParameters = [];
179
+
180
+	/**
181
+	 * Authorization Request HTTP headers.
182
+	 *
183
+	 * Sub classes may add any additional header when necessary.
184
+	 *
185
+	 * @see exchangeCodeForAccessToken()
186
+	 *
187
+	 * @var array
188
+	 */
189
+	protected $tokenExchangeHeaders = [];
190
+
191
+	/**
192
+	 * Refresh Token Request HTTP method.
193
+	 *
194
+	 * @see refreshAccessToken()
195
+	 *
196
+	 * @var string
197
+	 */
198
+	protected $tokenRefreshMethod = 'POST';
199
+
200
+	/**
201
+	 * Refresh Token Request URL parameters.
202
+	 *
203
+	 * Sub classes may change add any additional parameter when necessary.
204
+	 *
205
+	 * @see refreshAccessToken()
206
+	 *
207
+	 * @var array|null
208
+	 */
209
+	protected $tokenRefreshParameters = null;
210
+
211
+	/**
212
+	 * Refresh Token Request HTTP headers.
213
+	 *
214
+	 * Sub classes may add any additional header when necessary.
215
+	 *
216
+	 * @see refreshAccessToken()
217
+	 *
218
+	 * @var array
219
+	 */
220
+	protected $tokenRefreshHeaders = [];
221
+
222
+	/**
223
+	 * Authorization Request URL parameters.
224
+	 *
225
+	 * Sub classes may change add any additional parameter when necessary.
226
+	 *
227
+	 * @see apiRequest()
228
+	 *
229
+	 * @var array
230
+	 */
231
+	protected $apiRequestParameters = [];
232
+
233
+	/**
234
+	 * Authorization Request HTTP headers.
235
+	 *
236
+	 * Sub classes may add any additional header when necessary.
237
+	 *
238
+	 * @see apiRequest()
239
+	 *
240
+	 * @var array
241
+	 */
242
+	protected $apiRequestHeaders = [];
243
+
244
+	/**
245
+	 * {@inheritdoc}
246
+	 */
247
+	protected function configure()
248
+	{
249
+		$this->clientId = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
250
+		$this->clientSecret = $this->config->filter('keys')->get('secret');
251
+
252
+		if (!$this->clientId || !$this->clientSecret) {
253
+			throw new InvalidApplicationCredentialsException(
254
+				'Your application id is required in order to connect to ' . $this->providerId
255
+			);
256
+		}
257
+
258
+		$this->scope = $this->config->exists('scope') ? $this->config->get('scope') : $this->scope;
259
+
260
+		if ($this->config->exists('tokens')) {
261
+			$this->setAccessToken($this->config->get('tokens'));
262
+		}
263 263
         
264
-        if ($this->config->exists('supportRequestState')) {
265
-            $this->supportRequestState = $this->config->get('supportRequestState');
266
-        }
267
-
268
-        $this->setCallback($this->config->get('callback'));
269
-        $this->setApiEndpoints($this->config->get('endpoints'));
270
-    }
271
-
272
-    /**
273
-     * {@inheritdoc}
274
-     */
275
-    protected function initialize()
276
-    {
277
-        $this->AuthorizeUrlParameters = [
278
-            'response_type' => 'code',
279
-            'client_id' => $this->clientId,
280
-            'redirect_uri' => $this->callback,
281
-            'scope' => $this->scope,
282
-        ];
283
-
284
-        $this->tokenExchangeParameters = [
285
-            'client_id' => $this->clientId,
286
-            'client_secret' => $this->clientSecret,
287
-            'grant_type' => 'authorization_code',
288
-            'redirect_uri' => $this->callback
289
-        ];
290
-
291
-        $refreshToken = $this->getStoredData('refresh_token');
292
-        if (!empty($refreshToken)) {
293
-            $this->tokenRefreshParameters = [
294
-                'grant_type' => 'refresh_token',
295
-                'refresh_token' => $refreshToken,
296
-            ];
297
-        }
298
-
299
-        $this->apiRequestHeaders = [
300
-            'Authorization' => 'Bearer ' . $this->getStoredData('access_token')
301
-        ];
302
-    }
303
-
304
-    /**
305
-     * {@inheritdoc}
306
-     */
307
-    public function authenticate()
308
-    {
309
-        $this->logger->info(sprintf('%s::authenticate()', get_class($this)));
310
-
311
-        if ($this->isConnected()) {
312
-            return true;
313
-        }
314
-
315
-        try {
316
-            $this->authenticateCheckError();
317
-
318
-            $code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
319
-
320
-            if (empty($code)) {
321
-                $this->authenticateBegin();
322
-            } else {
323
-                $this->authenticateFinish();
324
-            }
325
-        } catch (Exception $e) {
326
-            $this->clearStoredData();
327
-
328
-            throw $e;
329
-        }
330
-
331
-        return null;
332
-    }
333
-
334
-    /**
335
-     * {@inheritdoc}
336
-     */
337
-    public function isConnected()
338
-    {
339
-        if ((bool)$this->getStoredData('access_token')) {
340
-            return (!$this->hasAccessTokenExpired() || $this->isRefreshTokenAvailable());
341
-        }
342
-        return false;
343
-    }
344
-
345
-    /**
346
-     * If we can use a refresh token, then an expired token does not stop us being connected.
347
-     *
348
-     * @return bool
349
-     */
350
-    public function isRefreshTokenAvailable()
351
-    {
352
-        return is_array($this->tokenRefreshParameters);
353
-    }
354
-
355
-    /**
356
-     * Authorization Request Error Response
357
-     *
358
-     * RFC6749: If the request fails due to a missing, invalid, or mismatching
359
-     * redirection URI, or if the client identifier is missing or invalid,
360
-     * the authorization server SHOULD inform the resource owner of the error.
361
-     *
362
-     * http://tools.ietf.org/html/rfc6749#section-4.1.2.1
363
-     *
364
-     * @throws \Hybridauth\Exception\InvalidAuthorizationCodeException
365
-     * @throws \Hybridauth\Exception\AuthorizationDeniedException
366
-     */
367
-    protected function authenticateCheckError()
368
-    {
369
-        $error = filter_input(INPUT_GET, 'error', FILTER_SANITIZE_SPECIAL_CHARS);
370
-
371
-        if (!empty($error)) {
372
-            $error_description = filter_input(INPUT_GET, 'error_description', FILTER_SANITIZE_SPECIAL_CHARS);
373
-            $error_uri = filter_input(INPUT_GET, 'error_uri', FILTER_SANITIZE_SPECIAL_CHARS);
374
-
375
-            $collated_error = sprintf('Provider returned an error: %s %s %s', $error, $error_description, $error_uri);
376
-
377
-            if ($error == 'access_denied') {
378
-                throw new AuthorizationDeniedException($collated_error);
379
-            }
380
-
381
-            throw new InvalidAuthorizationCodeException($collated_error);
382
-        }
383
-    }
384
-
385
-    /**
386
-     * Initiate the authorization protocol
387
-     *
388
-     * Build Authorization URL for Authorization Request and redirect the user-agent to the
389
-     * Authorization Server.
390
-     */
391
-    protected function authenticateBegin()
392
-    {
393
-        $authUrl = $this->getAuthorizeUrl();
394
-
395
-        $this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);
396
-
397
-        HttpClient\Util::redirect($authUrl);
398
-    }
399
-
400
-    /**
401
-     * Finalize the authorization process
402
-     *
403
-     * @throws \Hybridauth\Exception\HttpClientFailureException
404
-     * @throws \Hybridauth\Exception\HttpRequestFailedException
405
-     * @throws InvalidAccessTokenException
406
-     * @throws InvalidAuthorizationStateException
407
-     */
408
-    protected function authenticateFinish()
409
-    {
410
-        $this->logger->debug(
411
-            sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
412
-            [HttpClient\Util::getCurrentUrl(true)]
413
-        );
414
-
415
-        $state = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'state');
416
-        $code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
417
-
418
-        /**
419
-         * Authorization Request State
420
-         *
421
-         * RFC6749: state : RECOMMENDED. An opaque value used by the client to maintain
422
-         * state between the request and callback. The authorization server includes
423
-         * this value when redirecting the user-agent back to the client.
424
-         *
425
-         * http://tools.ietf.org/html/rfc6749#section-4.1.1
426
-         */
427
-        if ($this->supportRequestState
428
-            && (!$state || $this->getStoredData('authorization_state') != $state)
429
-        ) {
430
-            $this->deleteStoredData('authorization_state');
431
-            throw new InvalidAuthorizationStateException(
432
-                'The authorization state [state=' . substr(htmlentities($state), 0, 100) . '] '
433
-                . 'of this page is either invalid or has already been consumed.'
434
-            );
435
-        }
436
-
437
-        /**
438
-         * Authorization Request Code
439
-         *
440
-         * RFC6749: If the resource owner grants the access request, the authorization
441
-         * server issues an authorization code and delivers it to the client:
442
-         *
443
-         * http://tools.ietf.org/html/rfc6749#section-4.1.2
444
-         */
445
-        $response = $this->exchangeCodeForAccessToken($code);
446
-
447
-        $this->validateAccessTokenExchange($response);
448
-
449
-        $this->initialize();
450
-    }
451
-
452
-    /**
453
-     * Build Authorization URL for Authorization Request
454
-     *
455
-     * RFC6749: The client constructs the request URI by adding the following
456
-     * $parameters to the query component of the authorization endpoint URI:
457
-     *
458
-     *    - response_type  REQUIRED. Value MUST be set to "code".
459
-     *    - client_id      REQUIRED.
460
-     *    - redirect_uri   OPTIONAL.
461
-     *    - scope          OPTIONAL.
462
-     *    - state          RECOMMENDED.
463
-     *
464
-     * http://tools.ietf.org/html/rfc6749#section-4.1.1
465
-     *
466
-     * Sub classes may redefine this method when necessary.
467
-     *
468
-     * @param array $parameters
469
-     *
470
-     * @return string Authorization URL
471
-     */
472
-    protected function getAuthorizeUrl($parameters = [])
473
-    {
474
-        $this->AuthorizeUrlParameters = !empty($parameters)
475
-            ? $parameters
476
-            : array_replace(
477
-                (array)$this->AuthorizeUrlParameters,
478
-                (array)$this->config->get('authorize_url_parameters')
479
-            );
480
-
481
-        if ($this->supportRequestState) {
482
-            if (!isset($this->AuthorizeUrlParameters['state'])) {
483
-                $this->AuthorizeUrlParameters['state'] = 'HA-' . str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
484
-            }
485
-
486
-            $this->storeData('authorization_state', $this->AuthorizeUrlParameters['state']);
487
-        }
488
-
489
-        $queryParams = http_build_query($this->AuthorizeUrlParameters, '', '&', $this->AuthorizeUrlParametersEncType);
490
-        return $this->authorizeUrl . '?' . $queryParams;
491
-    }
492
-
493
-    /**
494
-     * Access Token Request
495
-     *
496
-     * This method will exchange the received $code in loginFinish() with an Access Token.
497
-     *
498
-     * RFC6749: The client makes a request to the token endpoint by sending the
499
-     * following parameters using the "application/x-www-form-urlencoded"
500
-     * with a character encoding of UTF-8 in the HTTP request entity-body:
501
-     *
502
-     *    - grant_type    REQUIRED. Value MUST be set to "authorization_code".
503
-     *    - code          REQUIRED. The authorization code received from the authorization server.
504
-     *    - redirect_uri  REQUIRED.
505
-     *    - client_id     REQUIRED.
506
-     *
507
-     * http://tools.ietf.org/html/rfc6749#section-4.1.3
508
-     *
509
-     * @param string $code
510
-     *
511
-     * @return string Raw Provider API response
512
-     * @throws \Hybridauth\Exception\HttpClientFailureException
513
-     * @throws \Hybridauth\Exception\HttpRequestFailedException
514
-     */
515
-    protected function exchangeCodeForAccessToken($code)
516
-    {
517
-        $this->tokenExchangeParameters['code'] = $code;
518
-
519
-        $response = $this->httpClient->request(
520
-            $this->accessTokenUrl,
521
-            $this->tokenExchangeMethod,
522
-            $this->tokenExchangeParameters,
523
-            $this->tokenExchangeHeaders
524
-        );
525
-
526
-        $this->validateApiResponse('Unable to exchange code for API access token');
527
-
528
-        return $response;
529
-    }
530
-
531
-    /**
532
-     * Validate Access Token Response
533
-     *
534
-     * RFC6749: If the access token request is valid and authorized, the
535
-     * authorization server issues an access token and optional refresh token.
536
-     * If the request client authentication failed or is invalid, the authorization
537
-     * server returns an error response as described in Section 5.2.
538
-     *
539
-     * Example of a successful response:
540
-     *
541
-     *  HTTP/1.1 200 OK
542
-     *  Content-Type: application/json;charset=UTF-8
543
-     *  Cache-Control: no-store
544
-     *  Pragma: no-cache
545
-     *
546
-     *  {
547
-     *      "access_token":"2YotnFZFEjr1zCsicMWpAA",
548
-     *      "token_type":"example",
549
-     *      "expires_in":3600,
550
-     *      "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
551
-     *      "example_parameter":"example_value"
552
-     *  }
553
-     *
554
-     * http://tools.ietf.org/html/rfc6749#section-4.1.4
555
-     *
556
-     * This method uses Data_Parser to attempt to decodes the raw $response (usually JSON)
557
-     * into a data collection.
558
-     *
559
-     * @param string $response
560
-     *
561
-     * @return \Hybridauth\Data\Collection
562
-     * @throws InvalidAccessTokenException
563
-     */
564
-    protected function validateAccessTokenExchange($response)
565
-    {
566
-        $data = (new Data\Parser())->parse($response);
567
-
568
-        $collection = new Data\Collection($data);
569
-
570
-        if (!$collection->exists('access_token')) {
571
-            throw new InvalidAccessTokenException(
572
-                'Provider returned no access_token: ' . htmlentities($response)
573
-            );
574
-        }
575
-
576
-        $this->storeData('access_token', $collection->get('access_token'));
577
-        $this->storeData('token_type', $collection->get('token_type'));
578
-
579
-        if ($collection->get('refresh_token')) {
580
-            $this->storeData('refresh_token', $collection->get('refresh_token'));
581
-        }
582
-
583
-        // calculate when the access token expire
584
-        if ($collection->exists('expires_in')) {
585
-            $expires_at = time() + (int)$collection->get('expires_in');
586
-
587
-            $this->storeData('expires_in', $collection->get('expires_in'));
588
-            $this->storeData('expires_at', $expires_at);
589
-        }
590
-
591
-        $this->deleteStoredData('authorization_state');
592
-
593
-        $this->initialize();
594
-
595
-        return $collection;
596
-    }
597
-
598
-    /**
599
-     * Refreshing an Access Token
600
-     *
601
-     * RFC6749: If the authorization server issued a refresh token to the
602
-     * client, the client makes a refresh request to the token endpoint by
603
-     * adding the following parameters ... in the HTTP request entity-body:
604
-     *
605
-     *    - grant_type     REQUIRED. Value MUST be set to "refresh_token".
606
-     *    - refresh_token  REQUIRED. The refresh token issued to the client.
607
-     *    - scope          OPTIONAL.
608
-     *
609
-     * http://tools.ietf.org/html/rfc6749#section-6
610
-     *
611
-     * This method is similar to exchangeCodeForAccessToken(). The only
612
-     * difference is here we exchange refresh_token for a new access_token.
613
-     *
614
-     * @param array $parameters
615
-     *
616
-     * @return string|null Raw Provider API response, or null if we cannot refresh
617
-     * @throws \Hybridauth\Exception\HttpClientFailureException
618
-     * @throws \Hybridauth\Exception\HttpRequestFailedException
619
-     * @throws InvalidAccessTokenException
620
-     */
621
-    public function refreshAccessToken($parameters = [])
622
-    {
623
-        $this->tokenRefreshParameters = !empty($parameters)
624
-            ? $parameters
625
-            : $this->tokenRefreshParameters;
626
-
627
-        if (!$this->isRefreshTokenAvailable()) {
628
-            return null;
629
-        }
630
-
631
-        $response = $this->httpClient->request(
632
-            $this->accessTokenUrl,
633
-            $this->tokenRefreshMethod,
634
-            $this->tokenRefreshParameters,
635
-            $this->tokenRefreshHeaders
636
-        );
637
-
638
-        $this->validateApiResponse('Unable to refresh the access token');
639
-
640
-        $this->validateRefreshAccessToken($response);
641
-
642
-        return $response;
643
-    }
644
-
645
-    /**
646
-     * Check whether access token has expired
647
-     *
648
-     * @param int|null $time
649
-     * @return bool|null
650
-     */
651
-    public function hasAccessTokenExpired($time = null)
652
-    {
653
-        if ($time === null) {
654
-            $time = time();
655
-        }
656
-
657
-        $expires_at = $this->getStoredData('expires_at');
658
-        if (!$expires_at) {
659
-            return null;
660
-        }
661
-
662
-        return $expires_at <= $time;
663
-    }
664
-
665
-    /**
666
-     * Validate Refresh Access Token Request
667
-     *
668
-     * RFC6749: If valid and authorized, the authorization server issues an
669
-     * access token as described in Section 5.1.  If the request failed
670
-     * verification or is invalid, the authorization server returns an error
671
-     * response as described in Section 5.2.
672
-     *
673
-     * http://tools.ietf.org/html/rfc6749#section-6
674
-     * http://tools.ietf.org/html/rfc6749#section-5.1
675
-     * http://tools.ietf.org/html/rfc6749#section-5.2
676
-     *
677
-     * This method simply use validateAccessTokenExchange(), however sub
678
-     * classes may redefine it when necessary.
679
-     *
680
-     * @param $response
681
-     *
682
-     * @return \Hybridauth\Data\Collection
683
-     * @throws InvalidAccessTokenException
684
-     */
685
-    protected function validateRefreshAccessToken($response)
686
-    {
687
-        return $this->validateAccessTokenExchange($response);
688
-    }
689
-
690
-    /**
691
-     * Send a signed request to provider API
692
-     *
693
-     * RFC6749: Accessing Protected Resources: The client accesses protected
694
-     * resources by presenting the access token to the resource server. The
695
-     * resource server MUST validate the access token and ensure that it has
696
-     * not expired and that its scope covers the requested resource.
697
-     *
698
-     * Note: Since the specifics of error responses is beyond the scope of
699
-     * RFC6749 and OAuth specifications, Hybridauth will consider any HTTP
700
-     * status code that is different than '200 OK' as an ERROR.
701
-     *
702
-     * http://tools.ietf.org/html/rfc6749#section-7
703
-     *
704
-     * @param string $url
705
-     * @param string $method
706
-     * @param array $parameters
707
-     * @param array $headers
708
-     * @param bool $multipart
709
-     *
710
-     * @return mixed
711
-     * @throws \Hybridauth\Exception\HttpClientFailureException
712
-     * @throws \Hybridauth\Exception\HttpRequestFailedException
713
-     * @throws InvalidAccessTokenException
714
-     */
715
-    public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
716
-    {
717
-        // refresh tokens if needed
718
-        $this->maintainToken();
719
-        if ($this->hasAccessTokenExpired() === true) {
720
-            $this->refreshAccessToken();
721
-        }
722
-
723
-        if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
724
-            $url = rtrim($this->apiBaseUrl, '/') . '/' . ltrim($url, '/');
725
-        }
726
-
727
-        $parameters = array_replace($this->apiRequestParameters, (array)$parameters);
728
-        $headers = array_replace($this->apiRequestHeaders, (array)$headers);
729
-
730
-        $response = $this->httpClient->request(
731
-            $url,
732
-            $method,     // HTTP Request Method. Defaults to GET.
733
-            $parameters, // Request Parameters
734
-            $headers,    // Request Headers
735
-            $multipart   // Is request multipart
736
-        );
737
-
738
-        $this->validateApiResponse('Signed API request to ' . $url . ' has returned an error');
739
-
740
-        $response = (new Data\Parser())->parse($response);
741
-
742
-        return $response;
743
-    }
264
+		if ($this->config->exists('supportRequestState')) {
265
+			$this->supportRequestState = $this->config->get('supportRequestState');
266
+		}
267
+
268
+		$this->setCallback($this->config->get('callback'));
269
+		$this->setApiEndpoints($this->config->get('endpoints'));
270
+	}
271
+
272
+	/**
273
+	 * {@inheritdoc}
274
+	 */
275
+	protected function initialize()
276
+	{
277
+		$this->AuthorizeUrlParameters = [
278
+			'response_type' => 'code',
279
+			'client_id' => $this->clientId,
280
+			'redirect_uri' => $this->callback,
281
+			'scope' => $this->scope,
282
+		];
283
+
284
+		$this->tokenExchangeParameters = [
285
+			'client_id' => $this->clientId,
286
+			'client_secret' => $this->clientSecret,
287
+			'grant_type' => 'authorization_code',
288
+			'redirect_uri' => $this->callback
289
+		];
290
+
291
+		$refreshToken = $this->getStoredData('refresh_token');
292
+		if (!empty($refreshToken)) {
293
+			$this->tokenRefreshParameters = [
294
+				'grant_type' => 'refresh_token',
295
+				'refresh_token' => $refreshToken,
296
+			];
297
+		}
298
+
299
+		$this->apiRequestHeaders = [
300
+			'Authorization' => 'Bearer ' . $this->getStoredData('access_token')
301
+		];
302
+	}
303
+
304
+	/**
305
+	 * {@inheritdoc}
306
+	 */
307
+	public function authenticate()
308
+	{
309
+		$this->logger->info(sprintf('%s::authenticate()', get_class($this)));
310
+
311
+		if ($this->isConnected()) {
312
+			return true;
313
+		}
314
+
315
+		try {
316
+			$this->authenticateCheckError();
317
+
318
+			$code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
319
+
320
+			if (empty($code)) {
321
+				$this->authenticateBegin();
322
+			} else {
323
+				$this->authenticateFinish();
324
+			}
325
+		} catch (Exception $e) {
326
+			$this->clearStoredData();
327
+
328
+			throw $e;
329
+		}
330
+
331
+		return null;
332
+	}
333
+
334
+	/**
335
+	 * {@inheritdoc}
336
+	 */
337
+	public function isConnected()
338
+	{
339
+		if ((bool)$this->getStoredData('access_token')) {
340
+			return (!$this->hasAccessTokenExpired() || $this->isRefreshTokenAvailable());
341
+		}
342
+		return false;
343
+	}
344
+
345
+	/**
346
+	 * If we can use a refresh token, then an expired token does not stop us being connected.
347
+	 *
348
+	 * @return bool
349
+	 */
350
+	public function isRefreshTokenAvailable()
351
+	{
352
+		return is_array($this->tokenRefreshParameters);
353
+	}
354
+
355
+	/**
356
+	 * Authorization Request Error Response
357
+	 *
358
+	 * RFC6749: If the request fails due to a missing, invalid, or mismatching
359
+	 * redirection URI, or if the client identifier is missing or invalid,
360
+	 * the authorization server SHOULD inform the resource owner of the error.
361
+	 *
362
+	 * http://tools.ietf.org/html/rfc6749#section-4.1.2.1
363
+	 *
364
+	 * @throws \Hybridauth\Exception\InvalidAuthorizationCodeException
365
+	 * @throws \Hybridauth\Exception\AuthorizationDeniedException
366
+	 */
367
+	protected function authenticateCheckError()
368
+	{
369
+		$error = filter_input(INPUT_GET, 'error', FILTER_SANITIZE_SPECIAL_CHARS);
370
+
371
+		if (!empty($error)) {
372
+			$error_description = filter_input(INPUT_GET, 'error_description', FILTER_SANITIZE_SPECIAL_CHARS);
373
+			$error_uri = filter_input(INPUT_GET, 'error_uri', FILTER_SANITIZE_SPECIAL_CHARS);
374
+
375
+			$collated_error = sprintf('Provider returned an error: %s %s %s', $error, $error_description, $error_uri);
376
+
377
+			if ($error == 'access_denied') {
378
+				throw new AuthorizationDeniedException($collated_error);
379
+			}
380
+
381
+			throw new InvalidAuthorizationCodeException($collated_error);
382
+		}
383
+	}
384
+
385
+	/**
386
+	 * Initiate the authorization protocol
387
+	 *
388
+	 * Build Authorization URL for Authorization Request and redirect the user-agent to the
389
+	 * Authorization Server.
390
+	 */
391
+	protected function authenticateBegin()
392
+	{
393
+		$authUrl = $this->getAuthorizeUrl();
394
+
395
+		$this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);
396
+
397
+		HttpClient\Util::redirect($authUrl);
398
+	}
399
+
400
+	/**
401
+	 * Finalize the authorization process
402
+	 *
403
+	 * @throws \Hybridauth\Exception\HttpClientFailureException
404
+	 * @throws \Hybridauth\Exception\HttpRequestFailedException
405
+	 * @throws InvalidAccessTokenException
406
+	 * @throws InvalidAuthorizationStateException
407
+	 */
408
+	protected function authenticateFinish()
409
+	{
410
+		$this->logger->debug(
411
+			sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
412
+			[HttpClient\Util::getCurrentUrl(true)]
413
+		);
414
+
415
+		$state = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'state');
416
+		$code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
417
+
418
+		/**
419
+		 * Authorization Request State
420
+		 *
421
+		 * RFC6749: state : RECOMMENDED. An opaque value used by the client to maintain
422
+		 * state between the request and callback. The authorization server includes
423
+		 * this value when redirecting the user-agent back to the client.
424
+		 *
425
+		 * http://tools.ietf.org/html/rfc6749#section-4.1.1
426
+		 */
427
+		if ($this->supportRequestState
428
+			&& (!$state || $this->getStoredData('authorization_state') != $state)
429
+		) {
430
+			$this->deleteStoredData('authorization_state');
431
+			throw new InvalidAuthorizationStateException(
432
+				'The authorization state [state=' . substr(htmlentities($state), 0, 100) . '] '
433
+				. 'of this page is either invalid or has already been consumed.'
434
+			);
435
+		}
436
+
437
+		/**
438
+		 * Authorization Request Code
439
+		 *
440
+		 * RFC6749: If the resource owner grants the access request, the authorization
441
+		 * server issues an authorization code and delivers it to the client:
442
+		 *
443
+		 * http://tools.ietf.org/html/rfc6749#section-4.1.2
444
+		 */
445
+		$response = $this->exchangeCodeForAccessToken($code);
446
+
447
+		$this->validateAccessTokenExchange($response);
448
+
449
+		$this->initialize();
450
+	}
451
+
452
+	/**
453
+	 * Build Authorization URL for Authorization Request
454
+	 *
455
+	 * RFC6749: The client constructs the request URI by adding the following
456
+	 * $parameters to the query component of the authorization endpoint URI:
457
+	 *
458
+	 *    - response_type  REQUIRED. Value MUST be set to "code".
459
+	 *    - client_id      REQUIRED.
460
+	 *    - redirect_uri   OPTIONAL.
461
+	 *    - scope          OPTIONAL.
462
+	 *    - state          RECOMMENDED.
463
+	 *
464
+	 * http://tools.ietf.org/html/rfc6749#section-4.1.1
465
+	 *
466
+	 * Sub classes may redefine this method when necessary.
467
+	 *
468
+	 * @param array $parameters
469
+	 *
470
+	 * @return string Authorization URL
471
+	 */
472
+	protected function getAuthorizeUrl($parameters = [])
473
+	{
474
+		$this->AuthorizeUrlParameters = !empty($parameters)
475
+			? $parameters
476
+			: array_replace(
477
+				(array)$this->AuthorizeUrlParameters,
478
+				(array)$this->config->get('authorize_url_parameters')
479
+			);
480
+
481
+		if ($this->supportRequestState) {
482
+			if (!isset($this->AuthorizeUrlParameters['state'])) {
483
+				$this->AuthorizeUrlParameters['state'] = 'HA-' . str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
484
+			}
485
+
486
+			$this->storeData('authorization_state', $this->AuthorizeUrlParameters['state']);
487
+		}
488
+
489
+		$queryParams = http_build_query($this->AuthorizeUrlParameters, '', '&', $this->AuthorizeUrlParametersEncType);
490
+		return $this->authorizeUrl . '?' . $queryParams;
491
+	}
492
+
493
+	/**
494
+	 * Access Token Request
495
+	 *
496
+	 * This method will exchange the received $code in loginFinish() with an Access Token.
497
+	 *
498
+	 * RFC6749: The client makes a request to the token endpoint by sending the
499
+	 * following parameters using the "application/x-www-form-urlencoded"
500
+	 * with a character encoding of UTF-8 in the HTTP request entity-body:
501
+	 *
502
+	 *    - grant_type    REQUIRED. Value MUST be set to "authorization_code".
503
+	 *    - code          REQUIRED. The authorization code received from the authorization server.
504
+	 *    - redirect_uri  REQUIRED.
505
+	 *    - client_id     REQUIRED.
506
+	 *
507
+	 * http://tools.ietf.org/html/rfc6749#section-4.1.3
508
+	 *
509
+	 * @param string $code
510
+	 *
511
+	 * @return string Raw Provider API response
512
+	 * @throws \Hybridauth\Exception\HttpClientFailureException
513
+	 * @throws \Hybridauth\Exception\HttpRequestFailedException
514
+	 */
515
+	protected function exchangeCodeForAccessToken($code)
516
+	{
517
+		$this->tokenExchangeParameters['code'] = $code;
518
+
519
+		$response = $this->httpClient->request(
520
+			$this->accessTokenUrl,
521
+			$this->tokenExchangeMethod,
522
+			$this->tokenExchangeParameters,
523
+			$this->tokenExchangeHeaders
524
+		);
525
+
526
+		$this->validateApiResponse('Unable to exchange code for API access token');
527
+
528
+		return $response;
529
+	}
530
+
531
+	/**
532
+	 * Validate Access Token Response
533
+	 *
534
+	 * RFC6749: If the access token request is valid and authorized, the
535
+	 * authorization server issues an access token and optional refresh token.
536
+	 * If the request client authentication failed or is invalid, the authorization
537
+	 * server returns an error response as described in Section 5.2.
538
+	 *
539
+	 * Example of a successful response:
540
+	 *
541
+	 *  HTTP/1.1 200 OK
542
+	 *  Content-Type: application/json;charset=UTF-8
543
+	 *  Cache-Control: no-store
544
+	 *  Pragma: no-cache
545
+	 *
546
+	 *  {
547
+	 *      "access_token":"2YotnFZFEjr1zCsicMWpAA",
548
+	 *      "token_type":"example",
549
+	 *      "expires_in":3600,
550
+	 *      "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
551
+	 *      "example_parameter":"example_value"
552
+	 *  }
553
+	 *
554
+	 * http://tools.ietf.org/html/rfc6749#section-4.1.4
555
+	 *
556
+	 * This method uses Data_Parser to attempt to decodes the raw $response (usually JSON)
557
+	 * into a data collection.
558
+	 *
559
+	 * @param string $response
560
+	 *
561
+	 * @return \Hybridauth\Data\Collection
562
+	 * @throws InvalidAccessTokenException
563
+	 */
564
+	protected function validateAccessTokenExchange($response)
565
+	{
566
+		$data = (new Data\Parser())->parse($response);
567
+
568
+		$collection = new Data\Collection($data);
569
+
570
+		if (!$collection->exists('access_token')) {
571
+			throw new InvalidAccessTokenException(
572
+				'Provider returned no access_token: ' . htmlentities($response)
573
+			);
574
+		}
575
+
576
+		$this->storeData('access_token', $collection->get('access_token'));
577
+		$this->storeData('token_type', $collection->get('token_type'));
578
+
579
+		if ($collection->get('refresh_token')) {
580
+			$this->storeData('refresh_token', $collection->get('refresh_token'));
581
+		}
582
+
583
+		// calculate when the access token expire
584
+		if ($collection->exists('expires_in')) {
585
+			$expires_at = time() + (int)$collection->get('expires_in');
586
+
587
+			$this->storeData('expires_in', $collection->get('expires_in'));
588
+			$this->storeData('expires_at', $expires_at);
589
+		}
590
+
591
+		$this->deleteStoredData('authorization_state');
592
+
593
+		$this->initialize();
594
+
595
+		return $collection;
596
+	}
597
+
598
+	/**
599
+	 * Refreshing an Access Token
600
+	 *
601
+	 * RFC6749: If the authorization server issued a refresh token to the
602
+	 * client, the client makes a refresh request to the token endpoint by
603
+	 * adding the following parameters ... in the HTTP request entity-body:
604
+	 *
605
+	 *    - grant_type     REQUIRED. Value MUST be set to "refresh_token".
606
+	 *    - refresh_token  REQUIRED. The refresh token issued to the client.
607
+	 *    - scope          OPTIONAL.
608
+	 *
609
+	 * http://tools.ietf.org/html/rfc6749#section-6
610
+	 *
611
+	 * This method is similar to exchangeCodeForAccessToken(). The only
612
+	 * difference is here we exchange refresh_token for a new access_token.
613
+	 *
614
+	 * @param array $parameters
615
+	 *
616
+	 * @return string|null Raw Provider API response, or null if we cannot refresh
617
+	 * @throws \Hybridauth\Exception\HttpClientFailureException
618
+	 * @throws \Hybridauth\Exception\HttpRequestFailedException
619
+	 * @throws InvalidAccessTokenException
620
+	 */
621
+	public function refreshAccessToken($parameters = [])
622
+	{
623
+		$this->tokenRefreshParameters = !empty($parameters)
624
+			? $parameters
625
+			: $this->tokenRefreshParameters;
626
+
627
+		if (!$this->isRefreshTokenAvailable()) {
628
+			return null;
629
+		}
630
+
631
+		$response = $this->httpClient->request(
632
+			$this->accessTokenUrl,
633
+			$this->tokenRefreshMethod,
634
+			$this->tokenRefreshParameters,
635
+			$this->tokenRefreshHeaders
636
+		);
637
+
638
+		$this->validateApiResponse('Unable to refresh the access token');
639
+
640
+		$this->validateRefreshAccessToken($response);
641
+
642
+		return $response;
643
+	}
644
+
645
+	/**
646
+	 * Check whether access token has expired
647
+	 *
648
+	 * @param int|null $time
649
+	 * @return bool|null
650
+	 */
651
+	public function hasAccessTokenExpired($time = null)
652
+	{
653
+		if ($time === null) {
654
+			$time = time();
655
+		}
656
+
657
+		$expires_at = $this->getStoredData('expires_at');
658
+		if (!$expires_at) {
659
+			return null;
660
+		}
661
+
662
+		return $expires_at <= $time;
663
+	}
664
+
665
+	/**
666
+	 * Validate Refresh Access Token Request
667
+	 *
668
+	 * RFC6749: If valid and authorized, the authorization server issues an
669
+	 * access token as described in Section 5.1.  If the request failed
670
+	 * verification or is invalid, the authorization server returns an error
671
+	 * response as described in Section 5.2.
672
+	 *
673
+	 * http://tools.ietf.org/html/rfc6749#section-6
674
+	 * http://tools.ietf.org/html/rfc6749#section-5.1
675
+	 * http://tools.ietf.org/html/rfc6749#section-5.2
676
+	 *
677
+	 * This method simply use validateAccessTokenExchange(), however sub
678
+	 * classes may redefine it when necessary.
679
+	 *
680
+	 * @param $response
681
+	 *
682
+	 * @return \Hybridauth\Data\Collection
683
+	 * @throws InvalidAccessTokenException
684
+	 */
685
+	protected function validateRefreshAccessToken($response)
686
+	{
687
+		return $this->validateAccessTokenExchange($response);
688
+	}
689
+
690
+	/**
691
+	 * Send a signed request to provider API
692
+	 *
693
+	 * RFC6749: Accessing Protected Resources: The client accesses protected
694
+	 * resources by presenting the access token to the resource server. The
695
+	 * resource server MUST validate the access token and ensure that it has
696
+	 * not expired and that its scope covers the requested resource.
697
+	 *
698
+	 * Note: Since the specifics of error responses is beyond the scope of
699
+	 * RFC6749 and OAuth specifications, Hybridauth will consider any HTTP
700
+	 * status code that is different than '200 OK' as an ERROR.
701
+	 *
702
+	 * http://tools.ietf.org/html/rfc6749#section-7
703
+	 *
704
+	 * @param string $url
705
+	 * @param string $method
706
+	 * @param array $parameters
707
+	 * @param array $headers
708
+	 * @param bool $multipart
709
+	 *
710
+	 * @return mixed
711
+	 * @throws \Hybridauth\Exception\HttpClientFailureException
712
+	 * @throws \Hybridauth\Exception\HttpRequestFailedException
713
+	 * @throws InvalidAccessTokenException
714
+	 */
715
+	public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
716
+	{
717
+		// refresh tokens if needed
718
+		$this->maintainToken();
719
+		if ($this->hasAccessTokenExpired() === true) {
720
+			$this->refreshAccessToken();
721
+		}
722
+
723
+		if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
724
+			$url = rtrim($this->apiBaseUrl, '/') . '/' . ltrim($url, '/');
725
+		}
726
+
727
+		$parameters = array_replace($this->apiRequestParameters, (array)$parameters);
728
+		$headers = array_replace($this->apiRequestHeaders, (array)$headers);
729
+
730
+		$response = $this->httpClient->request(
731
+			$url,
732
+			$method,     // HTTP Request Method. Defaults to GET.
733
+			$parameters, // Request Parameters
734
+			$headers,    // Request Headers
735
+			$multipart   // Is request multipart
736
+		);
737
+
738
+		$this->validateApiResponse('Signed API request to ' . $url . ' has returned an error');
739
+
740
+		$response = (new Data\Parser())->parse($response);
741
+
742
+		return $response;
743
+	}
744 744
 }
Please login to merge, or discard this patch.
Spacing   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -249,9 +249,9 @@  discard block
 block discarded – undo
249 249
         $this->clientId = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
250 250
         $this->clientSecret = $this->config->filter('keys')->get('secret');
251 251
 
252
-        if (!$this->clientId || !$this->clientSecret) {
252
+        if ( ! $this->clientId || ! $this->clientSecret) {
253 253
             throw new InvalidApplicationCredentialsException(
254
-                'Your application id is required in order to connect to ' . $this->providerId
254
+                'Your application id is required in order to connect to '.$this->providerId
255 255
             );
256 256
         }
257 257
 
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
         ];
290 290
 
291 291
         $refreshToken = $this->getStoredData('refresh_token');
292
-        if (!empty($refreshToken)) {
292
+        if ( ! empty($refreshToken)) {
293 293
             $this->tokenRefreshParameters = [
294 294
                 'grant_type' => 'refresh_token',
295 295
                 'refresh_token' => $refreshToken,
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
         }
298 298
 
299 299
         $this->apiRequestHeaders = [
300
-            'Authorization' => 'Bearer ' . $this->getStoredData('access_token')
300
+            'Authorization' => 'Bearer '.$this->getStoredData('access_token')
301 301
         ];
302 302
     }
303 303
 
@@ -336,8 +336,8 @@  discard block
 block discarded – undo
336 336
      */
337 337
     public function isConnected()
338 338
     {
339
-        if ((bool)$this->getStoredData('access_token')) {
340
-            return (!$this->hasAccessTokenExpired() || $this->isRefreshTokenAvailable());
339
+        if ((bool) $this->getStoredData('access_token')) {
340
+            return ( ! $this->hasAccessTokenExpired() || $this->isRefreshTokenAvailable());
341 341
         }
342 342
         return false;
343 343
     }
@@ -368,7 +368,7 @@  discard block
 block discarded – undo
368 368
     {
369 369
         $error = filter_input(INPUT_GET, 'error', FILTER_SANITIZE_SPECIAL_CHARS);
370 370
 
371
-        if (!empty($error)) {
371
+        if ( ! empty($error)) {
372 372
             $error_description = filter_input(INPUT_GET, 'error_description', FILTER_SANITIZE_SPECIAL_CHARS);
373 373
             $error_uri = filter_input(INPUT_GET, 'error_uri', FILTER_SANITIZE_SPECIAL_CHARS);
374 374
 
@@ -425,11 +425,11 @@  discard block
 block discarded – undo
425 425
          * http://tools.ietf.org/html/rfc6749#section-4.1.1
426 426
          */
427 427
         if ($this->supportRequestState
428
-            && (!$state || $this->getStoredData('authorization_state') != $state)
428
+            && ( ! $state || $this->getStoredData('authorization_state') != $state)
429 429
         ) {
430 430
             $this->deleteStoredData('authorization_state');
431 431
             throw new InvalidAuthorizationStateException(
432
-                'The authorization state [state=' . substr(htmlentities($state), 0, 100) . '] '
432
+                'The authorization state [state='.substr(htmlentities($state), 0, 100).'] '
433 433
                 . 'of this page is either invalid or has already been consumed.'
434 434
             );
435 435
         }
@@ -471,23 +471,23 @@  discard block
 block discarded – undo
471 471
      */
472 472
     protected function getAuthorizeUrl($parameters = [])
473 473
     {
474
-        $this->AuthorizeUrlParameters = !empty($parameters)
474
+        $this->AuthorizeUrlParameters = ! empty($parameters)
475 475
             ? $parameters
476 476
             : array_replace(
477
-                (array)$this->AuthorizeUrlParameters,
478
-                (array)$this->config->get('authorize_url_parameters')
477
+                (array) $this->AuthorizeUrlParameters,
478
+                (array) $this->config->get('authorize_url_parameters')
479 479
             );
480 480
 
481 481
         if ($this->supportRequestState) {
482
-            if (!isset($this->AuthorizeUrlParameters['state'])) {
483
-                $this->AuthorizeUrlParameters['state'] = 'HA-' . str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
482
+            if ( ! isset($this->AuthorizeUrlParameters['state'])) {
483
+                $this->AuthorizeUrlParameters['state'] = 'HA-'.str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
484 484
             }
485 485
 
486 486
             $this->storeData('authorization_state', $this->AuthorizeUrlParameters['state']);
487 487
         }
488 488
 
489 489
         $queryParams = http_build_query($this->AuthorizeUrlParameters, '', '&', $this->AuthorizeUrlParametersEncType);
490
-        return $this->authorizeUrl . '?' . $queryParams;
490
+        return $this->authorizeUrl.'?'.$queryParams;
491 491
     }
492 492
 
493 493
     /**
@@ -567,9 +567,9 @@  discard block
 block discarded – undo
567 567
 
568 568
         $collection = new Data\Collection($data);
569 569
 
570
-        if (!$collection->exists('access_token')) {
570
+        if ( ! $collection->exists('access_token')) {
571 571
             throw new InvalidAccessTokenException(
572
-                'Provider returned no access_token: ' . htmlentities($response)
572
+                'Provider returned no access_token: '.htmlentities($response)
573 573
             );
574 574
         }
575 575
 
@@ -582,7 +582,7 @@  discard block
 block discarded – undo
582 582
 
583 583
         // calculate when the access token expire
584 584
         if ($collection->exists('expires_in')) {
585
-            $expires_at = time() + (int)$collection->get('expires_in');
585
+            $expires_at = time() + (int) $collection->get('expires_in');
586 586
 
587 587
             $this->storeData('expires_in', $collection->get('expires_in'));
588 588
             $this->storeData('expires_at', $expires_at);
@@ -620,11 +620,11 @@  discard block
 block discarded – undo
620 620
      */
621 621
     public function refreshAccessToken($parameters = [])
622 622
     {
623
-        $this->tokenRefreshParameters = !empty($parameters)
623
+        $this->tokenRefreshParameters = ! empty($parameters)
624 624
             ? $parameters
625 625
             : $this->tokenRefreshParameters;
626 626
 
627
-        if (!$this->isRefreshTokenAvailable()) {
627
+        if ( ! $this->isRefreshTokenAvailable()) {
628 628
             return null;
629 629
         }
630 630
 
@@ -655,7 +655,7 @@  discard block
 block discarded – undo
655 655
         }
656 656
 
657 657
         $expires_at = $this->getStoredData('expires_at');
658
-        if (!$expires_at) {
658
+        if ( ! $expires_at) {
659 659
             return null;
660 660
         }
661 661
 
@@ -721,21 +721,21 @@  discard block
 block discarded – undo
721 721
         }
722 722
 
723 723
         if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
724
-            $url = rtrim($this->apiBaseUrl, '/') . '/' . ltrim($url, '/');
724
+            $url = rtrim($this->apiBaseUrl, '/').'/'.ltrim($url, '/');
725 725
         }
726 726
 
727
-        $parameters = array_replace($this->apiRequestParameters, (array)$parameters);
728
-        $headers = array_replace($this->apiRequestHeaders, (array)$headers);
727
+        $parameters = array_replace($this->apiRequestParameters, (array) $parameters);
728
+        $headers = array_replace($this->apiRequestHeaders, (array) $headers);
729 729
 
730 730
         $response = $this->httpClient->request(
731 731
             $url,
732
-            $method,     // HTTP Request Method. Defaults to GET.
732
+            $method, // HTTP Request Method. Defaults to GET.
733 733
             $parameters, // Request Parameters
734
-            $headers,    // Request Headers
734
+            $headers, // Request Headers
735 735
             $multipart   // Is request multipart
736 736
         );
737 737
 
738
-        $this->validateApiResponse('Signed API request to ' . $url . ' has returned an error');
738
+        $this->validateApiResponse('Signed API request to '.$url.' has returned an error');
739 739
 
740 740
         $response = (new Data\Parser())->parse($response);
741 741
 
Please login to merge, or discard this patch.