Passed
Pull Request — develop (#941)
by Shandak
07:32
created

RApiOauth2Oauth2   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 586
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 55
eloc 230
c 3
b 0
f 0
dl 0
loc 586
rs 6

13 Methods

Rating   Name   Duplication   Size   Complexity  
A apiProfile() 0 30 3
A loadUserIdentity() 0 12 2
B apiResource() 0 60 10
A cleanExpiredTokens() 0 32 3
B __construct() 0 96 5
A setApiOperation() 0 10 2
A execute() 0 26 6
A apiToken() 0 25 4
A prepareBody() 0 3 1
A isOperationAllowed() 0 8 2
A getLoggedUser() 0 20 2
C apiAuthorize() 0 91 12
A render() 0 25 3

How to fix   Complexity   

Complex Class

Complex classes like RApiOauth2Oauth2 often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RApiOauth2Oauth2, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package     Redcore
4
 * @subpackage  Api
5
 *
6
 * @copyright   Copyright (C) 2008 - 2021 redWEB.dk. All rights reserved.
7
 * @license     GNU General Public License version 2 or later, see LICENSE.
8
 */
9
10
defined('JPATH_REDCORE') or die;
11
12
/**
13
 * Class to represent a HAL standard object.
14
 *
15
 * @since  1.2
16
 */
17
class RApiOauth2Oauth2 extends RApi
18
{
19
	/**
20
	 * Option name parameter
21
	 * @var array
22
	 */
23
	public $optionName = null;
24
25
	/**
26
	 * Main OAuth2 Server object
27
	 * @var OAuth2\Server
28
	 */
29
	public $server = null;
30
31
	/**
32
	 * Main OAuth2 Server configuration
33
	 * @var array
34
	 */
35
	public $serverConfig = null;
36
37
	/**
38
	 * Result of OAuth2 Server response
39
	 * @var OAuth2\ResponseInterface
40
	 */
41
	public $response = null;
42
43
	/**
44
	 * Method to instantiate the file-based api call.
45
	 *
46
	 * @param   mixed  $options  Optional custom options to load. JRegistry or array format
47
	 *
48
	 * @since   1.2
49
	 */
50
	public function __construct($options = null)
51
	{
52
		parent::__construct($options);
53
54
		// Get the global JAuthentication object.
55
		jimport('joomla.user.authentication');
56
57
		// Register OAuth2 classes
58
		require_once dirname(__FILE__) . '/Autoloader.php';
59
		OAuth2\Autoloader::register();
60
61
		// OAuth2 Server config from plugin
62
		$this->serverConfig = array(
63
			'use_jwt_access_tokens'        => (boolean) RBootstrap::getConfig('oauth2_use_jwt_access_tokens', false),
64
			'store_encrypted_token_string' => (boolean) RBootstrap::getConfig('oauth2_store_encrypted_token_string', true),
65
			'use_openid_connect'       => (boolean) RBootstrap::getConfig('oauth2_use_openid_connect', false),
66
			'id_lifetime'              => RBootstrap::getConfig('oauth2_id_lifetime', 3600),
67
			'access_lifetime'          => RBootstrap::getConfig('oauth2_access_lifetime', 3600),
68
			'www_realm'                => 'Service',
69
			'token_param_name'         => RBootstrap::getConfig('oauth2_token_param_name', 'access_token'),
70
			'token_bearer_header_name' => RBootstrap::getConfig('oauth2_token_bearer_header_name', 'Bearer'),
71
			'enforce_state'            => (boolean) RBootstrap::getConfig('oauth2_enforce_state', true),
72
			'require_exact_redirect_uri' => (boolean) RBootstrap::getConfig('oauth2_require_exact_redirect_uri', true),
73
			'allow_implicit'           => (boolean) RBootstrap::getConfig('oauth2_allow_implicit', false),
74
			'allow_credentials_in_request_body' => (boolean) RBootstrap::getConfig('oauth2_allow_credentials_in_request_body', true),
75
			'allow_public_clients'     => (boolean) RBootstrap::getConfig('oauth2_allow_public_clients', true),
76
			'always_issue_new_refresh_token' => (boolean) RBootstrap::getConfig('oauth2_always_issue_new_refresh_token', false),
77
			'unset_refresh_token_after_use' => (boolean) RBootstrap::getConfig('oauth2_unset_refresh_token_after_use', true),
78
			'issuer' => $_SERVER['HTTP_HOST'],
79
		);
80
81
		// Set database names to Redcore DB tables
82
		$prefix = JFactory::getDbo()->getPrefix();
83
		$databaseConfig = array(
84
			'client_table' => $prefix . 'redcore_oauth_clients',
85
			'access_token_table' => $prefix . 'redcore_oauth_access_tokens',
86
			'refresh_token_table' => $prefix . 'redcore_oauth_refresh_tokens',
87
			'code_table' => $prefix . 'redcore_oauth_authorization_codes',
88
			'user_table' => $prefix . 'redcore_oauth_users',
89
			'jwt_table'  => $prefix . 'redcore_oauth_jwt',
90
			'jti_table'  => $prefix . 'redcore_oauth_jti',
91
			'scope_table'  => $prefix . 'redcore_oauth_scopes',
92
			'public_key_table'  => $prefix . 'redcore_oauth_public_keys',
93
		);
94
95
		$conf = JFactory::getConfig();
96
97
		$storage = new OAuth2\Storage\Pdoredcore([
98
				'dsn' => 'mysql:dbname=' . $conf->get('db') . ';host=' . $conf->get('host'),
99
				'username' => $conf->get('user'),
100
				'password' => $conf->get('password')
101
			],
102
			$databaseConfig
103
		);
104
		$this->server = new OAuth2\Server($storage, $this->serverConfig);
105
106
		if (RBootstrap::getConfig('public_key')
107
			&& JFile::exists(RBootstrap::getConfig('public_key'))
108
			&& RBootstrap::getConfig('private_key')
109
			&& JFile::exists(RBootstrap::getConfig('private_key')))
110
		{
111
			$this->server->addStorage(
112
				new OAuth2\Storage\Memory([
113
						'keys' => [
114
							'public_key'  => file_get_contents(RBootstrap::getConfig('public_key')),
0 ignored issues
show
Bug introduced by
It seems like RBootstrap::getConfig('public_key') can also be of type null; however, parameter $filename of file_get_contents() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

114
							'public_key'  => file_get_contents(/** @scrutinizer ignore-type */ RBootstrap::getConfig('public_key')),
Loading history...
115
							'private_key' => file_get_contents(RBootstrap::getConfig('private_key')),
116
						]
117
					]
118
				),
119
				'public_key'
120
			);
121
		}
122
123
		// Add the "Authorization Code" grant type (this is where the oauth magic happens)
124
		$this->server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage, $this->serverConfig));
0 ignored issues
show
Unused Code introduced by
The call to OAuth2\GrantType\AuthorizationCode::__construct() has too many arguments starting with $this->serverConfig. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

124
		$this->server->addGrantType(/** @scrutinizer ignore-call */ new OAuth2\GrantType\AuthorizationCode($storage, $this->serverConfig));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
125
126
		// Add the "Client Credentials" grant type (it is the simplest of the grant types)
127
		$this->server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage, $this->serverConfig));
