Passed
Push — main ( e868ec...9f95cc )
by smiley
12:00
created

NPROne::sendRequest()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 18
rs 9.6111
cc 5
nc 3
nop 1
1
<?php
2
/**
3
 * Class NPROne
4
 *
5
 * @created      28.07.2019
6
 * @author       smiley <[email protected]>
7
 * @copyright    2019 smiley
8
 * @license      MIT
9
 */
10
11
namespace chillerlan\OAuth\Providers;
12
13
use chillerlan\HTTP\Utils\MessageUtil;
14
use chillerlan\HTTP\Utils\QueryUtil;
15
use chillerlan\OAuth\Core\{CSRFToken, OAuth2Provider, ProviderException, TokenRefresh};
16
use Psr\Http\Message\{RequestInterface, ResponseInterface};
17
use function sprintf;
18
use function str_contains;
19
20
/**
21
 * @see https://dev.npr.org
22
 * @see https://github.com/npr/npr-one-backend-proxy-php
23
 */
24
class NPROne extends OAuth2Provider implements CSRFToken, TokenRefresh{
25
26
	public const SCOPE_IDENTITY_READONLY  = 'identity.readonly';
27
	public const SCOPE_IDENTITY_WRITE     = 'identity.write';
28
	public const SCOPE_LISTENING_READONLY = 'listening.readonly';
29
	public const SCOPE_LISTENING_WRITE    = 'listening.write';
30
	public const SCOPE_LOCALACTIVATION    = 'localactivation';
31
32
	protected string  $authURL            = 'https://authorization.api.npr.org/v2/authorize';
33
	protected string  $accessTokenURL     = 'https://authorization.api.npr.org/v2/token';
34
	protected ?string $revokeURL          = 'https://authorization.api.npr.org/v2/token/revoke';
35
	protected ?string $apiDocs            = 'https://dev.npr.org/api/';
36
	protected ?string $applicationURL     = 'https://dev.npr.org/console';
37
38
	protected array   $defaultScopes      = [
39
		self::SCOPE_IDENTITY_READONLY,
40
		self::SCOPE_LISTENING_READONLY,
41
	];
42
43
	/**
44
	 * @inheritDoc
45
	 */
46
	protected function getRequestTarget(string $uri):string{
47
		$parsedURL = QueryUtil::parseUrl($uri);
48
49
		if(!isset($parsedURL['path'])){
50
			throw new ProviderException('invalid path'); // @codeCoverageIgnore
51
		}
52
53
		// for some reason we were given a host name
54
		if(isset($parsedURL['host'])){
55
56
			// back out if it doesn't match
57
			if(!str_contains($parsedURL['host'], '.api.npr.org')){
58
				throw new ProviderException('given host does not match provider host'); // @codeCoverageIgnore
59
			}
60
61
			// we explicitly ignore any existing parameters here
62
			return 'https://'.$parsedURL['host'].$parsedURL['path'];
63
		}
64
65
		// $apiURL may already include a part of the path
66
		return $this->apiURL.$parsedURL['path'];
67
	}
68
69
	/**
70
	 * @inheritDoc
71
	 */
72
	public function sendRequest(RequestInterface $request):ResponseInterface{
73
74
		// get authorization only if we request the provider API
75
		if(str_contains((string)$request->getUri(), '.api.npr.org')){
76
			$token = $this->storage->getAccessToken($this->serviceName);
77
78
			// attempt to refresh an expired token
79
			if(
80
				$this->options->tokenAutoRefresh
81
				&& ($token->isExpired() || $token->expires === $token::EOL_UNKNOWN)
82
			){
83
				$token = $this->refreshAccessToken($token); // @codeCoverageIgnore
84
			}
85
86
			$request = $this->getRequestAuthorization($request, $token);
87
		}
88
89
		return $this->http->sendRequest($request);
90
	}
91
92
	/**
93
	 * @inheritDoc
94
	 */
95
	public function me():ResponseInterface{
96
		$response = $this->request('https://identity.api.npr.org/v2/user');
97
		$status   = $response->getStatusCode();
98
99
		if($status === 200){
100
			return $response;
101
		}
102
103
		$json = MessageUtil::decodeJSON($response);
104
105
		if(isset($json->errors)){
106
			throw new ProviderException($json->errors[0]->text);
107
		}
108
109
		throw new ProviderException(sprintf('user info error error HTTP/%s', $status));
110
	}
111
112
}
113