Skip to content

Commit b09def2

Browse files
authored
Merge branch 'master' into feat/26-package-routes-controllers
2 parents 8381081 + 3488158 commit b09def2

File tree

10 files changed

+187
-58
lines changed

10 files changed

+187
-58
lines changed

.github/workflows/tests.yml

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,44 @@ on:
77
branches: [master]
88

99
jobs:
10-
test:
10+
tests:
1111
runs-on: ubuntu-latest
1212

1313
strategy:
1414
fail-fast: false
1515
matrix:
1616
php: ['8.2', '8.3', '8.4']
17-
laravel: ['12.*']
18-
# Laravel 10-11 excluded: testbench compatibility issues with Redis/cache in CI
19-
20-
name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}
17+
laravel: ['^10.0', '^11.0', '^12.0', '^13.0']
18+
include:
19+
- laravel: '^10.0'
20+
testbench: '^8.0'
21+
- laravel: '^11.0'
22+
testbench: '^9.0'
23+
- laravel: '^12.0'
24+
testbench: '^10.0'
25+
- laravel: '^13.0'
26+
testbench: '^11.0'
27+
exclude:
28+
- php: '8.2'
29+
laravel: '^13.0'
30+
31+
name: PHP ${{ matrix.php }} – Laravel ${{ matrix.laravel }}
2132

2233
steps:
23-
- uses: actions/checkout@v4
34+
- name: Checkout
35+
uses: actions/checkout@v4
2436

2537
- name: Setup PHP
2638
uses: shivammathur/setup-php@v2
2739
with:
2840
php-version: ${{ matrix.php }}
29-
extensions: dom, curl, libxml, mbstring, zip
41+
extensions: mbstring, json
3042
coverage: none
3143

3244
- name: Install dependencies
3345
run: |
34-
composer require "illuminate/support:${{ matrix.laravel }}" --no-interaction --no-update
46+
composer require "illuminate/support:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-update
3547
composer update --prefer-dist --no-interaction --no-progress
3648
3749
- name: Run tests
38-
run: vendor/bin/phpunit --testsuite Unit
50+
run: vendor/bin/phpunit --testsuite=Unit

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ composer.lock
44
phpmd.xml
55
phpunit.xml
66
/tests/Browser/screenshots
7+
.phpunit.cache/

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## [Unreleased]
8+
### Added
9+
- Laravel 13 support.
10+
11+
### Fixed
12+
- Composer dependency constraints for `orchestra/testbench-browser-kit` and `orchestra/testbench-dusk` (added missing `^9.0` for Laravel 11 compatibility).
13+
714
## [0.4.4] - 2020-09-04
815
### Changed
916
- storing of `access_token` to `id_token`.

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,20 @@ We thank the following sponsors for their generosity, please take a moment to ch
2121
<a name="Requirements"></a>
2222
## Requirements
2323

24-
- PHP 7.3+
25-
- Laravel 8.0+
24+
- PHP 8.2+
25+
- Laravel 10.0+
2626
- Socialite 5.0+
2727
- Apple Developer Subscription
2828

29+
### Version Support
30+
31+
| Laravel | PHP | Package |
32+
|---------|-----------|----------|
33+
| 10.x | 8.2+ | 5.x |
34+
| 11.x | 8.2+ | 5.x |
35+
| 12.x | 8.2+ | 5.x |
36+
| 13.x | 8.3+ | 5.x |
37+
2938
<a name="Installation"></a>
3039
## Installation
3140

