Mastodon   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 86
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 6
eloc 42
c 1
b 0
f 0
dl 0
loc 86
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A setInstance() 0 17 2
A getAccessToken() 0 23 1
A me() 0 15 3
1
<?php
2
/**
3
 * Class Mastodon
4
 *
5
 * @created      19.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\OAuth\Core\{AccessToken, CSRFToken, OAuth2Provider, ProviderException, TokenRefresh};
14
use chillerlan\HTTP\Utils\MessageUtil;
15
use chillerlan\HTTP\Utils\QueryUtil;
16
use chillerlan\OAuth\OAuthException;
17
18
use Psr\Http\Message\ResponseInterface;
19
use function array_merge;
20
use function sprintf;
21
use const PHP_QUERY_RFC1738;
22
23
/**
24
 * @see https://docs.joinmastodon.org/client/intro/
25
 * @see https://docs.joinmastodon.org/methods/apps/oauth/
26
 */
27
class Mastodon extends OAuth2Provider implements CSRFToken, TokenRefresh{
28
29
	public const SCOPE_READ        = 'read';
30
	public const SCOPE_WRITE       = 'write';
31
	public const SCOPE_FOLLOW      = 'follow';
32
	public const SCOPE_PUSH        = 'push';
33
34
	protected ?string $apiDocs     = 'https://docs.joinmastodon.org/api/';
35
36
	protected array $defaultScopes = [
37
		Mastodon::SCOPE_READ,
38
		Mastodon::SCOPE_FOLLOW,
39
	];
40
41
	protected string $instance     = '';
42
43
	/**
44
	 * set the internal URLs for the given Mastodon instance
45
	 *
46
	 * @throws \chillerlan\OAuth\OAuthException
47
	 */
48
	public function setInstance(string $instance):Mastodon{
49
		$instance = QueryUtil::parseUrl($instance);
50
51
		if(!isset($instance['host'])){
52
			throw new OAuthException('invalid instance URL');
53
		}
54
55
		// @todo: check if host exists/responds
56
		$this->instance       = 'https://'.$instance['host'];
57
58
		$this->apiURL         = $this->instance.'/api';
59
		$this->authURL        = $this->instance.'/oauth/authorize';
60
		$this->accessTokenURL = $this->instance.'/oauth/token';
61
		$this->userRevokeURL  = $this->instance.'/oauth/authorized_applications';
62
		$this->applicationURL = $this->instance.'/settings/applications';
63
64
		return $this;
65
	}
66
67
	/**
68
	 * @inheritDoc
69
	 */
70
	public function getAccessToken(string $code, string $state = null):AccessToken{
71
72
		$body = [
73
			'client_id'     => $this->options->key,
74
			'client_secret' => $this->options->secret,
75
			'code'          => $code,
76
			'grant_type'    => 'authorization_code',
77
			'redirect_uri'  => $this->options->callbackURL,
78
		];
79
80
		$request = $this->requestFactory
81
			->createRequest('POST', $this->accessTokenURL)
82
			->withHeader('Content-Type', 'application/x-www-form-urlencoded')
83
			->withHeader('Accept-Encoding', 'identity')
84
			->withBody($this->streamFactory->createStream(QueryUtil::build($body, PHP_QUERY_RFC1738)));
85
86
		$token = $this->parseTokenResponse($this->http->sendRequest($request));
87
		// store the instance the token belongs to
88
		$token->extraParams = array_merge($token->extraParams, ['instance' => $this->instance]);
89
90
		$this->storage->storeAccessToken($token, $this->serviceName);
91
92
		return $token;
93
	}
94
95
	/**
96
	 * @inheritDoc
97
	 */
98
	public function me():ResponseInterface{
99
		$response = $this->request('/v1/accounts/verify_credentials');
100
		$status   = $response->getStatusCode();
101
102
		if($status === 200){
103
			return $response;
104
		}
105
106
		$json = MessageUtil::decodeJSON($response);
107
108
		if(isset($json->error)){
109
			throw new ProviderException($json->error);
110
		}
111
112
		throw new ProviderException(sprintf('user info error error HTTP/%s', $status));
113
	}
114
115
}
116