128
129
		// Add the "User Credentials" grant type (this is modified to suit Joomla authorization)
130
		$this->server->addGrantType(new OAuth2\GrantType\UserCredentials($storage, $this->serverConfig));
0 ignored issues
show
Unused Code introduced by
The call to OAuth2\GrantType\UserCredentials::__construct() has too many arguments starting with $this->serverConfig. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

130
		$this->server->addGrantType(/** @scrutinizer ignore-call */ new OAuth2\GrantType\UserCredentials($storage, $this->serverConfig));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
131
132
		// Add the "Refresh Token" grant type (this is great for extending expiration time on tokens)
133
		$this->server->addGrantType(new OAuth2\GrantType\RefreshToken($storage, $this->serverConfig));
134
135
		/*
136
		 * @todo Implement JwtBearer Grant type with public_key
137
		// Typically, the URI of the oauth server
138
		$audience = rtrim(JUri::base(), '/');
139
140
		// Add the "Refresh Token" grant type (this is great for extending expiration time on tokens)
141
		$this->server->addGrantType(new OAuth2\GrantType\JwtBearer($storage, $audience));
142
		*/
143
144
		// Init Environment
145
		$this->setApiOperation();
146
	}
147
148
	/**
149
	 * Set Method for Api
150
	 *
151
	 * @param   string  $operation  Operation name
152
	 *
153
	 * @return  RApi
154
	 *
155
	 * @since   1.2
156
	 */