composer.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@
1616
"genealabs/laravel-socialiter": "Automatic user resolution and persistence for any Laravel Socialite driver."
1717
},
1818
"require": {
19-
"php": "^8.1",
20-
"illuminate/support": "^10.0|^11.0|^12.0",
19+
"php": "^8.2",
20+
"illuminate/support": "^10.0|^11.0|^12.0|^13.0",
2121
"laravel/socialite": "^5.6"
2222
},
2323
"require-dev": {
24-
"orchestra/testbench-browser-kit": "^7.12|^8.5|^10.0",
25-
"orchestra/testbench-dusk": "^7.20|^8.22|^10.0",
26-
"orchestra/testbench": "^8.0|^9.0|^10.0",
27-
"predis/predis": "^2.1",
28-
"phpunit/phpunit": "^9.5.10|^10.5|^11.5.3"
24+
"orchestra/testbench-browser-kit": "^8.5|^9.0|^10.0|^11.0",
25+
"orchestra/testbench-dusk": "^8.22|^9.0|^10.0|^11.0",
26+
"orchestra/testbench": "^8.0|^9.0|^10.0|^11.0",
27+
"predis/predis": "^2.1|^3.4",
28+
"phpunit/phpunit": "^9.5.10|^10.5|^11.5.3|^12.5.12"
2929
},
3030
"autoload": {
3131
"psr-4": {

phpunit.xml.dist

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,22 @@
22
<phpunit
33
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
44
backupGlobals="false"
5-
backupStaticAttributes="false"
65
bootstrap="vendor/autoload.php"
76
colors="true"
8-
convertErrorsToExceptions="true"
9-
convertNoticesToExceptions="true"
10-
convertWarningsToExceptions="true"
117
processIsolation="false"
128
stopOnFailure="true"
13-
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
9+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.5/phpunit.xsd"
10+
cacheDirectory=".phpunit.cache"
1411
>
15-
<coverage processUncoveredFiles="false">
12+
<source>
1613
<include>
1714
<directory suffix=".php">./src</directory>
1815
</include>
19-
</coverage>
16+
</source>
2017
<testsuites>
2118
<testsuite name="Browser">
2219
<directory suffix="Test.php">./tests/Browser</directory>
2320
</testsuite>
24-
<testsuite name="Feature">
25-
<directory suffix="Test.php">./tests/Feature</directory>
26-
</testsuite>
2721
<testsuite name="Unit">
2822
<directory suffix="Test.php">./tests/Unit</directory>
2923
</testsuite>
@@ -32,12 +26,11 @@
3226
<env name="APP_KEY" value="base64:Xgs1LQt1GdVHhD6qyYCXnyq61DE3UKqJ5k2SJc+Nw2g="/>
3327
<env name="APP_ENV" value="testing"/>
3428
<env name="APP_URL" value="http://localhost"/>
35-
<env name="CACHE_DRIVER" value="redis"/>
29+
<env name="CACHE_DRIVER" value="array"/>
3630
<env name="SESSION_DRIVER" value="array"/>
3731
<env name="QUEUE_DRIVER" value="sync"/>
3832
<env name="DB_CONNECTION" value="sqlite"/>
3933
<env name="DB_DATABASE" value=":memory:"/>
40-
<env name="REDIS_HOST" value="127.0.0.1"/>
4134
<env name="SIGN_IN_WITH_APPLE_LOGIN" value="/siwa-login"/>
4235
<env name="SIGN_IN_WITH_APPLE_REDIRECT" value="http://testing.dev/siwa-callback"/>
4336
<env name="SIGN_IN_WITH_APPLE_CLIENT_ID" value="add-your-own"/>

src/Providers/ServiceProvider.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ protected function loadRoutesIf(bool $enabled): void
4444
public function bootSocialiteDriver()
4545
{
4646
$socialite = $this->app->make(Factory::class);
47+
$serviceProvider = $this;
4748
$socialite->extend(
4849
'sign-in-with-apple',
49-
function ($app) use ($socialite) {
50+
function ($app) use ($socialite, $serviceProvider) {
5051
$config = $app['config']['services.sign_in_with_apple'];
5152

52-
$this->validateAppleConfig($config);
53+
$serviceProvider->validateAppleConfig($config);
5354

5455
return $socialite
5556
->buildProvider(SignInWithAppleProvider::class, $config);
@@ -62,7 +63,7 @@ function ($app) use ($socialite) {
6263
*
6364
* @throws InvalidAppleCredentialsException
6465
*/
65-
protected function validateAppleConfig(?array $config): void
66+
public function validateAppleConfig(?array $config): void
6667
{
6768
if (empty($config)) {
6869
throw new InvalidAppleCredentialsException(

src/Providers/SignInWithAppleProvider.php

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use GeneaLabs\LaravelSignInWithApple\Exceptions\InvalidRedirectUrlException;
66
use GeneaLabs\LaravelSignInWithApple\Exceptions\InvalidAppleCredentialsException;
77
use GuzzleHttp\Exception\ClientException;
8+
use GuzzleHttp\Exception\ServerException;
89
use Illuminate\Support\Arr;
910
use Laravel\Socialite\Two\AbstractProvider;
1011
use Laravel\Socialite\Two\InvalidStateException;
@@ -108,34 +109,11 @@ public function getAccessTokenResponse($code)
108109
return parent::getAccessTokenResponse($code);
109110
} catch (ClientException $e) {
110111
$this->handleTokenError($e);
112+
} catch (ServerException $e) {
113+
$this->handleServerError($e);
111114
}
112115
}
113116

114-
public function getAccessToken($code)
115-
{
116-
$response = $this->getHttpClient()
117-
->post(
118-
$this->getTokenUrl(),
119-
[
120-
'headers' => [
121-
'Authorization' => 'Basic '. base64_encode(
122-
$this->clientId . ':' . $this->clientSecret
123-
),
124-
],
125-
'body' => $this->getTokenFields($code),
126-
]
127-
);
128-
129-
return $this->parseAccessToken($response->getBody());
130-
}
131-
132-
protected function parseAccessToken($response)
133-
{
134-
$data = $response->json();
135-
136-
return $data['access_token'];
137-
}
138-
139117
protected function getTokenFields($code)
140118
{
141119
$fields = parent::getTokenFields($code);
@@ -206,6 +184,28 @@ protected function mapUserToObject(array $user)
206184
]);
207185
}
208186

187+
/**
188+
* Handle a ServerException (5xx) from the Apple token endpoint.
189+
*
190+
* Apple's servers occasionally return 500 errors. This wraps them
191+
* in a descriptive exception so apps can handle them gracefully.
192+
*
193+
* @throws \RuntimeException
194+
*/
195+
protected function handleServerError(ServerException $exception): never
196+
{
197+
$statusCode = $exception->getResponse()->getStatusCode();
198+
199+
throw new \RuntimeException(
200+
"Apple Sign In is temporarily unavailable (HTTP {$statusCode}). "
201+
. 'Apple\'s authentication servers returned a server error. '
202+
. 'This is typically a temporary issue on Apple\'s side. '
203+
. 'Please try again in a few minutes.',
204+
$statusCode,
205+
$exception,
206+
);
207+
}
208+
209209
/**
210210
* Handle a ClientException from the Apple token endpoint.
211211
*
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace GeneaLabs\LaravelSignInWithApple\Tests\Unit;
4+
5+
use GeneaLabs\LaravelSignInWithApple\Providers\SignInWithAppleProvider;
6+
use GeneaLabs\LaravelSignInWithApple\Tests\UnitTestCase;
7+
use GuzzleHttp\Exception\ServerException;
8+
use GuzzleHttp\Psr7\Response;
9+
use Illuminate\Http\Request;
10+
use ReflectionMethod;
11+
12+
class ServerErrorHandlingTest extends UnitTestCase
13+
{
14+
protected function makeProvider(): SignInWithAppleProvider
15+
{
16+
return new SignInWithAppleProvider(
17+
Request::create('/'),
18+
'test-client-id',
19+
'test-client-secret',
20+
'https://example.com/callback'
21+
);
22+
}
23+
24+
public function testHandles500ServerError(): void
25+
{
26+
$provider = $this->makeProvider();
27+
28+
$response = new Response(500, [], 'Internal Server Error');
29+
$exception = new ServerException('Server error', new \GuzzleHttp\Psr7\Request('POST', '/'), $response);
30+
31+
$method = new ReflectionMethod($provider, 'handleServerError');
32+
$method->setAccessible(true);
33+
34+
try {
35+
$method->invoke($provider, $exception);
36+
$this->fail('Expected RuntimeException');
37+
} catch (\RuntimeException $e) {
38+
$this->assertStringContainsString('temporarily unavailable', $e->getMessage());
39+
$this->assertStringContainsString('500', $e->getMessage());
40+
$this->assertSame($exception, $e->getPrevious());
41+
}
42+
}
43+
44+
public function testHandles503ServiceUnavailable(): void
45+
{
46+
$provider = $this->makeProvider();
47+
48+
$response = new Response(503, [], 'Service Unavailable');
49+
$exception = new ServerException('Server error', new \GuzzleHttp\Psr7\Request('POST', '/'), $response);
50+
51+
$method = new ReflectionMethod($provider, 'handleServerError');
52+
$method->setAccessible(true);
53+
54+
try {
55+
$method->invoke($provider, $exception);
56+
$this->fail('Expected RuntimeException');
57+
} catch (\RuntimeException $e) {
58+
$this->assertStringContainsString('503', $e->getMessage());
59+
$this->assertStringContainsString('try again', $e->getMessage());
60+
}
61+
}
62+
}

tests/Unit/ServiceProviderTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace GeneaLabs\LaravelSignInWithApple\Tests\Unit;
4+
5+
use GeneaLabs\LaravelSignInWithApple\Providers\ServiceProvider;
6+
use GeneaLabs\LaravelSignInWithApple\Providers\SignInWithAppleProvider;
7+
use GeneaLabs\LaravelSignInWithApple\Tests\UnitTestCase;
8+
use Illuminate\Support\Facades\Blade;
9+
use Laravel\Socialite\Contracts\Factory as SocialiteFactory;
10+
11+
class ServiceProviderTest extends UnitTestCase
12+
{
13+
public function test_service_provider_is_registered(): void
14+
{
15+
$this->assertArrayHasKey(
16+
ServiceProvider::class,
17+
$this->app->getLoadedProviders(),
18+
);
19+
}
20+
21+
public function test_config_is_merged(): void
22+
{
23+
$this->assertNotNull(config('services.sign_in_with_apple'));
24+
$this->assertArrayHasKey('login', config('services.sign_in_with_apple'));
25+
$this->assertArrayHasKey('redirect', config('services.sign_in_with_apple'));
26+
$this->assertArrayHasKey('client_id', config('services.sign_in_with_apple'));
27+
$this->assertArrayHasKey('client_secret', config('services.sign_in_with_apple'));
28+
}
29+
30+
public function test_socialite_driver_is_registered(): void
31+
{
32+
$socialite = $this->app->make(SocialiteFactory::class);
33+
$driver = $socialite->driver('sign-in-with-apple');
34+
35+
$this->assertInstanceOf(SignInWithAppleProvider::class, $driver);
36+
}
37+
38+
public function test_blade_directive_is_registered(): void
39+
{
40+
$directives = Blade::getCustomDirectives();
41+
42+
$this->assertArrayHasKey('signInWithApple', $directives);
43+
}
44+
}

0 commit comments

Comments
 (0)