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

SteamOpenID   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 98
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 9
eloc 45
c 1
b 0
f 0
dl 0
loc 98
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getRequestAuthorization() 0 10 2
A getAuthURL() 0 13 1
A getAccessToken() 0 32 2
A parseTokenResponse() 0 16 4
1
<?php
2
/**
3
 * Class SteamOpenID
4
 *
5
 * @created      15.03.2021
6
 * @author       smiley <[email protected]>
7
 * @copyright    2021 smiley
8
 * @license      MIT
9
 */
10
11
namespace chillerlan\OAuth\Providers;
12
13
use chillerlan\OAuth\Core\{AccessToken, OAuthProvider, ProviderException};
14
use chillerlan\HTTP\Utils\QueryUtil;
15
use Psr\Http\Message\{RequestInterface, ResponseInterface, UriInterface};
16
17
use function explode, intval, preg_replace;
18
19
/**
20
 * @see https://steamcommunity.com/dev
21
 * @see https://partner.steamgames.com/doc/webapi_overview
22
 * @see https://steamwebapi.azurewebsites.net/
23
 */
24
class SteamOpenID extends OAuthProvider{
25
26
	protected string  $authURL        = 'https://steamcommunity.com/openid/login';
27
	protected string  $accessTokenURL = 'https://steamcommunity.com/openid/login';
28
	protected string  $apiURL         = 'https://api.steampowered.com';
29
	protected ?string $applicationURL = 'https://steamcommunity.com/dev/apikey';
30
	protected ?string $apiDocs        = 'https://developer.valvesoftware.com/wiki/Steam_Web_API';
31
32
	/**
33
	 * @inheritDoc
34
	 */
35
	public function getAuthURL(array $params = null):UriInterface{
36
37
		// we ignore user supplied params here
38
		$params = [
39
			'openid.ns'         => 'http://specs.openid.net/auth/2.0',
40
			'openid.mode'       => 'checkid_setup',
41
			'openid.return_to'  => $this->options->callbackURL,
42
			'openid.realm'      => $this->options->key,
43
			'openid.identity'   => 'http://specs.openid.net/auth/2.0/identifier_select',
44
			'openid.claimed_id' => 'http://specs.openid.net/auth/2.0/identifier_select',
45
		];
46
47
		return $this->uriFactory->createUri(QueryUtil::merge($this->authURL, $params));
48
	}
49
50
	/**
51
	 * @inheritDoc
52
	 */
53
	public function getAccessToken(array $received):AccessToken{
54
55
		$body = [
56
			'openid.mode' => 'check_authentication',
57
			'openid.ns'   => 'http://specs.openid.net/auth/2.0',
58
			'openid.sig'  => $received['openid_sig'],
59
		];
60
61
		foreach(explode(',', $received['openid_signed']) as $item){
62
			$body['openid.'.$item] = $received['openid_'.$item];
63
		}
64
65
		$request = $this->requestFactory
66
			->createRequest('POST', $this->accessTokenURL)
67
			->withHeader('Content-Type', 'application/x-www-form-urlencoded')
68
			->withBody($this->streamFactory->createStream(QueryUtil::build($body)));
69
70
		$token = $this->parseTokenResponse($this->http->sendRequest($request));
71
		$id    = preg_replace('/[^\d]/', '', $received['openid_claimed_id']);
72
73
		// as this method is intended for one-time authentication only we'll not receive a token.
74
		// instead we're gonna save the verified steam user id as token as it is required
75
		// for several "authenticated" endpoints.
76
		$token->accessToken = $id;
77
		$token->extraParams = [
78
			'claimed_id' => $received['openid_claimed_id'],
79
			'id_int'     => intval($id),
80
		];
81
82
		$this->storage->storeAccessToken($token, $this->serviceName);
83
84
		return $token;
85
	}
86
87
	/**
88
	 * @throws \chillerlan\OAuth\Core\ProviderException
89
	 */
90
	protected function parseTokenResponse(ResponseInterface $response):AccessToken{
91
		$data = explode("\x0a", (string)$response->getBody());
92
93
		if(!isset($data[1]) || !str_starts_with($data[1], 'is_valid')){
94
			throw new ProviderException('unable to parse token response');
95
		}
96
97
		if($data[1] !== 'is_valid:true'){
98
			throw new ProviderException('invalid id');
99
		}
100
101
		// the response is only validation, so we'll just return an empty token and add the id in the next step
102
		return new AccessToken([
103
			'accessToken' => 'SteamID',
104
			'provider' => $this->serviceName,
105
			'expires'  => AccessToken::EOL_NEVER_EXPIRES,
106
		]);
107
	}
108
109
	/**
110
	 *
111
	 */
112
	public function getRequestAuthorization(RequestInterface $request, AccessToken $token):RequestInterface{
113
		$uri    = (string)$request->getUri();
114
		$params = ['key' => $this->options->secret];
115
116
		// the steamid parameter does not necessarily specify the current user, so add it only when it's not already set
117
		if(!str_contains($uri, 'steamid=')){
118
			$params['steamid']= $token->accessToken;
119
		}
120
121
		return $request->withUri($this->uriFactory->createUri(QueryUtil::merge($uri, $params)));
122
	}
123
124
}
125