├── .github
└── workflows
│ ├── psalm.yml
│ └── tests.yml
├── .gitignore
├── LICENSE
├── README.md
├── UPGRADE.md
├── composer.json
├── config
└── steam-auth.php
├── phpunit.xml
├── psalm.xml
├── src
├── Exceptions
│ ├── Authentication
│ │ ├── AuthenticationException.php
│ │ ├── SteamIdNotFoundAuthenticationException.php
│ │ └── SteamResponseNotValidAuthenticationException.php
│ └── Validation
│ │ ├── InvalidQueryValidationException.php
│ │ ├── InvalidReturnToValidationException.php
│ │ └── ValidationException.php
├── ServiceProvider.php
├── SteamAuthenticator.php
└── SteamUserDto.php
└── tests
├── AuthValidationTest.php
├── BuildAuthUrlTest.php
├── SteamResponsesTest.php
└── TestCase.php
/.github/workflows/psalm.yml:
--------------------------------------------------------------------------------
1 | name: Psalm Static Analysis
2 |
3 | on:
4 | push:
5 | paths:
6 | - '**.php'
7 | - 'psalm.xml'
8 |
9 | jobs:
10 | psalm:
11 | name: Psalm
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout Code
15 | uses: actions/checkout@v2
16 |
17 | - name: Setup PHP
18 | uses: shivammathur/setup-php@v2
19 | with:
20 | php-version: '8.2'
21 |
22 | - name: Install Dependencies
23 | run: |
24 | php -v
25 | composer install --prefer-dist --no-interaction
26 |
27 | - name: Run Psalm
28 | run: ./vendor/bin/psalm
29 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | tests:
7 | name: PHP ${{ matrix.php }}, Laravel ${{ matrix.laravel }}
8 | runs-on: ubuntu-latest
9 |
10 | strategy:
11 | matrix:
12 | php: [8.1, 8.2]
13 | laravel: [9.*, 10.*, 11.*, 12.*]
14 |
15 | steps:
16 | - name: Checkout Code
17 | uses: actions/checkout@v2
18 |
19 | - name: Setup PHP
20 | uses: shivammathur/setup-php@v2
21 | with:
22 | php-version: ${{ matrix.php }}
23 |
24 | - name: Install Dependencies
25 | run: |
26 | php -v
27 | composer install --prefer-dist --no-interaction
28 |
29 | - name: Execute Tests
30 | run: XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-clover coverage.xml
31 |
32 | - name: Upload coverage reports to Codecov
33 | uses: codecov/codecov-action@v3
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/
2 | /composer.lock
3 | /vendor/
4 | /.phpunit.cache/
5 | /.phpunit.result.cache
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Ilia Lazarev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Steam Auth for Laravel
2 | [](https://packagist.org/packages/ilzrv/laravel-steam-auth)
3 | [](https://packagist.org/packages/ilzrv/laravel-steam-auth)
4 | [](https://github.com/ilzrv/laravel-steam-auth/actions/workflows/tests.yml)
5 | [](https://app.codecov.io/github/ilzrv/laravel-steam-auth)
6 | [](https://packagist.org/packages/ilzrv/laravel-steam-auth)
7 |
8 | Package allows you to implement Steam authentication in your Laravel project.
9 |
10 | ## Requirements
11 | * Laravel 9+
12 | * PHP 8.1+
13 |
14 | ## Installation
15 | #### Install the package
16 | ```bash
17 | composer require ilzrv/laravel-steam-auth
18 | ```
19 |
20 | #### Publish the config file
21 | ```bash
22 | php artisan vendor:publish --provider="Ilzrv\LaravelSteamAuth\ServiceProvider"
23 | ```
24 |
25 | #### Setup Steam API Key(s)
26 |
27 | Add your Steam API key to your `.env` file. You can find it [here](https://steamcommunity.com/dev/apikey).
28 |
29 | *if you want to use multiple API keys just list them separated by commas*
30 |
31 | ```
32 | STEAM_AUTH_API_KEYS=YourSteamApiKey1,YourSteamApiKey2
33 | ```
34 |
35 | ## Tips
36 |
37 | #### Client Settings
38 | You can use any settings that your client supports, for example, a [Guzzle Proxy](https://docs.guzzlephp.org/en/latest/request-options.html#proxy):
39 |
40 | ```php
41 | 'socks5://user:password@192.168.1.1:1080',
56 | ]);
57 |
58 | $steamAuthenticator = new SteamAuthenticator(
59 | new Uri($request->getUri()),
60 | $client,
61 | $httpFactory,
62 | );
63 |
64 | // Continuation of your code...
65 | }
66 | ```
67 |
68 | #### Proxy Domain
69 | If you want to make a proxy domain. Update `redirect_url` inside `steam-auth.php` to your absolute address like `https://auth.test/login`. You can use different domains for the local environment and for production like this:
70 |
71 | ```php
72 | env('APP_ENV', 'production') == 'production'
78 | ? 'https://auth.test/login'
79 | : null,
80 | ];
81 | ```
82 |
83 | In the NGINX settings for proxy domain, you can specify the following:
84 | ```
85 | server {
86 | listen 443 ssl http2;
87 | server_name auth.test;
88 | return 301 https://general.test$uri$is_args$args;
89 | }
90 | ```
91 |
92 | ## Basic example
93 |
94 | In `routes/web.php`:
95 |
96 | ```php
97 | Route::get('login', \App\Http\Controllers\Auth\SteamAuthController::class);
98 | ```
99 |
100 | Create a controller `SteamAuthController.php`:
101 |
102 | ```php
103 | getUri()),
133 | $client,
134 | $httpFactory,
135 | );
136 |
137 | try {
138 | $steamAuthenticator->auth();
139 | } catch (ValidationException|SteamResponseNotValidAuthenticationException) {
140 | return $redirector->to(
141 | $steamAuthenticator->buildAuthUrl()
142 | );
143 | }
144 |
145 | $steamUser = $steamAuthenticator->getSteamUser();
146 |
147 | $authManager->login(
148 | $this->firstOrCreate($steamUser),
149 | true
150 | );
151 |
152 | return $redirector->to('/');
153 | }
154 |
155 | private function firstOrCreate(SteamUserDto $steamUser): User
156 | {
157 | return User::firstOrCreate([
158 | 'steam_id' => $steamUser->getSteamId(),
159 | ], [
160 | 'name' => $steamUser->getPersonaName(),
161 | 'avatar' => $steamUser->getAvatarFull(),
162 | 'player_level' => $steamUser->getPlayerLevel(),
163 | // ...and other what you need
164 | ]);
165 | }
166 | }
167 | ```
168 |
--------------------------------------------------------------------------------
/UPGRADE.md:
--------------------------------------------------------------------------------
1 | # Upgrade guide
2 |
3 | ## 2.0 to 3.0
4 | - You should completely redefine the authentication process according to the README (for example your controller)
5 | - The configuration remains the same
6 | - Now the authenticator uses PSR abstractions
7 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ilzrv/laravel-steam-auth",
3 | "description": "Steam Auth for Laravel",
4 | "require": {
5 | "php": "^8.1",
6 | "illuminate/support": "^9.0|^10.0|^11.0|^12.0",
7 | "psr/http-message": "^2.0",
8 | "psr/http-client": "^1.0",
9 | "psr/http-factory": "^1.0"
10 | },
11 | "require-dev": {
12 | "roave/security-advisories": "dev-latest",
13 | "phpunit/phpunit": "^10.0|^11.0",
14 | "orchestra/testbench": "7.x|^8.5",
15 | "vimeo/psalm": "^5.12"
16 | },
17 | "license": "MIT",
18 | "authors": [
19 | {
20 | "name": "Ilia Lazarev",
21 | "email": "me@ilzrv.com"
22 | }
23 | ],
24 | "autoload": {
25 | "psr-4": {
26 | "Ilzrv\\LaravelSteamAuth\\": "src"
27 | }
28 | },
29 | "autoload-dev": {
30 | "psr-4": {
31 | "Ilzrv\\LaravelSteamAuth\\Tests\\": "tests/"
32 | }
33 | },
34 | "extra": {
35 | "laravel": {
36 | "providers": [
37 | "Ilzrv\\LaravelSteamAuth\\ServiceProvider"
38 | ]
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/config/steam-auth.php:
--------------------------------------------------------------------------------
1 | null,
16 |
17 | /*
18 | |--------------------------------------------------------------------------
19 | | Getting Steam User Level
20 | |--------------------------------------------------------------------------
21 | |
22 | | Defines need to get the user level.
23 | |
24 | | This makes an additional request in the Steam API.
25 | |
26 | */
27 | 'getting_level' => false,
28 |
29 | /*
30 | |--------------------------------------------------------------------------
31 | | Steam API Keys
32 | |--------------------------------------------------------------------------
33 | |
34 | | List of Steam API keys for reducing
35 | | requests from a single key.
36 | |
37 | */
38 | 'api_keys' => explode(',', env('STEAM_AUTH_API_KEYS')),
39 |
40 | ];
41 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | tests
15 |
16 |
17 |
18 |
19 |
20 | src
21 |
22 |
23 | src/SteamUserDto.php
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/psalm.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/Exceptions/Authentication/AuthenticationException.php:
--------------------------------------------------------------------------------
1 | mergeConfigFrom(__DIR__ . '/../config/steam-auth.php', 'steam-auth');
15 | }
16 |
17 | /**
18 | * Bootstrap any application services.
19 | */
20 | public function boot(): void
21 | {
22 | $this->publishes([
23 | __DIR__ . '/../config/steam-auth.php' => $this->app->configPath('steam-auth.php'),
24 | ]);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/SteamAuthenticator.php:
--------------------------------------------------------------------------------
1 | validateRequest();
45 | $this->validateReturnToUrl();
46 |
47 | $response = $this->httpClient->sendRequest(
48 | $this->requestFactory->createRequest('GET', self::OPENID_URL . '?' . $this->buildOpenIdRequestQuery()),
49 | );
50 |
51 | $contents = $response->getBody()->getContents();
52 |
53 | if (preg_match("#is_valid\s*:\s*true#i", $contents) !== 1) {
54 | throw new SteamResponseNotValidAuthenticationException(
55 | sprintf('Steam response contains invalid content: "%s"', $contents)
56 | );
57 | }
58 |
59 | $query = $this->parseUriQueryString();
60 |
61 | preg_match(
62 | "#^https?://steamcommunity.com/openid/id/([0-9]{17,25})#",
63 | $query['openid_claimed_id'],
64 | $matches
65 | );
66 |
67 | if (!isset($matches[1]) || !is_numeric($matches[1])) {
68 | throw new SteamIdNotFoundAuthenticationException();
69 | }
70 |
71 | $this->loadSteamUser($matches[1]);
72 | }
73 |
74 | /**
75 | * @throws ClientExceptionInterface
76 | * @throws JsonException
77 | */
78 | private function loadSteamUser(string $steamId): void
79 | {
80 | $steamDataResponse = $this->httpClient->sendRequest(
81 | $this->requestFactory->createRequest('GET', sprintf(self::STEAM_DATA_URL, $this->getApiKey(), $steamId)),
82 | );
83 |
84 | $steamData = json_decode(
85 | $steamDataResponse->getBody()->getContents(),
86 | true,
87 | 512,
88 | JSON_THROW_ON_ERROR
89 | )['response']['players'][0];
90 |
91 | if (config('steam-auth.getting_level')) {
92 | $userLevelResponse = $this->httpClient->sendRequest(
93 | $this->requestFactory->createRequest(
94 | 'GET',
95 | sprintf(self::STEAM_LEVEL_URL, $this->getApiKey(), $steamId)
96 | )
97 | );
98 |
99 | $steamData = array_merge(
100 | $steamData,
101 | json_decode($userLevelResponse->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR)['response']
102 | );
103 | }
104 |
105 | $this->steamUserDto = SteamUserDto::create($steamData);
106 | }
107 |
108 | private function getApiKey(): string
109 | {
110 | $apiKeys = config('steam-auth.api_keys');
111 |
112 | return $apiKeys[array_rand($apiKeys)];
113 | }
114 |
115 | private function buildOpenIdRequestQuery(): string
116 | {
117 | $query = $this->parseUriQueryString();
118 |
119 | $params = [
120 | 'openid.assoc_handle' => $query['openid_assoc_handle'],
121 | 'openid.signed' => $query['openid_signed'],
122 | 'openid.sig' => $query['openid_sig'],
123 | 'openid.ns' => 'http://specs.openid.net/auth/2.0',
124 | 'openid.mode' => 'check_authentication',
125 | ];
126 |
127 | $signed = explode(',', $query['openid_signed']);
128 |
129 | foreach ($signed as $item) {
130 | $params['openid.' . $item] = $query['openid_' . str_replace('.', '_', $item)] ?? null;
131 | }
132 |
133 | return http_build_query($params);
134 | }
135 |
136 | public function getSteamUser(): ?SteamUserDto
137 | {
138 | return $this->steamUserDto;
139 | }
140 |
141 | /**
142 | * @throws InvalidQueryValidationException
143 | */
144 | private function validateRequest(): void
145 | {
146 | $query = $this->parseUriQueryString();
147 |
148 | $params = [
149 | 'openid_assoc_handle',
150 | 'openid_signed',
151 | 'openid_sig',
152 | 'openid_return_to',
153 | 'openid_claimed_id',
154 | ];
155 |
156 | foreach ($params as $param) {
157 | if (!isset($query[$param])) {
158 | throw InvalidQueryValidationException::invalidQuery($param);
159 | }
160 | }
161 | }
162 |
163 | /**
164 | * @throws InvalidReturnToValidationException
165 | */
166 | private function validateReturnToUrl(): void
167 | {
168 | $query = $this->parseUriQueryString();
169 |
170 | if ($this->buildRedirectUrl() !== $query['openid_return_to']) {
171 | throw InvalidReturnToValidationException::invalidReturnTo();
172 | }
173 | }
174 |
175 | private function parseUriQueryString(): array
176 | {
177 | parse_str($this->requestUri->getQuery(), $result);
178 |
179 | return $result;
180 | }
181 |
182 | public function buildAuthUrl(): string
183 | {
184 | $redirectUrl = $this->buildRedirectUrl();
185 |
186 | $params = [
187 | 'openid.ns' => 'http://specs.openid.net/auth/2.0',
188 | 'openid.mode' => 'checkid_setup',
189 | 'openid.return_to' => $redirectUrl,
190 | 'openid.realm' => parse_url($redirectUrl, PHP_URL_SCHEME) . '://' . parse_url($redirectUrl, PHP_URL_HOST),
191 | 'openid.identity' => 'http://specs.openid.net/auth/2.0/identifier_select',
192 | 'openid.claimed_id' => 'http://specs.openid.net/auth/2.0/identifier_select',
193 | ];
194 |
195 | return self::OPENID_URL . '?' . http_build_query($params, '', '&');
196 | }
197 |
198 | private function buildRedirectUrl(): string
199 | {
200 | $redirectUrl = config('steam-auth.redirect_url');
201 |
202 | if (is_string($redirectUrl) && is_string($buildRedirectUrl = url($redirectUrl))) {
203 | return $buildRedirectUrl;
204 | }
205 |
206 | return $this->requestUri->getScheme()
207 | . '://'
208 | . $this->requestUri->getAuthority()
209 | . $this->requestUri->getPath();
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/SteamUserDto.php:
--------------------------------------------------------------------------------
1 | steamId;
56 | }
57 |
58 | public function getCommunityVisibilityState(): ?int
59 | {
60 | return $this->communityVisibilityState;
61 | }
62 |
63 | public function getProfileState(): ?int
64 | {
65 | return $this->profileState;
66 | }
67 |
68 | public function getPersonaName(): ?string
69 | {
70 | return $this->personaName;
71 | }
72 |
73 | public function getCommentPermission(): ?int
74 | {
75 | return $this->commentPermission;
76 | }
77 |
78 | public function getProfileUrl(): ?string
79 | {
80 | return $this->profileUrl;
81 | }
82 |
83 | public function getAvatar(): ?string
84 | {
85 | return $this->avatar;
86 | }
87 |
88 | public function getAvatarMedium(): ?string
89 | {
90 | return $this->avatarMedium;
91 | }
92 |
93 | public function getAvatarFull(): ?string
94 | {
95 | return $this->avatarFull;
96 | }
97 |
98 | public function getAvatarHash(): ?string
99 | {
100 | return $this->avatarHash;
101 | }
102 |
103 | public function getLastLogoff(): ?int
104 | {
105 | return $this->lastLogoff;
106 | }
107 |
108 | public function getPersonaState(): ?int
109 | {
110 | return $this->personaState;
111 | }
112 |
113 | public function getPrimaryClanId(): ?string
114 | {
115 | return $this->primaryClanId;
116 | }
117 |
118 | public function getTimeCreated(): ?int
119 | {
120 | return $this->timeCreated;
121 | }
122 |
123 | public function getPersonaStateFlags(): ?int
124 | {
125 | return $this->personaStateFlags;
126 | }
127 |
128 | public function getLocCountryCode(): ?string
129 | {
130 | return $this->locCountryCode;
131 | }
132 |
133 | public function getPlayerLevel(): ?int
134 | {
135 | return $this->playerLevel;
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/tests/AuthValidationTest.php:
--------------------------------------------------------------------------------
1 | createMock(UriInterface::class);
33 | $uri->expects($this->once())->method('getQuery')->willReturn($query);
34 |
35 | $steamAuth = new SteamAuthenticator(
36 | $uri,
37 | $this->createMock(ClientInterface::class),
38 | $this->createMock(RequestFactoryInterface::class),
39 | );
40 |
41 | $this->expectException(InvalidQueryValidationException::class);
42 | $this->expectExceptionMessage('The "' . $param . '" parameter is required');
43 |
44 | $steamAuth->auth();
45 | }
46 |
47 | public static function provideRequiredParams(): array
48 | {
49 | return [
50 | ['openid_assoc_handle', self::buildHttpQuery('openid_assoc_handle')],
51 | ['openid_signed', self::buildHttpQuery('openid_signed')],
52 | ['openid_sig', self::buildHttpQuery('openid_sig')],
53 | ['openid_return_to', self::buildHttpQuery('openid_return_to')],
54 | ['openid_claimed_id', self::buildHttpQuery('openid_claimed_id')],
55 | ];
56 | }
57 |
58 | /**
59 | * @throws Exception
60 | * @throws ClientExceptionInterface
61 | * @throws InvalidQueryValidationException
62 | * @throws AuthenticationException
63 | * @throws JsonException
64 | */
65 | public function testValidateReturnToUrl(): void
66 | {
67 | $uri = $this->createMock(UriInterface::class);
68 | $uri->expects($this->exactly(2))->method('getQuery')->willReturn(self::buildHttpQuery());
69 |
70 | $steamAuth = new SteamAuthenticator(
71 | $uri,
72 | $this->createMock(ClientInterface::class),
73 | $this->createMock(RequestFactoryInterface::class),
74 | );
75 |
76 | $this->expectException(InvalidReturnToValidationException::class);
77 | $this->expectExceptionMessage('openid_return_to does not match redirect url');
78 |
79 | $steamAuth->auth();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/tests/BuildAuthUrlTest.php:
--------------------------------------------------------------------------------
1 | app['config']->set('steam-auth.redirect_url', null);
16 |
17 | $steamAuthenticator = new SteamAuthenticator(
18 | $this->createUriMock('example.test'),
19 | $this->createMock(ClientInterface::class),
20 | $this->createMock(RequestFactoryInterface::class),
21 | );
22 |
23 | $uri = 'https://steamcommunity.com/openid/login?openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=checkid_setup&openid.return_to=https%3A%2F%2Fexample.test%2Flogin&openid.realm=https%3A%2F%2Fexample.test&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select';
24 |
25 | $this->assertSame(
26 | $uri,
27 | $steamAuthenticator->buildAuthUrl()
28 | );
29 | }
30 |
31 | public function testAuthUrlWithRedirectUrl(): void
32 | {
33 | $this->app['config']->set('steam-auth.redirect_url', 'https://used-example.test/login');
34 |
35 | $steamAuthenticator = new SteamAuthenticator(
36 | $this->createUriMock('unused-example.test'),
37 | $this->createMock(ClientInterface::class),
38 | $this->createMock(RequestFactoryInterface::class),
39 | );
40 |
41 | $uri = 'https://steamcommunity.com/openid/login?openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=checkid_setup&openid.return_to=https%3A%2F%2Fused-example.test%2Flogin&openid.realm=https%3A%2F%2Fused-example.test&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select';
42 |
43 | $this->assertSame(
44 | $uri,
45 | $steamAuthenticator->buildAuthUrl()
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/SteamResponsesTest.php:
--------------------------------------------------------------------------------
1 | createResponseMock(
22 | <<createMock(ClientInterface::class);
29 | $client->method('sendRequest')->willReturn($response);
30 |
31 | $steamAuthenticator = new SteamAuthenticator(
32 | $this->createUriMock('example.test'),
33 | $client,
34 | $this->createMock(RequestFactoryInterface::class),
35 | );
36 |
37 | $this->expectException(SteamResponseNotValidAuthenticationException::class);
38 |
39 | $steamAuthenticator->auth();
40 | }
41 |
42 | public function testSteamIdNotFoundResponse(): void
43 | {
44 | $response = $this->createResponseMock(
45 | <<createMock(ClientInterface::class);
52 | $client->method('sendRequest')->willReturn($response);
53 |
54 | $steamAuthenticator = new SteamAuthenticator(
55 | $this->createUriMock('example.test'),
56 | $client,
57 | $this->createMock(RequestFactoryInterface::class),
58 | );
59 |
60 | $this->expectException(SteamIdNotFoundAuthenticationException::class);
61 |
62 | $steamAuthenticator->auth();
63 | }
64 |
65 | public function testValidSteamResponseWithoutPlayerLevel(): void
66 | {
67 | $this->app['config']->set('steam-auth.getting_level', false);
68 |
69 | $response1 = $this->createResponseMock(
70 | <<createResponseMock(
77 | <<createMock(ClientInterface::class);
83 | $client->method('sendRequest')->willReturnOnConsecutiveCalls($response1, $response2);
84 |
85 | $steamAuthenticator = new SteamAuthenticator(
86 | $this->createUriMockWithOpenidClaimedId('76561198019153518'),
87 | $client,
88 | $this->createMock(RequestFactoryInterface::class),
89 | );
90 |
91 | $steamAuthenticator->auth();
92 |
93 | $this->assertInstanceOf(SteamUserDto::class, $steamAuthenticator->getSteamUser());
94 | }
95 |
96 | public function testValidSteamResponseWithPlayerLevel(): void
97 | {
98 | $this->app['config']->set('steam-auth.getting_level', true);
99 |
100 | $response1 = $this->createResponseMock(
101 | <<createResponseMock(
108 | <<createResponseMock(
114 | <<createMock(ClientInterface::class);
120 | $client->method('sendRequest')->willReturnOnConsecutiveCalls($response1, $response2, $response3);
121 |
122 | $steamAuthenticator = new SteamAuthenticator(
123 | $this->createUriMockWithOpenidClaimedId('76561198019153518'),
124 | $client,
125 | $this->createMock(RequestFactoryInterface::class),
126 | );
127 |
128 | $steamAuthenticator->auth();
129 |
130 | $this->assertInstanceOf(SteamUserDto::class, $steamAuthenticator->getSteamUser());
131 | $this->assertSame(44, $steamAuthenticator->getSteamUser()->getPlayerLevel());
132 | }
133 |
134 | private function createResponseMock(string $contents): ResponseInterface
135 | {
136 | $body = $this->createMock(StreamInterface::class);
137 | $body->method('getContents')->willReturn($contents);
138 |
139 | $response = $this->createMock(ResponseInterface::class);
140 | $response->method('getBody')->willReturn($body);
141 |
142 | return $response;
143 | }
144 |
145 | private function createUriMockWithOpenidClaimedId(string $steamId): UriInterface
146 | {
147 | $uri = $this->createMock(UriInterface::class);
148 |
149 | $httpQuery = self::buildHttpQuery(null, [
150 | 'openid_return_to' => 'https://example.test/login',
151 | 'openid_claimed_id' => 'https://steamcommunity.com/openid/id/' . $steamId,
152 | ]);
153 |
154 | $uri->method('getScheme')->willReturn('https');
155 | $uri->method('getAuthority')->willReturn('example.test');
156 | $uri->method('getPath')->willReturn('/login');
157 | $uri->method('getQuery')->willReturn($httpQuery);
158 |
159 | return $uri;
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | >
19 | */
20 | protected function getPackageProviders($app)
21 | {
22 | return [
23 | ServiceProvider::class,
24 | ];
25 | }
26 |
27 | protected static function buildHttpQuery(
28 | string $without = null,
29 | array $replace = [],
30 | ): string {
31 | $params = [
32 | 'openid_assoc_handle' => 'data',
33 | 'openid_signed' => 'data',
34 | 'openid_sig' => 'data',
35 | 'openid_return_to' => 'data',
36 | 'openid_claimed_id' => 'data',
37 | ];
38 |
39 | $params = array_replace($params, $replace);
40 |
41 | unset($params[$without]);
42 |
43 | return http_build_query($params);
44 | }
45 |
46 | /**
47 | * @throws Exception
48 | */
49 | protected function createUriMock(
50 | string $authority,
51 | ): UriInterface {
52 | $uri = $this->createMock(UriInterface::class);
53 |
54 | $uri->method('getScheme')->willReturn('https');
55 | $uri->method('getAuthority')->willReturn($authority);
56 | $uri->method('getPath')->willReturn('/login');
57 | $uri->method('getQuery')->willReturn(
58 | self::buildHttpQuery(null, ['openid_return_to' => "https://$authority/login"])
59 | );
60 |
61 | return $uri;
62 | }
63 | }
64 |
65 |
--------------------------------------------------------------------------------