157
	public function setApiOperation($operation = '')
158
	{
159
		if (!empty($operation))
160
		{
161
			$this->options->set('optionName', $operation);
162
		}
163
164
		$this->operation = strtolower($this->options->get('optionName', ''));
165
166
		return $this;
167
	}
168
169
	/**
170
	 * Execute the Api operation.
171
	 *
172
	 * @return  mixed  RApi object with information on success, boolean false on failure.
173
	 *
174
	 * @since   1.2
175
	 * @throws  RuntimeException
176
	 */
177
	public function execute()
178
	{
179
		if (!$this->isOperationAllowed())
180
		{
181
			throw new RuntimeException(JText::_('LIB_REDCORE_API_HAL_OPERATION_NOT_ALLOWED'));
182
		}
183
184
		switch ($this->operation)
185
		{
186
			case 'token':
187
				$this->apiToken();
188
				$this->cleanExpiredTokens($this->operation);
189
				break;
190
			case 'resource':
191
				$this->apiResource();
192
				break;
193
			case 'authorize':
194
				$this->apiAuthorize();
195
				$this->cleanExpiredTokens($this->operation);
196
				break;
197
			case 'profile':
198
				$this->apiProfile();
199
				break;
200
		}
201
202
		return $this;
203
	}
204
205
	/**
206
	 * Method to update client scopes.
207
	 *
208
	 * @param   string  $operation  Operation name
209
	 *
210
	 * @return  boolean  True on success, False on error.
211
	 */
212
	public function cleanExpiredTokens($operation)
213
	{
214
		$db = JFactory::getDbo();
215
		$query = $db->getQuery(true);
216
217
		switch ($operation)
218
		{
219
			// Delete Access Tokens
220
			case 'token':
221
				$query->delete('#__redcore_oauth_access_tokens')
222
					->where($db->qn('expires') . ' < ' . $db->q(date('Y-m-d H:i:s', strtotime('-2 weeks'))));
223
				$db->setQuery($query);
224
				$db->execute();
225
226
				$query = $db->getQuery(true)
227
					->delete('#__redcore_oauth_refresh_tokens')
228
					->where($db->qn('expires') . ' < ' . $db->q(date('Y-m-d H:i:s', strtotime('-2 weeks'))));
229
				$db->setQuery($query);
230
				$db->execute();
231
				break;
232
233
			// Delete Authorization codes
234
			case 'authorize':
235
			default:
236
				$query->delete('#__redcore_oauth_authorization_codes')
237
					->where($db->qn('expires') . ' < ' . $db->q(date('Y-m-d H:i:s', strtotime('-2 weeks'))));
238
				$db->setQuery($query);
239
				$db->execute();
240
				break;
241
		}
242
243
		return true;
244
	}
245
246
	/**
247
	 * Execute the Api Profile operation.
248
	 *
249
	 * @return  mixed  RApi object with information on success, boolean false on failure.
250
	 *
251
	 * @since   1.7
252
	 */
253
	public function apiProfile()
