diff --git a/.github/workflows/run-coverage.yml b/.github/workflows/run-coverage.yml index ccc2214..068625b 100644 --- a/.github/workflows/run-coverage.yml +++ b/.github/workflows/run-coverage.yml @@ -9,7 +9,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.0] + php: [8.1] dependency-version: [prefer-stable] name: P${{ matrix.php }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} diff --git a/.github/workflows/run-fix-code-style.yml b/.github/workflows/run-fix-code-style.yml index afbbe38..2f7a825 100644 --- a/.github/workflows/run-fix-code-style.yml +++ b/.github/workflows/run-fix-code-style.yml @@ -9,9 +9,9 @@ jobs: strategy: fail-fast: true matrix: - os: [ ubuntu-latest ] - php: [ 8.0 ] - dependency-version: [ prefer-stable ] + os: [ubuntu-latest] + php: [8.1] + dependency-version: [prefer-stable] env: COMPOSER_NO_INTERACTION: 1 diff --git a/.github/workflows/run-static-analysis.yml b/.github/workflows/run-static-analysis.yml index 6010fb3..e772888 100644 --- a/.github/workflows/run-static-analysis.yml +++ b/.github/workflows/run-static-analysis.yml @@ -1,6 +1,6 @@ name: Static Analysis -on: [push, pull_request] +on: [push, pull_request, workflow_dispatch] jobs: static-analysis: @@ -9,7 +9,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.0] + php: [8.1] dependency-version: [prefer-stable] name: P${{ matrix.php }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index c537bce..c05f949 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -1,6 +1,6 @@ name: Tests -on: [push, pull_request] +on: [push, pull_request, workflow_dispatch] jobs: test: @@ -9,7 +9,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [7.4, 8.0] + php: [8.0, 8.1] dependency-version: [prefer-lowest, prefer-stable] name: P${{ matrix.php }} - ${{ matrix.dependency-version }} - ${{ matrix.os }} diff --git a/.php_cs.dist b/.php-cs-fixer.dist.php similarity index 89% rename from .php_cs.dist rename to .php-cs-fixer.dist.php index 2083345..2f23997 100644 --- a/.php_cs.dist +++ b/.php-cs-fixer.dist.php @@ -7,7 +7,7 @@ $config = require __DIR__ . '/.php_cs.common.php'; -return PhpCsFixer\Config::create() +return (new PhpCsFixer\Config()) ->setFinder($finder) ->setRules($config) ->setRiskyAllowed(true) diff --git a/.php_cs.common.php b/.php_cs.common.php index 980f434..1b3d804 100644 --- a/.php_cs.common.php +++ b/.php_cs.common.php @@ -57,7 +57,9 @@ 'no_unused_imports' => true, 'single_quote' => true, 'space_after_semicolon' => true, - 'trailing_comma_in_multiline_array' => true, + 'trailing_comma_in_multiline' => [ + 'elements' => ['arrays'], + ], 'trim_array_spaces' => true, 'unary_operator_spaces' => true, 'whitespace_after_comma_in_array' => true, diff --git a/.php_cs.tests.php b/.php_cs.tests.php index 24c484d..b43109d 100644 --- a/.php_cs.tests.php +++ b/.php_cs.tests.php @@ -15,7 +15,7 @@ ] ); -return PhpCsFixer\Config::create() +return (new PhpCsFixer\Config()) ->setFinder($finder) ->setRules($config) ->setRiskyAllowed(true) diff --git a/README.md b/README.md index 1f3282c..5d24a0b 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,7 @@ Add [Laravel Sanctum](https://github.com/laravel/sanctum) support to [Lighthouse ## Requirements -- [laravel/laravel:^8.36.2](https://github.com/laravel/laravel) -- [laravel/sanctum:^2.0](https://github.com/laravel/sanctum) +- [laravel/laravel:^9.0](https://github.com/laravel/laravel) - [nuwave/lighthouse:^5.5](https://github.com/nuwave/lighthouse) ## Installation diff --git a/composer.json b/composer.json index b1bc6fc..6009232 100644 --- a/composer.json +++ b/composer.json @@ -1,15 +1,14 @@ { "name": "daniel-de-wit/lighthouse-sanctum", - "type": "library", "description": "Laravel Sanctum support for Laravel Lighthouse.", + "license": "MIT", + "type": "library", "keywords": [ "daniel-de-wit", "laravel-sanctum", "lighthouse", "lighthouse-sanctum" ], - "homepage": "https://github.com/daniel-de-wit/lighthouse-sanctum", - "license": "MIT", "authors": [ { "name": "Daniel de Wit", @@ -17,32 +16,24 @@ "role": "Developer" } ], + "homepage": "https://github.com/daniel-de-wit/lighthouse-sanctum", "require": { - "php": "^7.4 || ^8.0", - "laravel/framework": "^8.36.2", - "laravel/sanctum": "^2.10", + "php": "^8.0.2", + "laravel/framework": "^9.0", + "laravel/sanctum": "^2.14", "nuwave/lighthouse": "^5.5" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.18", - "mockery/mockery": "^1.3.3", - "nunomaduro/larastan": "^0.7.2", - "orchestra/testbench": "^6.5", - "orchestra/testbench-core": "^v6.23.1", - "phpstan/phpstan-mockery": "^0.12.13", - "phpstan/phpstan-phpunit": "^0.12.18", + "friendsofphp/php-cs-fixer": "^3.0", + "mockery/mockery": "^1.5", + "nunomaduro/larastan": "^1.0 || ^2.0", + "orchestra/testbench": "^6.0 || ^7.0", + "orchestra/testbench-core": "^6.26 || ^7.0", + "phpoption/phpoption": "^1.8", + "phpstan/phpstan-mockery": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^9.5", - "thecodingmachine/phpstan-safe-rule": "^1.0" - }, - "config": { - "sort-packages": true - }, - "extra": { - "laravel": { - "providers": [ - "DanielDeWit\\LighthouseSanctum\\Providers\\LighthouseSanctumServiceProvider" - ] - } + "thecodingmachine/safe": "^2.0" }, "autoload": { "psr-4": { @@ -54,11 +45,21 @@ "DanielDeWit\\LighthouseSanctum\\Tests\\": "tests" } }, + "config": { + "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "DanielDeWit\\LighthouseSanctum\\Providers\\LighthouseSanctumServiceProvider" + ] + } + }, "scripts": { "analyze": "vendor/phpstan/phpstan/phpstan analyse", "check-style": [ - "php-cs-fixer fix --diff --diff-format=udiff --dry-run", - "php-cs-fixer fix --diff --diff-format=udiff --dry-run --config=.php_cs.tests.php" + "php-cs-fixer fix --diff --dry-run", + "php-cs-fixer fix --diff --dry-run --config=.php_cs.tests.php" ], "coverage": "vendor/bin/phpunit", "fix-style": [ diff --git a/phpstan.neon b/phpstan.neon index 82ae801..fa50b9f 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,7 +3,6 @@ includes: - vendor/phpstan/phpstan-mockery/extension.neon - vendor/phpstan/phpstan-phpunit/extension.neon - vendor/phpstan/phpstan-phpunit/rules.neon - - vendor/thecodingmachine/phpstan-safe-rule/phpstan-safe-rule.neon parameters: level: max diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9baa281..16bc465 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,6 +11,7 @@ failOnRisky="true" failOnWarning="true" verbose="true" + convertDeprecationsToExceptions="false" > diff --git a/src/GraphQL/Mutations/ForgotPassword.php b/src/GraphQL/Mutations/ForgotPassword.php index 846384d..6a205f0 100644 --- a/src/GraphQL/Mutations/ForgotPassword.php +++ b/src/GraphQL/Mutations/ForgotPassword.php @@ -28,22 +28,28 @@ public function __construct( /** * @param mixed $_ * @param array $args - * @return array + * @return array * @throws Exception */ public function __invoke($_, array $args): array { if (isset($args['reset_password_url'])) { - $this->resetPasswordService->setResetPasswordUrl($args['reset_password_url']['url']); + /** @var array $resetPasswordUrl */ + $resetPasswordUrl = $args['reset_password_url']; + + $this->resetPasswordService->setResetPasswordUrl($resetPasswordUrl['url']); } $this->passwordBroker->sendResetLink([ 'email' => $args['email'], ]); + /** @var string $message */ + $message = $this->translator->get('An email has been sent'); + return [ 'status' => 'EMAIL_SENT', - 'message' => $this->translator->get('An email has been sent'), + 'message' => $message, ]; } } diff --git a/src/GraphQL/Mutations/Logout.php b/src/GraphQL/Mutations/Logout.php index e08712a..c0b5a3d 100644 --- a/src/GraphQL/Mutations/Logout.php +++ b/src/GraphQL/Mutations/Logout.php @@ -28,7 +28,7 @@ public function __construct(AuthFactory $authFactory, Translator $translator) /** * @param mixed $_ * @param array $args - * @return array + * @return array * @throws Exception */ public function __invoke($_, array $args): array @@ -43,9 +43,12 @@ public function __invoke($_, array $args): array $personalAccessToken = $user->currentAccessToken(); $personalAccessToken->delete(); + /** @var string $message */ + $message = $this->translator->get('Your session has been terminated'); + return [ 'status' => 'TOKEN_REVOKED', - 'message' => $this->translator->get('Your session has been terminated'), + 'message' => $message, ]; } diff --git a/src/GraphQL/Mutations/Register.php b/src/GraphQL/Mutations/Register.php index 8c13ac8..80ff3ef 100644 --- a/src/GraphQL/Mutations/Register.php +++ b/src/GraphQL/Mutations/Register.php @@ -56,7 +56,10 @@ public function __invoke($_, array $args): array if ($user instanceof MustVerifyEmail) { if (isset($args['verification_url'])) { - $this->emailVerificationService->setVerificationUrl($args['verification_url']['url']); + /** @var array $verificationUrl */ + $verificationUrl = $args['verification_url']; + + $this->emailVerificationService->setVerificationUrl($verificationUrl['url']); } $user->sendEmailVerificationNotification(); diff --git a/src/GraphQL/Mutations/ResendEmailVerification.php b/src/GraphQL/Mutations/ResendEmailVerification.php index 4477568..a103b36 100644 --- a/src/GraphQL/Mutations/ResendEmailVerification.php +++ b/src/GraphQL/Mutations/ResendEmailVerification.php @@ -43,7 +43,10 @@ public function __invoke($_, array $args): array if ($user && $user instanceof MustVerifyEmail && ! $user->hasVerifiedEmail()) { if (isset($args['verification_url'])) { - $this->emailVerificationService->setVerificationUrl($args['verification_url']['url']); + /** @var array $verificationUrl */ + $verificationUrl = $args['verification_url']; + + $this->emailVerificationService->setVerificationUrl($verificationUrl['url']); } $user->sendEmailVerificationNotification(); diff --git a/src/GraphQL/Mutations/ResetPassword.php b/src/GraphQL/Mutations/ResetPassword.php index a562d39..f64c5b3 100644 --- a/src/GraphQL/Mutations/ResetPassword.php +++ b/src/GraphQL/Mutations/ResetPassword.php @@ -35,7 +35,7 @@ public function __construct( * @param array $args * @param GraphQLContext $context * @param ResolveInfo $resolveInfo - * @return array + * @return array * @throws Exception */ public function __invoke($_, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): array @@ -45,19 +45,23 @@ public function __invoke($_, array $args, GraphQLContext $context, ResolveInfo $ 'password_confirmation', ]); + /** @var string $response */ $response = $this->passwordBroker->reset($credentials, function (Authenticatable $user, string $password) { $this->resetPasswordService->resetPassword($user, $password); }); + /** @var string $message */ + $message = $this->translator->get($response); + if ($response === PasswordBroker::PASSWORD_RESET) { return [ 'status' => 'PASSWORD_RESET', - 'message' => $this->translator->get($response), + 'message' => $message, ]; } throw new GraphQLValidationException( - $this->translator->get($response), + $message, $this->getInvalidField($response), $resolveInfo, ); diff --git a/src/GraphQL/Mutations/UpdatePassword.php b/src/GraphQL/Mutations/UpdatePassword.php index 1677af3..6f3d758 100644 --- a/src/GraphQL/Mutations/UpdatePassword.php +++ b/src/GraphQL/Mutations/UpdatePassword.php @@ -34,7 +34,7 @@ public function __construct(AuthFactory $authFactory, Hasher $hasher, Translator /** * @param mixed $_ - * @param array $args + * @param array $args * @param GraphQLContext $context * @param ResolveInfo $resolveInfo * @return array @@ -66,6 +66,7 @@ public function __invoke($_, array $args, GraphQLContext $context, ResolveInfo $ protected function currentPasswordMustBeTheSame(Authenticatable $user, string $currentPassword): void { if (! $this->hasher->check($currentPassword, $user->getAuthPassword())) { + /** @var string $message */ $message = $this->translator->get('validation.same', [ 'attribute' => 'current_password', 'other' => 'user password', @@ -83,6 +84,7 @@ protected function currentPasswordMustBeTheSame(Authenticatable $user, string $c protected function newPasswordMustBeDifferent(Authenticatable $user, string $newPassword): void { if ($this->hasher->check($newPassword, $user->getAuthPassword())) { + /** @var string $message */ $message = $this->translator->get('validation.different', [ 'attribute' => 'password', 'other' => 'user password', diff --git a/src/Providers/LighthouseSanctumServiceProvider.php b/src/Providers/LighthouseSanctumServiceProvider.php index 150d0fa..c1b51cf 100644 --- a/src/Providers/LighthouseSanctumServiceProvider.php +++ b/src/Providers/LighthouseSanctumServiceProvider.php @@ -24,17 +24,23 @@ public function register(): void /** @var Config $config */ $config = $container->make(Config::class); - return new SignatureService($config->get('app.key')); + /** @var string $appKey */ + $appKey = $config->get('app.key'); + + return new SignatureService($appKey); }); $this->app->singleton(EmailVerificationServiceInterface::class, function (Container $container) { /** @var Config $config */ $config = $container->make(Config::class); - return new EmailVerificationService( - $container->make(SignatureServiceInterface::class), - $config->get('auth.verification.expire', 60), - ); + /** @var SignatureServiceInterface $signatureService */ + $signatureService = $container->make(SignatureServiceInterface::class); + + /** @var int $expiresIn */ + $expiresIn = $config->get('auth.verification.expire', 60); + + return new EmailVerificationService($signatureService, $expiresIn); }); } diff --git a/src/Traits/CreatesUserProvider.php b/src/Traits/CreatesUserProvider.php index 5ac5b34..c2b8e2e 100644 --- a/src/Traits/CreatesUserProvider.php +++ b/src/Traits/CreatesUserProvider.php @@ -17,6 +17,7 @@ abstract protected function getConfig(): Config; protected function createUserProvider(): UserProvider { + /** @var string $provider */ $provider = $this->getConfig()->get('lighthouse-sanctum.provider'); $userProvider = $this->getAuthManager()->createUserProvider($provider); diff --git a/tests/Integration/AbstractIntegrationTest.php b/tests/Integration/AbstractIntegrationTest.php index 90798fd..c9d2557 100644 --- a/tests/Integration/AbstractIntegrationTest.php +++ b/tests/Integration/AbstractIntegrationTest.php @@ -10,6 +10,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Notifications\NotificationServiceProvider; use Laravel\Sanctum\SanctumServiceProvider; +use Nuwave\Lighthouse\Auth\AuthServiceProvider; use Nuwave\Lighthouse\LighthouseServiceProvider; use Nuwave\Lighthouse\Testing\MakesGraphQLRequests; use Nuwave\Lighthouse\Validation\ValidationServiceProvider; @@ -27,6 +28,7 @@ abstract class AbstractIntegrationTest extends TestCase protected function getPackageProviders($app): array { return [ + AuthServiceProvider::class, LighthouseSanctumServiceProvider::class, LighthouseServiceProvider::class, NotificationServiceProvider::class, @@ -54,4 +56,12 @@ protected function getStubsPath(string $path): string { return dirname(__DIR__) . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . $path; } + + protected function getAppKey(): string + { + /** @var string $appKey */ + $appKey = $this->app['config']->get('app.key'); + + return $appKey; + } } diff --git a/tests/Integration/GraphQL/Mutations/RegisterTest.php b/tests/Integration/GraphQL/Mutations/RegisterTest.php index a63ab19..75ad2f2 100644 --- a/tests/Integration/GraphQL/Mutations/RegisterTest.php +++ b/tests/Integration/GraphQL/Mutations/RegisterTest.php @@ -95,6 +95,7 @@ public function it_sends_an_email_verification_notification(): void Notification::assertSentTo($user, function (VerifyEmail $notification) use ($user) { $url = call_user_func($notification::$createUrlCallback, $user); + /** @var int|string $id */ $id = $user->getKey(); $hash = sha1('foo@bar.com'); @@ -152,13 +153,14 @@ public function it_sends_a_signed_email_verification_notification(): void Notification::assertSentTo($user, function (VerifyEmail $notification) use ($user) { $url = call_user_func($notification::$createUrlCallback, $user); + /** @var int|string $id */ $id = $user->getKey(); $hash = sha1('foo@bar.com'); $signature = hash_hmac('sha256', serialize([ 'id' => $id, 'hash' => $hash, 'expires' => 1609480800, - ]), $this->app['config']->get('app.key')); + ]), $this->getAppKey()); return $url === "https://mysite.com/verify-email/{$id}/{$hash}/1609480800/{$signature}"; }); diff --git a/tests/Integration/GraphQL/Mutations/ResendEmailVerificationTest.php b/tests/Integration/GraphQL/Mutations/ResendEmailVerificationTest.php index 19fed2d..0c7b653 100644 --- a/tests/Integration/GraphQL/Mutations/ResendEmailVerificationTest.php +++ b/tests/Integration/GraphQL/Mutations/ResendEmailVerificationTest.php @@ -105,7 +105,7 @@ public function it_resends_a_signed_email_verification_notification(): void 'id' => 123, 'hash' => $hash, 'expires' => 1609480800, - ]), $this->app['config']->get('app.key')); + ]), $this->getAppKey()); return $url === "https://mysite.com/verify-email/123/{$hash}/1609480800/{$signature}"; }); diff --git a/tests/Integration/GraphQL/Mutations/VerifyEmailTest.php b/tests/Integration/GraphQL/Mutations/VerifyEmailTest.php index f073c74..d713a3a 100644 --- a/tests/Integration/GraphQL/Mutations/VerifyEmailTest.php +++ b/tests/Integration/GraphQL/Mutations/VerifyEmailTest.php @@ -67,7 +67,7 @@ public function it_verifies_an_email_with_a_signature(): void 'id' => 123, 'hash' => sha1('john.doe@gmail.com'), 'expires' => 1609480800, - ]), $this->app['config']->get('app.key')); + ]), $this->getAppKey()); $this->graphQL(/** @lang GraphQL */ ' mutation { @@ -154,7 +154,7 @@ public function it_returns_an_error_if_the_expires_is_incorrect(): void 'id' => 123, 'hash' => sha1('john.doe@gmail.com'), 'expires' => 1609480800, - ]), $this->app['config']->get('app.key')); + ]), $this->getAppKey()); $this->graphQL(/** @lang GraphQL */ ' mutation { @@ -190,7 +190,7 @@ public function it_returns_an_error_if_the_signature_has_expired(): void 'id' => 123, 'hash' => sha1('john.doe@gmail.com'), 'expires' => 1609476200, - ]), $this->app['config']->get('app.key')); + ]), $this->getAppKey()); $this->graphQL(/** @lang GraphQL */ ' mutation { diff --git a/tests/Integration/Services/EmailVerificationServiceTest.php b/tests/Integration/Services/EmailVerificationServiceTest.php index 8115b17..937bb58 100644 --- a/tests/Integration/Services/EmailVerificationServiceTest.php +++ b/tests/Integration/Services/EmailVerificationServiceTest.php @@ -20,10 +20,10 @@ protected function setUp(): void { parent::setUp(); - $this->service = new EmailVerificationService( - $this->app->make(SignatureServiceInterface::class), - 60, - ); + /** @var SignatureServiceInterface $signatureService */ + $signatureService = $this->app->make(SignatureServiceInterface::class); + + $this->service = new EmailVerificationService($signatureService, 60); } /** @@ -64,7 +64,7 @@ public function it_transforms_a_signed_verification_url(): void 'id' => 12345, 'hash' => sha1('user@example.com'), 'expires' => 1609480800, - ]), $this->app['config']->get('app.key')); + ]), $this->getAppKey()); static::assertSame('https://mysite.com/verify-email/12345/' . sha1('user@example.com') . '/1609480800/' . $signature, $url); } @@ -108,7 +108,7 @@ public function it_sets_the_signed_verification_url(): void 'id' => 12345, 'hash' => sha1('user@example.com'), 'expires' => 1609480800, - ]), $this->app['config']->get('app.key')); + ]), $this->getAppKey()); static::assertSame('https://mysite.com/verify-email/12345/' . sha1('user@example.com') . '/1609480800/' . $signature, $url); } diff --git a/tests/Integration/Services/ResetPasswordServiceTest.php b/tests/Integration/Services/ResetPasswordServiceTest.php index 4cb6e44..baabb01 100644 --- a/tests/Integration/Services/ResetPasswordServiceTest.php +++ b/tests/Integration/Services/ResetPasswordServiceTest.php @@ -24,10 +24,10 @@ protected function setUp(): void $dispatcher = Event::fake([PasswordReset::class]); - $this->service = new ResetPasswordService( - $this->app->make(Hasher::class), - $dispatcher, - ); + /** @var Hasher $hasher */ + $hasher = $this->app->make(Hasher::class); + + $this->service = new ResetPasswordService($hasher, $dispatcher); } /** diff --git a/tests/stubs/Users/UserHasApiTokens.php b/tests/stubs/Users/UserHasApiTokens.php index 190d677..5b1d6b0 100644 --- a/tests/stubs/Users/UserHasApiTokens.php +++ b/tests/stubs/Users/UserHasApiTokens.php @@ -44,6 +44,9 @@ class UserHasApiTokens extends User implements HasApiTokensContract 'email_verified_at' => 'datetime', ]; + /** + * @return UserHasApiTokensFactory + */ protected static function newFactory(): Factory { return new UserHasApiTokensFactory(); diff --git a/tests/stubs/Users/UserMustVerifyEmail.php b/tests/stubs/Users/UserMustVerifyEmail.php index abbf621..e1e79e3 100644 --- a/tests/stubs/Users/UserMustVerifyEmail.php +++ b/tests/stubs/Users/UserMustVerifyEmail.php @@ -9,6 +9,9 @@ class UserMustVerifyEmail extends UserHasApiTokens implements MustVerifyEmail { + /** + * @return UserMustVerifyEmailFactory + */ protected static function newFactory(): Factory { return new UserMustVerifyEmailFactory();