1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Class SteamOpenID |
4
|
|
|
* |
5
|
|
|
* @link https://steamcommunity.com/dev |
6
|
|
|
* @link https://partner.steamgames.com/doc/webapi_overview |
7
|
|
|
* @link https://steamwebapi.azurewebsites.net/ |
8
|
|
|
* |
9
|
|
|
* @created 15.03.2021 |
10
|
|
|
* @author smiley <[email protected]> |
11
|
|
|
* @copyright 2021 smiley |
12
|
|
|
* @license MIT |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
namespace chillerlan\OAuth\Providers\Steam; |
16
|
|
|
|
17
|
|
|
use chillerlan\OAuth\Core\{AccessToken, OAuthProvider, ProviderException}; |
18
|
|
|
use Psr\Http\Message\{RequestInterface, ResponseInterface, UriInterface}; |
19
|
|
|
|
20
|
|
|
use function chillerlan\HTTP\Psr7\merge_query; |
21
|
|
|
use function explode, http_build_query, intval, parse_url, preg_replace, strpos; |
22
|
|
|
|
23
|
|
|
use const PHP_URL_QUERY; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @method \Psr\Http\Message\ResponseInterface playerServiceGetBadges(array $params = ['steamid']) |
27
|
|
|
* @method \Psr\Http\Message\ResponseInterface playerServiceGetCommunityBadgeProgress(array $params = ['steamid', 'badgeid']) |
28
|
|
|
* @method \Psr\Http\Message\ResponseInterface playerServiceGetOwnedGames(array $params = ['steamid', 'include_appinfo', 'include_played_free_games', 'appids_filter', 'include_free_sub', 'skip_unvetted_apps']) |
29
|
|
|
* @method \Psr\Http\Message\ResponseInterface playerServiceGetRecentlyPlayedGames(array $params = ['steamid', 'count']) |
30
|
|
|
* @method \Psr\Http\Message\ResponseInterface playerServiceGetSteamLevel(array $params = ['steamid']) |
31
|
|
|
* @method \Psr\Http\Message\ResponseInterface playerServiceIsPlayingSharedGame(array $params = ['steamid', 'appid_playing']) |
32
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamAppsGetAppList() |
33
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamAppsGetSDRConfig(array $params = ['appid', 'partner']) |
34
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamAppsGetServersAtAddress(array $params = ['addr']) |
35
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamAppsUpToDateCheck(array $params = ['appid', 'version']) |
36
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamNewsGetNewsForApp(array $params = ['appid', 'maxlength', 'enddate', 'count', 'feeds', 'tags']) |
37
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserGetFriendList(array $params = ['steamid', 'relationship']) |
38
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserGetPlayerBans(array $params = ['steamids']) |
39
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserGetPlayerSummaries(array $params = ['steamids']) |
40
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserGetUserGroupList(array $params = ['steamid']) |
41
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserResolveVanityURL(array $params = ['vanityurl', 'url_type']) |
42
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserStatsGetGlobalAchievementPercentagesForApp(array $params = ['gameid']) |
43
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserStatsGetGlobalStatsForGame(array $params = ['appid', 'count', 'name[0]', 'startdate', 'enddate']) |
44
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserStatsGetNumberOfCurrentPlayers(array $params = ['appid']) |
45
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserStatsGetPlayerAchievements(array $params = ['steamid', 'appid', 'l']) |
46
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserStatsGetSchemaForGame(array $params = ['appid', 'l']) |
47
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamUserStatsGetUserStatsForGame(array $params = ['steamid', 'appid']) |
48
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamWebAPIUtilGetServerInfo() |
49
|
|
|
* @method \Psr\Http\Message\ResponseInterface steamWebAPIUtilGetSupportedAPIList() |
50
|
|
|
* @method \Psr\Http\Message\ResponseInterface storeServiceGetAppList(array $params = ['if_modified_since', 'have_description_language', 'include_games', 'include_dlc', 'include_software', 'include_videos', 'include_hardware', 'last_appid', 'max_results']) |
51
|
|
|
*/ |
52
|
|
|
class SteamOpenID extends OAuthProvider{ |
53
|
|
|
|
54
|
|
|
protected string $authURL = 'https://steamcommunity.com/openid/login'; |
55
|
|
|
protected string $accessTokenURL = 'https://steamcommunity.com/openid/login'; |
56
|
|
|
protected ?string $apiURL = 'https://api.steampowered.com'; |
57
|
|
|
protected ?string $applicationURL = 'https://steamcommunity.com/dev/apikey'; |
58
|
|
|
protected ?string $apiDocs = 'https://developer.valvesoftware.com/wiki/Steam_Web_API'; |
59
|
|
|
protected ?string $endpointMap = SteamEndpoints::class; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @param array|null $params |
63
|
|
|
* |
64
|
|
|
* @return \Psr\Http\Message\UriInterface |
65
|
|
|
*/ |
66
|
|
|
public function getAuthURL(array $params = null):UriInterface{ |
67
|
|
|
|
68
|
|
|
// we ignore user supplied params here |
69
|
|
|
$params = [ |
70
|
|
|
'openid.ns' => 'http://specs.openid.net/auth/2.0', |
71
|
|
|
'openid.mode' => 'checkid_setup', |
72
|
|
|
'openid.return_to' => $this->options->callbackURL, |
73
|
|
|
'openid.realm' => $this->options->key, |
74
|
|
|
'openid.identity' => 'http://specs.openid.net/auth/2.0/identifier_select', |
75
|
|
|
'openid.claimed_id' => 'http://specs.openid.net/auth/2.0/identifier_select', |
76
|
|
|
]; |
77
|
|
|
|
78
|
|
|
return $this->uriFactory->createUri(merge_query($this->authURL, $params)); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @param array $received |
83
|
|
|
* |
84
|
|
|
* @return \chillerlan\OAuth\Core\AccessToken |
85
|
|
|
*/ |
86
|
|
|
public function getAccessToken(array $received):AccessToken{ |
87
|
|
|
|
88
|
|
|
$body = [ |
89
|
|
|
'openid.mode' => 'check_authentication', |
90
|
|
|
'openid.ns' => 'http://specs.openid.net/auth/2.0', |
91
|
|
|
'openid.sig' => $received['openid_sig'], |
92
|
|
|
]; |
93
|
|
|
|
94
|
|
|
foreach(explode(',', $received['openid_signed']) as $item){ |
95
|
|
|
$body['openid.'.$item] = $received['openid_'.$item]; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
$request = $this->requestFactory |
99
|
|
|
->createRequest('POST', $this->accessTokenURL) |
100
|
|
|
->withHeader('Content-Type', 'application/x-www-form-urlencoded') |
101
|
|
|
->withBody($this->streamFactory->createStream(http_build_query($body))); |
102
|
|
|
|
103
|
|
|
$token = $this->parseTokenResponse($this->http->sendRequest($request)); |
104
|
|
|
$id = preg_replace('/[^\d]/', '', $received['openid_claimed_id']); |
105
|
|
|
|
106
|
|
|
// as this method is intended for one-time authentication only we'll not receive a token. |
107
|
|
|
// instead we're gonna save the verified steam user id as token as it is required |
108
|
|
|
// for several "authenticated" endpoints. |
109
|
|
|
$token->accessToken = $id; |
110
|
|
|
$token->extraParams = [ |
111
|
|
|
'claimed_id' => $received['openid_claimed_id'], |
112
|
|
|
'id_int' => intval($id), |
113
|
|
|
]; |
114
|
|
|
|
115
|
|
|
$this->storage->storeAccessToken($this->serviceName, $token); |
116
|
|
|
|
117
|
|
|
return $token; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* @param \Psr\Http\Message\ResponseInterface $response |
122
|
|
|
* |
123
|
|
|
* @return \chillerlan\OAuth\Core\AccessToken |
124
|
|
|
* @throws \chillerlan\OAuth\Core\ProviderException |
125
|
|
|
*/ |
126
|
|
|
protected function parseTokenResponse(ResponseInterface $response):AccessToken{ |
127
|
|
|
$data = explode("\x0a", (string)$response->getBody()); |
128
|
|
|
|
129
|
|
|
if(!isset($data[1]) || strpos($data[1], 'is_valid') !== 0){ |
130
|
|
|
throw new ProviderException('unable to parse token response'); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
if($data[1] !== 'is_valid:true'){ |
134
|
|
|
throw new ProviderException('invalid id'); |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
// the response is only validation, so we'll just return an empty token and add the id in the next step |
138
|
|
|
return new AccessToken([ |
139
|
|
|
'provider' => $this->serviceName, |
140
|
|
|
'expires' => AccessToken::EOL_NEVER_EXPIRES, |
141
|
|
|
]); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* @param \Psr\Http\Message\RequestInterface $request |
146
|
|
|
* @param \chillerlan\OAuth\Core\AccessToken $token |
147
|
|
|
* |
148
|
|
|
* @return \Psr\Http\Message\RequestInterface |
149
|
|
|
*/ |
150
|
|
|
public function getRequestAuthorization(RequestInterface $request, AccessToken $token):RequestInterface{ |
151
|
|
|
$uri = (string)$request->getUri(); |
152
|
|
|
$params = ['key' => $this->options->secret]; |
153
|
|
|
|
154
|
|
|
// the steamid parameter does not necessarily specify the current user, so add it only when it's not already set |
155
|
|
|
if(strpos(parse_url($uri, PHP_URL_QUERY), 'steamid=') === false){ // php8: str_contains |
156
|
|
|
$params['steamid']= $token->accessToken; |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
return $request->withUri($this->uriFactory->createUri(merge_query($uri, $params))); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
} |
163
|
|
|
|