254
	{
255
		// Handle a request for an OAuth2.0 Access Token and send the response to the client if the token has expired
256
		if (!$this->server->verifyResourceRequest(OAuth2\Request::createFromGlobals(), null, $scopeToCheck = ''))
257
		{
258
			$this->response = $this->server->getResponse();
259
260
			return $this;
261
		}
262
263
		// We can take token and add more data to it
264
		$token = $this->server->getResourceController()->getToken();
265
266
		if (!empty($token['user_id']))
267
		{
268
			$this->loadUserIdentity($token['user_id']);
269
		}
270
271
		// Add expire Time
272
		$token['expireTimeFormatted'] = date('Y-m-d H:i:s', $token['expires']);
273
274
		// Add user Profile info
275
		$token['profile'] = RApiOauth2Helper::getUserProfileInformation();
276
277
		$this->response = RLayoutHelper::render(
0 ignored issues
show
Documentation Bug introduced by
It seems like RLayoutHelper::render('r...ile', compact('token')) of type string is incompatible with the declared type OAuth2\ResponseInterface of property $response.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
278
			'redcore.api.oauth2.profile',
279
			compact('token')
0 ignored issues
show
Bug introduced by
compact('token') of type array is incompatible with the type object expected by parameter $displayData of RLayoutHelper::render(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

279
			/** @scrutinizer ignore-type */ compact('token')
Loading history...
280
		);
281
282
		return $this;
283
	}
284
285
	/**
286
	 * Loads up user identity when requested
287
	 *
288
	 * @param   int  $userId  User ID
289
	 *
290
	 * @return  mixed  RApi object with information on success, boolean false on failure.
291
	 *
292
	 * @since   1.8
293
	 */
294
	public function loadUserIdentity($userId)
295
	{
296
		if (!empty($userId))
297
		{
298
			$user = JFactory::getUser($userId);
299
300
			// Load the JUser class on application for this client
301
			JFactory::getApplication()->loadIdentity($user);
302
			JFactory::getSession()->set('user', $user);
303
		}
304
305
		return $this;
306
	}
307
308
	/**
309
	 * Execute the Api Token operation.
310
	 *
311
	 * @return  mixed  RApi object with information on success, boolean false on failure.
312
	 *
313
	 * @since   1.2
314
	 */
315
	public function apiToken()
316
	{
317
		$request = OAuth2\Request::createFromGlobals();
318
319
		// Implicit grant type and Authorization code grant type require user to be logged in before authorising
320
		if ($request->request('grant_type') == 'implicit')
321
		{
322
			$user = $this->getLoggedUser();
0 ignored issues
show
Unused Code introduced by
The assignment to $user is dead and can be removed.
Loading history...
323
		}
324
325
		$this->response = $this->server->handleTokenRequest($request);
326
327
		if ($this->response instanceof OAuth2\Response)
0 ignored issues
show
introduced by
$this->response is always a sub-type of OAuth2\Response.
Loading history...
328
		{
329
			$expires = $this->response->getParameter('expires_in');
330
331
			if ($expires)
332
			{
333
				// Add expire Time
334
				$this->response->setParameter('expireTimeFormatted', date('Y-m-d H:i:s', $expires + time()));
335
				$this->response->setParameter('created', date('Y-m-d H:i:s'));
336
			}
337
		}
338
339
		return $this;
340
	}
341
342
	/**
343
	 * Execute the Api Resource operation.
344
	 *
345
	 * @return  mixed  RApi object with information on success, boolean false on failure.
346
	 *
347
	 * @since   1.2
348
	 */
349
	public function apiResource()
350
	{
351
		$scopeToCheck = $this->options->get('scope', '');
352
		$scopes = array();
353
354
		if (is_array($scopeToCheck) && count($scopeToCheck) > 0)
355
		{
356
			$scopes = $scopeToCheck;
357
			$scopeToCheck = null;
358
		}
359
360
		// Handle a request for an OAuth2.0 Access Token and send the response to the client
361
		if (!$this->server->verifyResourceRequest(OAuth2\Request::createFromGlobals(), null, $scopeToCheck))
362
		{
363
			$this->response = $this->server->getResponse();
364
365
			return $this;
366
		}
367
368
		$token = $this->server->getResourceController()->getToken();
369
370
		if (!empty($scopes))
371
		{
372
			$requestValid = false;
373
374
			// Check all scopes
375
			foreach ($scopes as $scope)
376
			{
377
				if (!empty($scope) && !empty($token["scope"]) && $this->server->getScopeUtil()->checkScope($scope, $token['scope']))
378
				{
379
					$requestValid = true;
380
					break;
381
				}
382
			}
383
384
			if (!$requestValid)
385
			{
386
				$this->response = $this->server->getResponse();
387
				$this->response->setError(403, 'insufficient_scope', JText::_('LIB_REDCORE_API_OAUTH2_SERVER_INSUFFICIENT_SCOPE'));
388
				$this->response->addHttpHeaders(
389
					array(
390
						'WWW-Authenticate' => sprintf('%s realm="%s", scope="%s", error="%s", error_description="%s"',
391
							$this->server->getTokenType()->getTokenType(),
392
							$this->serverConfig['www_realm'],
393
							implode(', ', $scopes),
394
							$this->response->getParameter('error'),
395
							$this->response->getParameter('error_description')
396
						)
397
					)
398
				);
399
400
				return $this;
401
			}
402
		}
403
404
		$this->response = json_encode(
0 ignored issues
show
Documentation Bug introduced by
It seems like json_encode(array('succe...RVER_ACCESS_SUCCESS'))) of type string is incompatible with the declared type OAuth2\ResponseInterface of property $response.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
405
			array('success' => true, 'user_id' => $token['user_id'], 'message' => JText::_('LIB_REDCORE_API_OAUTH2_SERVER_ACCESS_SUCCESS'))
406
		);
407
408
		return $this;
409
	}
