Deezer   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 64
c 0
b 0
f 0
dl 0
loc 121
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getAccessToken() 0 21 1
A getAuthURL() 0 17 2
A me() 0 14 4
A parseTokenResponse() 0 23 3
1
<?php
2
/**
3
 * Class Deezer
4
 *
5
 * @created      09.08.2018
6
 * @author       Smiley <[email protected]>
7
 * @copyright    2018 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\{AccessToken, CSRFToken, OAuth2Provider, ProviderException};
16
use Psr\Http\Message\{ResponseInterface, UriInterface};
17
use function array_merge;
18
use function implode;
19
use function sprintf;
20
use const PHP_QUERY_RFC1738;
21
22
/**
23
 * @see https://developers.deezer.com/api/oauth
24
 *
25
 * sure, you *can* use different parameter names than the standard ones... and what about JSON?
26
 * https://xkcd.com/927/
27
 */
28
class Deezer extends OAuth2Provider implements CSRFToken{
29
30
	public const SCOPE_BASIC             = 'basic_access';
31
	public const SCOPE_EMAIL             = 'email';
32
	public const SCOPE_OFFLINE_ACCESS    = 'offline_access';
33
	public const SCOPE_MANAGE_LIBRARY    = 'manage_library';
34
	public const SCOPE_MANAGE_COMMUNITY  = 'manage_community';
35
	public const SCOPE_DELETE_LIBRARY    = 'delete_library';
36
	public const SCOPE_LISTENING_HISTORY = 'listening_history';
37
38
	protected string  $authURL           = 'https://connect.deezer.com/oauth/auth.php';
39
	protected string  $accessTokenURL    = 'https://connect.deezer.com/oauth/access_token.php';
40
	protected string  $apiURL            = 'https://api.deezer.com';
41
	protected ?string $userRevokeURL     = 'https://www.deezer.com/account/apps';
42
	protected ?string $apiDocs           = 'https://developers.deezer.com/api';
43
	protected ?string $applicationURL    = 'http://developers.deezer.com/myapps';
44
	protected int     $authMethod        = self::AUTH_METHOD_QUERY;
45
46
	protected array   $defaultScopes     = [
47
		self::SCOPE_BASIC,
48
		self::SCOPE_EMAIL,
49
		self::SCOPE_OFFLINE_ACCESS,
50
		self::SCOPE_MANAGE_LIBRARY,
51
		self::SCOPE_LISTENING_HISTORY,
52
	];
53
54
	/**
55
	 * @inheritDoc
56
	 */
57
	public function getAuthURL(array $params = null, array $scopes = null):UriInterface{
58
		$params ??= [];
59
60
		if(isset($params['client_secret'])){
61
			unset($params['client_secret']);
62
		}
63
64
		$params = array_merge($params, [
65
			'app_id'        => $this->options->key,
66
			'redirect_uri'  => $this->options->callbackURL,
67
			'perms'         => implode($this->scopesDelimiter, $scopes ?? []),
68
#			'response_type' => 'token', // -> token in hash fragment
69
		]);
70
71
		$params = $this->setState($params);
72
73
		return $this->uriFactory->createUri(QueryUtil::merge($this->authURL, $params));
74
	}
75
76
	/**
77
	 * @inheritDoc
78
	 */
79
	public function getAccessToken(string $code, string $state = null):AccessToken{
80
		$this->checkState($state);
81
82
		$body = [
83
			'app_id' => $this->options->key,
84
			'secret' => $this->options->secret,
85
			'code'   => $code,
86
			'output' => 'json',
87
		];
88
89
		$request = $this->requestFactory
90
			->createRequest('POST', $this->accessTokenURL)
91
			->withHeader('Content-Type', 'application/x-www-form-urlencoded')
92
			->withHeader('Accept-Encoding', 'identity')
93
			->withBody($this->streamFactory->createStream(QueryUtil::build($body, PHP_QUERY_RFC1738)));
94
95
		$token = $this->parseTokenResponse($this->http->sendRequest($request));
96
97
		$this->storage->storeAccessToken($token, $this->serviceName);
98
99
		return $token;
100
	}
101
102
	/**
103
	 * @inheritDoc
104
	 */
105
	protected function parseTokenResponse(ResponseInterface $response):AccessToken{
106
		$data = QueryUtil::parse(MessageUtil::decompress($response));
107
108
		if(isset($data['error_reason'])){
109
			throw new ProviderException('error retrieving access token: "'.$data['error_reason'].'"');
110
		}
111
112
		if(!isset($data['access_token'])){
113
			throw new ProviderException('token missing');
114
		}
115
116
		$token = new AccessToken;
117
118
		$token->provider     = $this->serviceName;
119
		$token->accessToken  = $data['access_token'];
120
		$token->expires      = $data['expires'] ?? $data['expires_in'] ?? AccessToken::EOL_NEVER_EXPIRES;
121
		$token->refreshToken = $data['refresh_token'] ?? null;
122
123
		unset($data['expires'], $data['expires_in'], $data['refresh_token'], $data['access_token']);
124
125
		$token->extraParams = $data;
126
127
		return $token;
128
	}
129
130
	/**
131
	 * deezer keeps testing my sanity - HTTP/200 on invalid token... sure
132
	 *
133
	 * @inheritDoc
134
	 */
135
	public function me():ResponseInterface{
136
		$response = $this->request('/user/me');
137
		$status   = $response->getStatusCode();
138
		$json     = MessageUtil::decodeJSON($response);
139
140
		if($status === 200 && !isset($json->error)){
141
			return $response;
142
		}
143
144
		if(isset($json->error)){
145
			throw new ProviderException($json->error->message);
146
		}
147
148
		throw new ProviderException(sprintf('user info error error HTTP/%s', $status));
149
	}
150
151
}
152