410
411
	/**
412
	 * Execute the Api Authorize operation.
413
	 *
414
	 * @return  mixed  RApi object with information on success, boolean false on failure.
415
	 *
416
	 * @since   1.2
417
	 */
418
	public function apiAuthorize()
419
	{
420
		$user = $this->getLoggedUser();
421
		$request = OAuth2\Request::createFromGlobals();
422
		$response = new OAuth2\Response;
423
424
		// Validate the authorize request
425
		if (!$this->server->validateAuthorizeRequest($request, $response))
426
		{
427
			$this->response = $response;
428
429
			return $this;
430
		}
431
432
		$clientId = $request->query('client_id');
433
		$scopes = RApiOauth2Helper::getClientScopes($clientId);
434
435
		if ($request->request('authorized', '') == '')
436
		{
437
			$clientScopes = !empty($scopes) ? explode(' ', $scopes) : array();
0 ignored issues
show
Bug introduced by
$scopes of type array is incompatible with the type string expected by parameter $string of explode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

437
			$clientScopes = !empty($scopes) ? explode(' ', /** @scrutinizer ignore-type */ $scopes) : array();
Loading history...
438
439
			if (!empty($clientScopes))
440
			{
441
				$clientScopes = RApiHalHelper::getWebserviceScopes($clientScopes);
442
			}
443
444
			$currentUri = JUri::getInstance();
445
			$formAction = JUri::root() . 'index.php?' . $currentUri->getQuery();
446
447
			// Display an authorization form
448
			$this->response = RLayoutHelper::render(
0 ignored issues
show
Documentation Bug introduced by
It seems like RLayoutHelper::render('o...es' => $clientScopes))) of type string is incompatible with the declared type OAuth2\ResponseInterface of property $response.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
449
				'oauth2.authorize',
450
				array(
451
					'view' => $this,
452
					'options' => array (
453
						'clientId' => $clientId,
454
						'formAction' => $formAction,
455
						'scopes' => $clientScopes,
456
					)
457
				)
458
			);
459
460
			return $this;
461
		}
462
463
		// Print the authorization code if the user has authorized your client
464
		$is_authorized = $request->request('authorized', '') === JText::_('LIB_REDCORE_API_OAUTH2_SERVER_AUTHORIZE_CLIENT_YES')
465
			|| $request->request('authorized', '') == '1';
466
467
		// We are setting client scope instead of requesting scope from user request
468
		$request->request['scope'] = $scopes;
469
		$this->server->handleAuthorizeRequest($request, $response, $is_authorized, $user->id);
470
471
		// We add access_token directly to the URI of the redirect string (default is after the # character)
472
		if (RBootstrap::getConfig('oauth2_redirect_with_token', 0))
473
		{
474
			if ($response->isRedirection())
475
			{
476
				$location = $response->getHttpHeader('Location');
477
				$location = explode('#', $location);
478
479
				// Get access token
480
				if (isset($location[1]))
481
				{
482
					$location[1] = str_replace('&amp;', '&', $location[1]);
483
					$uris = explode('&', $location[1]);
484
485
					// We search for access_token parameter
486
					foreach ($uris as $uri)
487
					{
488
						if (strpos($uri, RBootstrap::getConfig('oauth2_token_param_name', 'access_token')) === 0)
489
						{
490
							$location[0] .= '&' . $uri;
491
							break;
492
						}
493
					}
494
495
					$location = implode('#', $location);
496
					$response->setHttpHeader('Location', $location);
497
				}
498
			}
499
		}
500
501
		$this->response = $response;
502
503
		if (RBootstrap::getConfig('oauth2_joomla_logout_right_after_authorize', false))
504
		{
505
			JFactory::getApplication()->logout($user->id);
506
		}
507
508
		return $this;
509
	}
510
511
	/**
512
	 * Checks if operation is allowed from the configuration file
513
	 *
514
	 * @return object This method may be chained.
515
	 *
516
	 * @throws  RuntimeException
517
	 */
518
	public function isOperationAllowed()
519
	{
520
		if (empty($this->operation))
521
		{
522
			throw new RuntimeException(JText::_('LIB_REDCORE_API_OAUTH2_OPERATION_NOT_SPECIFIED'));
523
		}
524
525
		return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type object.
Loading history...
526
	}
527
528
	/**
529
	 * Gets logged In user or redirect to login page
530
	 *
531
	 * @return JUser  Instance of the logged in user
532
	 */
533
	public function getLoggedUser()
534
	{
535
		$user = JFactory::getUser();
536
537
		// If user is not logged in we redirect him to the login page
538
		if (empty($user->id))
539
		{
540
			$currentUri = JUri::getInstance();
541
			$returnUrl = JUri::root() . 'index.php?' . $currentUri->getQuery();
542
543
			$loginLink = RRoute::_(JUri::root() . 'index.php?option=com_users&view=login');
544
545
			$loginPage = new JUri($loginLink);
546
			$loginPage->setVar('return', base64_encode($returnUrl));
547
548
			JFactory::getApplication()->redirect($loginPage);
549
			JFactory::getApplication()->close();
550
		}
551
552
		return $user;
553
	}
554
555
	/**
556
	 * Method to send the application response to the client.  All headers will be sent prior to the main
557
	 * application output data.
558
	 *
559
	 * @return  void
560
	 *
561
	 * @since   1.2
562
	 */
563
	public function render()
564
	{
565
		if ($this->response instanceof OAuth2\ResponseInterface)
0 ignored issues
show
introduced by
$this->response is always a sub-type of OAuth2\ResponseInterface.
Loading history...
566
		{
567
			$this->response->send();
0 ignored issues
show
Bug introduced by
The method send() does not exist on OAuth2\ResponseInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to OAuth2\ResponseInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

567
			$this->response->/** @scrutinizer ignore-call */ 
568
                    send();
Loading history...
568
		}
569
		else
570
		{
571
			$app = JFactory::getApplication();
572
573
			$body = $this->response;
574
575
			// Check if the request is CORS ( Cross-origin resource sharing ) and change the body if true
576
			$body = $this->prepareBody($body);
577
578
			json_decode((string) $body);
579
580
			if (json_last_error() == JSON_ERROR_NONE)
581
			{
582
				$app->setHeader('Content-length', strlen($body), true);
583
				$app->setHeader('Content-type', 'application/json; charset=UTF-8', true);
584
				$app->sendHeaders();
585
			}
586
587
			echo (string) $body;
588
		}
589
	}
590
591
	/**
592
	 * Prepares body for response
593
	 *
594
	 * @param   string  $message  The return message
595
	 *
596
	 * @return  string	The message prepared
597
	 *
598
	 * @since   1.2
599
	 */
600
	public function prepareBody($message)
601
	{
602
		return $message;
603
	}
604
}
605