From 70e61da405874d957f09f94dd7c122d45df788fa Mon Sep 17 00:00:00 2001 From: mortazavi Date: Mon, 31 Jul 2023 16:00:17 +0330 Subject: [PATCH 1/2] badge added to README.md; --- README.md | 1 + docs/content/docs/installation.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 472b5b7..e3538a1 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/hans-thomas/sphinx/php.yml) ![GitHub top language](https://img.shields.io/github/languages/top/hans-thomas/sphinx) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/hans-thomas/sphinx) +![StyleCi](https://github.styleci.io/repos/464496173/shield?style=plastic) Sphinx is a feature reach Jwt-based authentication system that make zero queries to database during authorization. diff --git a/docs/content/docs/installation.md b/docs/content/docs/installation.md index 6ccab02..8282d6f 100644 --- a/docs/content/docs/installation.md +++ b/docs/content/docs/installation.md @@ -16,6 +16,7 @@ toc = false ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/hans-thomas/sphinx/php.yml) ![GitHub top language](https://img.shields.io/github/languages/top/hans-thomas/sphinx) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/hans-thomas/sphinx) +![StyleCi](https://github.styleci.io/repos/464496173/shield?style=plastic) Install the package via composer From 8b7b6a62b2175fda1390eef1a791ccff63c5f9a5 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Mon, 31 Jul 2023 12:30:30 +0000 Subject: [PATCH 2/2] Apply fixes from StyleCI --- .../Constraints/ExpirationValidator.php | 44 +- src/Drivers/Constraints/RoleIdValidator.php | 74 +- .../SecretVerificationValidator.php | 74 +- .../Constraints/SessionIdValidator.php | 76 +- src/Drivers/Contracts/JwtToken.php | 572 +++++------ src/Drivers/InnerAccessToken.php | 28 +- src/Drivers/InnerRefreshToken.php | 28 +- src/Drivers/WrapperAccessToken.php | 40 +- src/Drivers/WrapperRefreshToken.php | 32 +- src/Exceptions/SphinxErrorCode.php | 32 +- src/Exceptions/SphinxException.php | 56 +- src/Facades/Sphinx.php | 78 +- src/Helpers/Enums/SphinxCache.php | 8 +- src/Models/Session.php | 130 +-- src/Services/SphinxGuard.php | 318 +++--- src/Services/SphinxService.php | 930 +++++++++--------- src/Services/SphinxUserProvider.php | 86 +- src/SphinxServiceProvider.php | 100 +- src/Traits/SphinxMethods.php | 160 +-- src/Traits/SphinxRelationHandler.php | 24 +- src/Traits/SphinxTokenCan.php | 206 ++-- src/Traits/SphinxTrait.php | 12 +- tests/Factories/UserFactory.php | 130 +-- tests/Feature/Drivers/ConstraintsTest.php | 262 ++--- tests/Feature/Drivers/JwtTokenTest.php | 896 ++++++++--------- tests/Feature/Helpers/FunctionsTest.php | 220 ++--- tests/Feature/PerformanceTest.php | 66 +- tests/Feature/Services/SphinxGuardTest.php | 420 ++++---- tests/Feature/Services/SphinxServiceTest.php | 924 ++++++++--------- .../Services/SphinxUserProviderTest.php | 116 +-- tests/Feature/Traits/SphinxMethodsTest.php | 148 +-- tests/Feature/Traits/SphinxTokenCanTest.php | 206 ++-- tests/Instances/JwtTokenInstance.php | 24 +- ...kenWithCustomizableConstraintsInstance.php | 38 +- tests/TestCase.php | 310 +++--- tests/Unit/SessionModelTest.php | 98 +- .../app/Http/Middleware/ValidateSignature.php | 34 +- .../laravel-10.x/app/Models/RoleDelegate.php | 98 +- .../skeleton/laravel-10.x/app/Models/User.php | 150 +-- .../database/seeders/DatabaseSeeder.php | 24 +- 40 files changed, 3636 insertions(+), 3636 deletions(-) diff --git a/src/Drivers/Constraints/ExpirationValidator.php b/src/Drivers/Constraints/ExpirationValidator.php index 9907e4c..74b0ce5 100644 --- a/src/Drivers/Constraints/ExpirationValidator.php +++ b/src/Drivers/Constraints/ExpirationValidator.php @@ -2,29 +2,29 @@ namespace Hans\Sphinx\Drivers\Constraints; - use DateTimeImmutable; - use Hans\Sphinx\Exceptions\SphinxErrorCode; - use Hans\Sphinx\Exceptions\SphinxException; - use Lcobucci\JWT\Token; - use Lcobucci\JWT\Validation\Constraint; - use Symfony\Component\HttpFoundation\Response as ResponseAlias; +use DateTimeImmutable; +use Hans\Sphinx\Exceptions\SphinxErrorCode; +use Hans\Sphinx\Exceptions\SphinxException; +use Lcobucci\JWT\Token; +use Lcobucci\JWT\Validation\Constraint; +use Symfony\Component\HttpFoundation\Response as ResponseAlias; - final class ExpirationValidator implements Constraint +final class ExpirationValidator implements Constraint +{ + /** + * @param Token $token + * + * @throws SphinxException + */ + public function assert(Token $token): void { - /** - * @param Token $token - * - * @throws SphinxException - */ - public function assert(Token $token): void - { - $diff = ( new DateTimeImmutable('UTC') )->diff($token->claims()->get('exp')); - if ('-' == $diff->format('%R')) { - throw new SphinxException( - 'Token expired!', - SphinxErrorCode::TOKEN_EXPIRED, - ResponseAlias::HTTP_FORBIDDEN - ); - } + $diff = ( new DateTimeImmutable('UTC') )->diff($token->claims()->get('exp')); + if ('-' == $diff->format('%R')) { + throw new SphinxException( + 'Token expired!', + SphinxErrorCode::TOKEN_EXPIRED, + ResponseAlias::HTTP_FORBIDDEN + ); } } +} diff --git a/src/Drivers/Constraints/RoleIdValidator.php b/src/Drivers/Constraints/RoleIdValidator.php index 42c8256..5df12f0 100644 --- a/src/Drivers/Constraints/RoleIdValidator.php +++ b/src/Drivers/Constraints/RoleIdValidator.php @@ -2,47 +2,47 @@ namespace Hans\Sphinx\Drivers\Constraints; - use Hans\Sphinx\Exceptions\SphinxErrorCode; - use Hans\Sphinx\Exceptions\SphinxException; - use Lcobucci\JWT\Token; - use Lcobucci\JWT\Validation\Constraint; - use Symfony\Component\HttpFoundation\Response as ResponseAlias; +use Hans\Sphinx\Exceptions\SphinxErrorCode; +use Hans\Sphinx\Exceptions\SphinxException; +use Lcobucci\JWT\Token; +use Lcobucci\JWT\Validation\Constraint; +use Symfony\Component\HttpFoundation\Response as ResponseAlias; - final class RoleIdValidator implements Constraint +final class RoleIdValidator implements Constraint +{ + /** + * @param Token $token + * + * @throws SphinxException + */ + public function assert(Token $token): void { - /** - * @param Token $token - * - * @throws SphinxException - */ - public function assert(Token $token): void - { - $role_id = $token->headers()->get('role_id', false); - $role_version = $token->headers()->get('role_version', false); + $role_id = $token->headers()->get('role_id', false); + $role_version = $token->headers()->get('role_version', false); - if (!$role_id) { - throw new SphinxException( - 'Role id not found in header!', - SphinxErrorCode::ROLE_NOT_FOUND, - ResponseAlias::HTTP_FORBIDDEN - ); - } - if (!$role_version) { - throw new SphinxException( - 'Role\'s version not found in header!', - SphinxErrorCode::ROLE_VERSION_NOT_FOUND, - ResponseAlias::HTTP_FORBIDDEN - ); - } + if (!$role_id) { + throw new SphinxException( + 'Role id not found in header!', + SphinxErrorCode::ROLE_NOT_FOUND, + ResponseAlias::HTTP_FORBIDDEN + ); + } + if (!$role_version) { + throw new SphinxException( + 'Role\'s version not found in header!', + SphinxErrorCode::ROLE_VERSION_NOT_FOUND, + ResponseAlias::HTTP_FORBIDDEN + ); + } - $role = app(sphinx_config('role_model'))->findAndCache($role_id); + $role = app(sphinx_config('role_model'))->findAndCache($role_id); - if ($role->getVersion() != $role_version) { - throw new SphinxException( - 'User\'s token is out-of-date!', - SphinxErrorCode::TOKEN_IS_OUT_OF_DATE, - ResponseAlias::HTTP_FORBIDDEN - ); - } + if ($role->getVersion() != $role_version) { + throw new SphinxException( + 'User\'s token is out-of-date!', + SphinxErrorCode::TOKEN_IS_OUT_OF_DATE, + ResponseAlias::HTTP_FORBIDDEN + ); } } +} diff --git a/src/Drivers/Constraints/SecretVerificationValidator.php b/src/Drivers/Constraints/SecretVerificationValidator.php index 4a5d730..aafe1a1 100644 --- a/src/Drivers/Constraints/SecretVerificationValidator.php +++ b/src/Drivers/Constraints/SecretVerificationValidator.php @@ -2,47 +2,47 @@ namespace Hans\Sphinx\Drivers\Constraints; - use Hans\Sphinx\Exceptions\SphinxErrorCode; - use Hans\Sphinx\Exceptions\SphinxException; - use Lcobucci\JWT\Signer; - use Lcobucci\JWT\Token; - use Lcobucci\JWT\Validation\Constraint; - use Symfony\Component\HttpFoundation\Response; +use Hans\Sphinx\Exceptions\SphinxErrorCode; +use Hans\Sphinx\Exceptions\SphinxException; +use Lcobucci\JWT\Signer; +use Lcobucci\JWT\Token; +use Lcobucci\JWT\Validation\Constraint; +use Symfony\Component\HttpFoundation\Response; - final class SecretVerificationValidator implements Constraint +final class SecretVerificationValidator implements Constraint +{ + private Signer $signer; + private Signer\Key $key; + + public function __construct(Signer $signer, Signer\Key $key) { - private Signer $signer; - private Signer\Key $key; + $this->signer = $signer; + $this->key = $key; + } - public function __construct(Signer $signer, Signer\Key $key) - { - $this->signer = $signer; - $this->key = $key; + /** + * @param Token $token + * + * @throws SphinxException + * + * @return void + */ + public function assert(Token $token): void + { + if ($token->headers()->get('alg') !== $this->signer->algorithmId()) { + throw new SphinxException( + 'Token signer mismatch!', + SphinxErrorCode::TOKEN_MISMATCH, + Response::HTTP_FORBIDDEN + ); } - /** - * @param Token $token - * - * @throws SphinxException - * - * @return void - */ - public function assert(Token $token): void - { - if ($token->headers()->get('alg') !== $this->signer->algorithmId()) { - throw new SphinxException( - 'Token signer mismatch!', - SphinxErrorCode::TOKEN_MISMATCH, - Response::HTTP_FORBIDDEN - ); - } - - if (!$this->signer->verify($token->signature()->hash(), $token->payload(), $this->key)) { - throw new SphinxException( - 'Token signature mismatch!', - SphinxErrorCode::TOKEN_MISMATCH, - Response::HTTP_FORBIDDEN - ); - } + if (!$this->signer->verify($token->signature()->hash(), $token->payload(), $this->key)) { + throw new SphinxException( + 'Token signature mismatch!', + SphinxErrorCode::TOKEN_MISMATCH, + Response::HTTP_FORBIDDEN + ); } } +} diff --git a/src/Drivers/Constraints/SessionIdValidator.php b/src/Drivers/Constraints/SessionIdValidator.php index 6e0fb44..be418b7 100644 --- a/src/Drivers/Constraints/SessionIdValidator.php +++ b/src/Drivers/Constraints/SessionIdValidator.php @@ -2,48 +2,48 @@ namespace Hans\Sphinx\Drivers\Constraints; - use Hans\Sphinx\Exceptions\SphinxErrorCode; - use Hans\Sphinx\Exceptions\SphinxException; - use Hans\Sphinx\Models\Session; - use Lcobucci\JWT\Token; - use Lcobucci\JWT\Validation\Constraint; - use Symfony\Component\HttpFoundation\Response as ResponseAlias; +use Hans\Sphinx\Exceptions\SphinxErrorCode; +use Hans\Sphinx\Exceptions\SphinxException; +use Hans\Sphinx\Models\Session; +use Lcobucci\JWT\Token; +use Lcobucci\JWT\Validation\Constraint; +use Symfony\Component\HttpFoundation\Response as ResponseAlias; - final class SessionIdValidator implements Constraint +final class SessionIdValidator implements Constraint +{ + /** + * @param Token $token + * + * @throws SphinxException + */ + public function assert(Token $token): void { - /** - * @param Token $token - * - * @throws SphinxException - */ - public function assert(Token $token): void - { - $session_id = $token->headers()->get('session_id', false); - $sessionable_version = $token->headers()->get('sessionable_version', false); + $session_id = $token->headers()->get('session_id', false); + $sessionable_version = $token->headers()->get('sessionable_version', false); - if (!$session_id) { - throw new SphinxException( - 'Session id not found in header!', - SphinxErrorCode::SESSION_NOT_FOUND, - ResponseAlias::HTTP_FORBIDDEN - ); - } - if (!$sessionable_version) { - throw new SphinxException( - "User's version not found in header!", - SphinxErrorCode::USERS_VERSION_NOT_FOUND, - ResponseAlias::HTTP_FORBIDDEN - ); - } + if (!$session_id) { + throw new SphinxException( + 'Session id not found in header!', + SphinxErrorCode::SESSION_NOT_FOUND, + ResponseAlias::HTTP_FORBIDDEN + ); + } + if (!$sessionable_version) { + throw new SphinxException( + "User's version not found in header!", + SphinxErrorCode::USERS_VERSION_NOT_FOUND, + ResponseAlias::HTTP_FORBIDDEN + ); + } - $session = Session::findAndCache($session_id); + $session = Session::findAndCache($session_id); - if ($session->sessionable_version != $sessionable_version) { - throw new SphinxException( - 'Token is out-of-date!', - SphinxErrorCode::TOKEN_IS_OUT_OF_DATE, - ResponseAlias::HTTP_FORBIDDEN - ); - } + if ($session->sessionable_version != $sessionable_version) { + throw new SphinxException( + 'Token is out-of-date!', + SphinxErrorCode::TOKEN_IS_OUT_OF_DATE, + ResponseAlias::HTTP_FORBIDDEN + ); } } +} diff --git a/src/Drivers/Contracts/JwtToken.php b/src/Drivers/Contracts/JwtToken.php index 5ad75d5..e42366c 100644 --- a/src/Drivers/Contracts/JwtToken.php +++ b/src/Drivers/Contracts/JwtToken.php @@ -2,325 +2,325 @@ namespace Hans\Sphinx\Drivers\Contracts; - use Closure; - use DateTimeImmutable; - use Hans\Sphinx\Exceptions\SphinxErrorCode; - use Hans\Sphinx\Exceptions\SphinxException; - use Lcobucci\JWT\Builder; - use Lcobucci\JWT\Configuration; - use Lcobucci\JWT\Signer\Hmac\Sha512; - use Lcobucci\JWT\Signer\Key\InMemory; - use Lcobucci\JWT\Token\Plain; - use Lcobucci\JWT\UnencryptedToken; - use Symfony\Component\HttpFoundation\Response as ResponseAlias; - use Throwable; - - abstract class JwtToken +use Closure; +use DateTimeImmutable; +use Hans\Sphinx\Exceptions\SphinxErrorCode; +use Hans\Sphinx\Exceptions\SphinxException; +use Lcobucci\JWT\Builder; +use Lcobucci\JWT\Configuration; +use Lcobucci\JWT\Signer\Hmac\Sha512; +use Lcobucci\JWT\Signer\Key\InMemory; +use Lcobucci\JWT\Token\Plain; +use Lcobucci\JWT\UnencryptedToken; +use Symfony\Component\HttpFoundation\Response as ResponseAlias; +use Throwable; + +abstract class JwtToken +{ + /** + * Configuration for JWT builder and parser. + * + * @var Configuration + */ + protected Configuration $configuration; + + /** + * JWT builder instance. + * + * @var Builder + */ + protected Builder $instance; + + public function __construct(string $secret) { - /** - * Configuration for JWT builder and parser. - * - * @var Configuration - */ - protected Configuration $configuration; - - /** - * JWT builder instance. - * - * @var Builder - */ - protected Builder $instance; - - public function __construct(string $secret) - { - // TODO: RSA support? - $this->configuration = Configuration::forSymmetricSigner( - new Sha512(), - InMemory::plainText($secret) - ); - $this->configuration->setValidationConstraints(...$this->getAvailableConstrains()); - $this->instance = $this->configuration->builder(); - } - - /** - * Return available constrains for current implementation. - * - * @return array - */ - abstract protected function getAvailableConstrains(): array; - - /** - * Determine the token is issued by who. - * - * @param string $issuedBy - * - * @return self - */ - public function issuedBy(string $issuedBy): self - { - $this->instance->issuedBy($issuedBy); - - return $this; - } + // TODO: RSA support? + $this->configuration = Configuration::forSymmetricSigner( + new Sha512(), + InMemory::plainText($secret) + ); + $this->configuration->setValidationConstraints(...$this->getAvailableConstrains()); + $this->instance = $this->configuration->builder(); + } - /** - * Determine the token is permitted for what. - * - * @param string $permittedFor - * - * @return self - */ - public function permittedFor(string $permittedFor): self - { - $this->instance->permittedFor($permittedFor); - - return $this; - } + /** + * Return available constrains for current implementation. + * + * @return array + */ + abstract protected function getAvailableConstrains(): array; + + /** + * Determine the token is issued by who. + * + * @param string $issuedBy + * + * @return self + */ + public function issuedBy(string $issuedBy): self + { + $this->instance->issuedBy($issuedBy); - /** - * Determine the token is identified by who. - * - * @param string $identifiedBy - * - * @return self - */ - public function identifiedBy(string $identifiedBy): self - { - $this->instance->identifiedBy($identifiedBy); - - return $this; - } + return $this; + } - /** - * Determine the token can be used after a period. - * - * @param string $due - * - * @return self - */ - public function canOnlyBeUsedAfter(string $due = '+1 minute'): self - { - $date = new DateTimeImmutable(); - $this->instance->canOnlyBeUsedAfter($date->modify($due)); - - return $this; - } + /** + * Determine the token is permitted for what. + * + * @param string $permittedFor + * + * @return self + */ + public function permittedFor(string $permittedFor): self + { + $this->instance->permittedFor($permittedFor); - /** - * Determine the token expires after a period. - * - * @param string $due - * - * @return self - */ - public function expiresAt(string $due = '+5 hour'): self - { - $date = new DateTimeImmutable(); - $this->instance->expiresAt($date->modify($due)); - - return $this; - } + return $this; + } - /** - * Set many claims at once. - * - * @param array $claims - * - * @throws SphinxException - * - * @return self - */ - public function claims(array $claims): self - { - foreach ($claims as $key => $value) { - try { - $this->claim($key, $value); - } catch (Throwable $e) { - throw new SphinxException( - "Failed to set [$key => $value] claim.", - SphinxErrorCode::FAILED_TO_SET_CLAIM - ); - } - } + /** + * Determine the token is identified by who. + * + * @param string $identifiedBy + * + * @return self + */ + public function identifiedBy(string $identifiedBy): self + { + $this->instance->identifiedBy($identifiedBy); - return $this; - } + return $this; + } - /** - * Set a claim for token. - * - * @param string $key - * @param string|int|array $value - * - * @return self - */ - public function claim(string $key, string|int|array $value): self - { - $this->instance->withClaim($key, $value); + /** + * Determine the token can be used after a period. + * + * @param string $due + * + * @return self + */ + public function canOnlyBeUsedAfter(string $due = '+1 minute'): self + { + $date = new DateTimeImmutable(); + $this->instance->canOnlyBeUsedAfter($date->modify($due)); - return $this; - } + return $this; + } - /** - * Set a claim if condition is true. - * - * @param bool $condition - * @param string $key - * @param string|int|array|callable $value - * - * @return self - */ - public function claimWhen(bool $condition, string $key, string|int|array|callable $value): self - { - if ($condition) { - if ($value instanceof Closure) { - $value = $value(); - } - $this->instance->withClaim($key, $value); - } + /** + * Determine the token expires after a period. + * + * @param string $due + * + * @return self + */ + public function expiresAt(string $due = '+5 hour'): self + { + $date = new DateTimeImmutable(); + $this->instance->expiresAt($date->modify($due)); - return $this; - } + return $this; + } - /** - * Set many headers at once. - * - * @param array $headers - * - * @throws SphinxException - * - * @return self - */ - public function headers(array $headers): self - { - foreach ($headers as $key => $value) { - try { - $this->header($key, $value); - } catch (Throwable $e) { - throw new SphinxException( - "Failed to set [$key => $value] header.", - SphinxErrorCode::FAILED_TO_SET_HEADER - ); - } + /** + * Set many claims at once. + * + * @param array $claims + * + * @throws SphinxException + * + * @return self + */ + public function claims(array $claims): self + { + foreach ($claims as $key => $value) { + try { + $this->claim($key, $value); + } catch (Throwable $e) { + throw new SphinxException( + "Failed to set [$key => $value] claim.", + SphinxErrorCode::FAILED_TO_SET_CLAIM + ); } - - return $this; } - /** - * Set a header for token. - * - * @param string $key - * @param string|int $value - * - * @return self - */ - public function header(string $key, string|int $value): self - { - $this->instance->withHeader($key, $value); + return $this; + } - return $this; - } + /** + * Set a claim for token. + * + * @param string $key + * @param string|int|array $value + * + * @return self + */ + public function claim(string $key, string|int|array $value): self + { + $this->instance->withClaim($key, $value); - /** - * Set a header if condition is true. - * - * @param bool $condition - * @param string $key - * @param string|int|callable $value - * - * @return self - */ - public function headerWhen(bool $condition, string $key, string|int|callable $value): self - { - if ($condition) { - if ($value instanceof Closure) { - $value = $value(); - } - $this->instance->withHeader($key, $value); - } + return $this; + } - return $this; + /** + * Set a claim if condition is true. + * + * @param bool $condition + * @param string $key + * @param string|int|array|callable $value + * + * @return self + */ + public function claimWhen(bool $condition, string $key, string|int|array|callable $value): self + { + if ($condition) { + if ($value instanceof Closure) { + $value = $value(); + } + $this->instance->withClaim($key, $value); } - /** - * Set immutable time to the token as issued time. - * - * @return self - */ - public function encode(): self - { - $this->instance->issuedAt(new DateTimeImmutable()); - - return $this; - } + return $this; + } - /** - * Decode the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return UnencryptedToken - */ - public function decode(string $token): UnencryptedToken - { + /** + * Set many headers at once. + * + * @param array $headers + * + * @throws SphinxException + * + * @return self + */ + public function headers(array $headers): self + { + foreach ($headers as $key => $value) { try { - $decoded = $this->configuration->parser()->parse($token); + $this->header($key, $value); } catch (Throwable $e) { throw new SphinxException( - 'Failed to decode the token. '.$e->getMessage(), - SphinxErrorCode::DECODE_FAILED, - ResponseAlias::HTTP_FORBIDDEN + "Failed to set [$key => $value] header.", + SphinxErrorCode::FAILED_TO_SET_HEADER ); } - - return $decoded; } - /** - * Assert the given token with available constraints. - * - * @param string $token - * - * @throws SphinxException - * - * @return void - */ - public function assert(string $token): void - { - $constraints = $this->configuration->validationConstraints(); - $this->configuration->validator()->assert($this->decode($token), ...$constraints); - } + return $this; + } - /** - * Validation the given token with available constraints. - * - * @param string $token - * - * @return bool - */ - public function validate(string $token): bool - { - $constraints = $this->configuration->validationConstraints(); + /** + * Set a header for token. + * + * @param string $key + * @param string|int $value + * + * @return self + */ + public function header(string $key, string|int $value): self + { + $this->instance->withHeader($key, $value); - try { - $this->configuration->validator()->validate($this->decode($token), ...$constraints); - } catch (Throwable $e) { - return false; + return $this; + } + + /** + * Set a header if condition is true. + * + * @param bool $condition + * @param string $key + * @param string|int|callable $value + * + * @return self + */ + public function headerWhen(bool $condition, string $key, string|int|callable $value): self + { + if ($condition) { + if ($value instanceof Closure) { + $value = $value(); } + $this->instance->withHeader($key, $value); + } - return true; + return $this; + } + + /** + * Set immutable time to the token as issued time. + * + * @return self + */ + public function encode(): self + { + $this->instance->issuedAt(new DateTimeImmutable()); + + return $this; + } + + /** + * Decode the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return UnencryptedToken + */ + public function decode(string $token): UnencryptedToken + { + try { + $decoded = $this->configuration->parser()->parse($token); + } catch (Throwable $e) { + throw new SphinxException( + 'Failed to decode the token. '.$e->getMessage(), + SphinxErrorCode::DECODE_FAILED, + ResponseAlias::HTTP_FORBIDDEN + ); } - /** - * Return the configured plain token instance. - * - * @return Plain - */ - public function getToken(): Plain - { - return $this->instance->getToken($this->configuration->signer(), $this->configuration->signingKey()); + return $decoded; + } + + /** + * Assert the given token with available constraints. + * + * @param string $token + * + * @throws SphinxException + * + * @return void + */ + public function assert(string $token): void + { + $constraints = $this->configuration->validationConstraints(); + $this->configuration->validator()->assert($this->decode($token), ...$constraints); + } + + /** + * Validation the given token with available constraints. + * + * @param string $token + * + * @return bool + */ + public function validate(string $token): bool + { + $constraints = $this->configuration->validationConstraints(); + + try { + $this->configuration->validator()->validate($this->decode($token), ...$constraints); + } catch (Throwable $e) { + return false; } + + return true; + } + + /** + * Return the configured plain token instance. + * + * @return Plain + */ + public function getToken(): Plain + { + return $this->instance->getToken($this->configuration->signer(), $this->configuration->signingKey()); } +} diff --git a/src/Drivers/InnerAccessToken.php b/src/Drivers/InnerAccessToken.php index 1942224..2726312 100644 --- a/src/Drivers/InnerAccessToken.php +++ b/src/Drivers/InnerAccessToken.php @@ -2,20 +2,20 @@ namespace Hans\Sphinx\Drivers; - use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; - use Hans\Sphinx\Drivers\Contracts\JwtToken; +use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; +use Hans\Sphinx\Drivers\Contracts\JwtToken; - class InnerAccessToken extends JwtToken +class InnerAccessToken extends JwtToken +{ + /** + * Return available constrains for current implementation. + * + * @return array + */ + protected function getAvailableConstrains(): array { - /** - * Return available constrains for current implementation. - * - * @return array - */ - protected function getAvailableConstrains(): array - { - return [ - new SecretVerificationValidator($this->configuration->signer(), $this->configuration->signingKey()), - ]; - } + return [ + new SecretVerificationValidator($this->configuration->signer(), $this->configuration->signingKey()), + ]; } +} diff --git a/src/Drivers/InnerRefreshToken.php b/src/Drivers/InnerRefreshToken.php index 0151f61..1717bfd 100644 --- a/src/Drivers/InnerRefreshToken.php +++ b/src/Drivers/InnerRefreshToken.php @@ -2,20 +2,20 @@ namespace Hans\Sphinx\Drivers; - use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; - use Hans\Sphinx\Drivers\Contracts\JwtToken; +use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; +use Hans\Sphinx\Drivers\Contracts\JwtToken; - class InnerRefreshToken extends JwtToken +class InnerRefreshToken extends JwtToken +{ + /** + * Return available constrains for current implementation. + * + * @return array + */ + protected function getAvailableConstrains(): array { - /** - * Return available constrains for current implementation. - * - * @return array - */ - protected function getAvailableConstrains(): array - { - return [ - new SecretVerificationValidator($this->configuration->signer(), $this->configuration->signingKey()), - ]; - } + return [ + new SecretVerificationValidator($this->configuration->signer(), $this->configuration->signingKey()), + ]; } +} diff --git a/src/Drivers/WrapperAccessToken.php b/src/Drivers/WrapperAccessToken.php index 6a095cd..4e4040c 100644 --- a/src/Drivers/WrapperAccessToken.php +++ b/src/Drivers/WrapperAccessToken.php @@ -2,26 +2,26 @@ namespace Hans\Sphinx\Drivers; - use Hans\Sphinx\Drivers\Constraints\ExpirationValidator; - use Hans\Sphinx\Drivers\Constraints\RoleIdValidator; - use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; - use Hans\Sphinx\Drivers\Constraints\SessionIdValidator; - use Hans\Sphinx\Drivers\Contracts\JwtToken; +use Hans\Sphinx\Drivers\Constraints\ExpirationValidator; +use Hans\Sphinx\Drivers\Constraints\RoleIdValidator; +use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; +use Hans\Sphinx\Drivers\Constraints\SessionIdValidator; +use Hans\Sphinx\Drivers\Contracts\JwtToken; - class WrapperAccessToken extends JwtToken +class WrapperAccessToken extends JwtToken +{ + /** + * Return available constrains for current implementation. + * + * @return array + */ + protected function getAvailableConstrains(): array { - /** - * Return available constrains for current implementation. - * - * @return array - */ - protected function getAvailableConstrains(): array - { - return [ - new SecretVerificationValidator($this->configuration->signer(), $this->configuration->signingKey()), - new ExpirationValidator(), - new SessionIdValidator(), - new RoleIdValidator(), - ]; - } + return [ + new SecretVerificationValidator($this->configuration->signer(), $this->configuration->signingKey()), + new ExpirationValidator(), + new SessionIdValidator(), + new RoleIdValidator(), + ]; } +} diff --git a/src/Drivers/WrapperRefreshToken.php b/src/Drivers/WrapperRefreshToken.php index 00e80eb..6fbf42f 100644 --- a/src/Drivers/WrapperRefreshToken.php +++ b/src/Drivers/WrapperRefreshToken.php @@ -2,22 +2,22 @@ namespace Hans\Sphinx\Drivers; - use Hans\Sphinx\Drivers\Constraints\ExpirationValidator; - use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; - use Hans\Sphinx\Drivers\Contracts\JwtToken; +use Hans\Sphinx\Drivers\Constraints\ExpirationValidator; +use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; +use Hans\Sphinx\Drivers\Contracts\JwtToken; - class WrapperRefreshToken extends JwtToken +class WrapperRefreshToken extends JwtToken +{ + /** + * Return available constrains for current implementation. + * + * @return array + */ + protected function getAvailableConstrains(): array { - /** - * Return available constrains for current implementation. - * - * @return array - */ - protected function getAvailableConstrains(): array - { - return [ - new SecretVerificationValidator($this->configuration->signer(), $this->configuration->signingKey()), - new ExpirationValidator(), - ]; - } + return [ + new SecretVerificationValidator($this->configuration->signer(), $this->configuration->signingKey()), + new ExpirationValidator(), + ]; } +} diff --git a/src/Exceptions/SphinxErrorCode.php b/src/Exceptions/SphinxErrorCode.php index 3b7c4e9..1427a9f 100644 --- a/src/Exceptions/SphinxErrorCode.php +++ b/src/Exceptions/SphinxErrorCode.php @@ -2,19 +2,19 @@ namespace Hans\Sphinx\Exceptions; - class SphinxErrorCode - { - public const TOKEN_EXPIRED = 1001; - public const DECODE_FAILED = 1003; - public const ROLE_NOT_FOUND = 1004; - public const ROLE_VERSION_NOT_FOUND = 1005; - public const TOKEN_IS_OUT_OF_DATE = 1006; - public const SESSION_NOT_FOUND = 1007; - public const USERS_VERSION_NOT_FOUND = 1008; - public const TOKEN_MISMATCH = 1010; - public const CAPTURE_SESSION_FAILED = 1011; - public const FAILED_TO_SET_CLAIM = 1012; - public const FAILED_TO_SET_HEADER = 1013; - public const FAILED_TO_CREATE_TOKEN = 1014; - public const FAILED_TO_CREATE_REFRESH_TOKEN = 1015; - } +class SphinxErrorCode +{ + public const TOKEN_EXPIRED = 1001; + public const DECODE_FAILED = 1003; + public const ROLE_NOT_FOUND = 1004; + public const ROLE_VERSION_NOT_FOUND = 1005; + public const TOKEN_IS_OUT_OF_DATE = 1006; + public const SESSION_NOT_FOUND = 1007; + public const USERS_VERSION_NOT_FOUND = 1008; + public const TOKEN_MISMATCH = 1010; + public const CAPTURE_SESSION_FAILED = 1011; + public const FAILED_TO_SET_CLAIM = 1012; + public const FAILED_TO_SET_HEADER = 1013; + public const FAILED_TO_CREATE_TOKEN = 1014; + public const FAILED_TO_CREATE_REFRESH_TOKEN = 1015; +} diff --git a/src/Exceptions/SphinxException.php b/src/Exceptions/SphinxException.php index 2e5009a..2b92aa1 100644 --- a/src/Exceptions/SphinxException.php +++ b/src/Exceptions/SphinxException.php @@ -2,36 +2,36 @@ namespace Hans\Sphinx\Exceptions; - use Exception; - use Illuminate\Http\JsonResponse; - use Throwable; +use Exception; +use Illuminate\Http\JsonResponse; +use Throwable; - class SphinxException extends Exception - { - private int $errorCode; +class SphinxException extends Exception +{ + private int $errorCode; - public function __construct(string $message, int $errorCode, int $responseCode = 500, Throwable $previous = null) - { - parent::__construct($message, $responseCode, $previous); - $this->errorCode = $errorCode; - } + public function __construct(string $message, int $errorCode, int $responseCode = 500, Throwable $previous = null) + { + parent::__construct($message, $responseCode, $previous); + $this->errorCode = $errorCode; + } - /** - * Render the exception into an HTTP response. - * - * @return JsonResponse - */ - public function render(): JsonResponse - { - return new JsonResponse([ - 'code' => $this->getErrorCode(), - 'detail' => $this->getMessage(), - 'title' => 'Unexpected error!', - ], $this->getCode()); - } + /** + * Render the exception into an HTTP response. + * + * @return JsonResponse + */ + public function render(): JsonResponse + { + return new JsonResponse([ + 'code' => $this->getErrorCode(), + 'detail' => $this->getMessage(), + 'title' => 'Unexpected error!', + ], $this->getCode()); + } - public function getErrorCode(): int - { - return $this->errorCode; - } + public function getErrorCode(): int + { + return $this->errorCode; } +} diff --git a/src/Facades/Sphinx.php b/src/Facades/Sphinx.php index ccaed86..9c026a8 100644 --- a/src/Facades/Sphinx.php +++ b/src/Facades/Sphinx.php @@ -2,48 +2,48 @@ namespace Hans\Sphinx\Facades; - use Hans\Sphinx\Models\Session; - use Hans\Sphinx\Services\SphinxService; - use Illuminate\Contracts\Auth\Authenticatable; - use Illuminate\Support\Facades\Facade; - use Lcobucci\JWT\UnencryptedToken; - use RuntimeException; +use Hans\Sphinx\Models\Session; +use Hans\Sphinx\Services\SphinxService; +use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Support\Facades\Facade; +use Lcobucci\JWT\UnencryptedToken; +use RuntimeException; +/** + * @method static UnencryptedToken decode( string $token ) + * @method static SphinxService generateTokenFor( Authenticatable $user ) + * @method static string getAccessToken() + * @method static string getRefreshToken() + * @method static SphinxService claim( string $key, string|int|array $value ) + * @method static SphinxService header( string $key, string|int|array $value ) + * @method static bool validateWrapperAccessToken( string $token ) + * @method static void assertWrapperAccessToken( string $token ) + * @method static bool validateInnerAccessToken( string $token ) + * @method static void assertInnerAccessToken( string $token ) + * @method static UnencryptedToken getInnerAccessToken( string $token ) + * @method static bool validateWrapperRefreshToken( string $token ) + * @method static void assertWrapperRefreshToken( string $token ) + * @method static bool validateInnerRefreshToken( string $token ) + * @method static void assertInnerRefreshToken( string $token ) + * @method static UnencryptedToken getInnerRefreshToken( string $token ) + * @method static array getPermissions( string $token ) + * @method static bool isRefreshToken( string $token ) + * @method static bool isNotRefreshToken( string $token ) + * @method static Session|null getCurrentSession() + * + * @see SphinxService + */ +class Sphinx extends Facade +{ /** - * @method static UnencryptedToken decode( string $token ) - * @method static SphinxService generateTokenFor( Authenticatable $user ) - * @method static string getAccessToken() - * @method static string getRefreshToken() - * @method static SphinxService claim( string $key, string|int|array $value ) - * @method static SphinxService header( string $key, string|int|array $value ) - * @method static bool validateWrapperAccessToken( string $token ) - * @method static void assertWrapperAccessToken( string $token ) - * @method static bool validateInnerAccessToken( string $token ) - * @method static void assertInnerAccessToken( string $token ) - * @method static UnencryptedToken getInnerAccessToken( string $token ) - * @method static bool validateWrapperRefreshToken( string $token ) - * @method static void assertWrapperRefreshToken( string $token ) - * @method static bool validateInnerRefreshToken( string $token ) - * @method static void assertInnerRefreshToken( string $token ) - * @method static UnencryptedToken getInnerRefreshToken( string $token ) - * @method static array getPermissions( string $token ) - * @method static bool isRefreshToken( string $token ) - * @method static bool isNotRefreshToken( string $token ) - * @method static Session|null getCurrentSession() + * Get the registered name of the component. * - * @see SphinxService + * @throws RuntimeException + * + * @return string */ - class Sphinx extends Facade + protected static function getFacadeAccessor() { - /** - * Get the registered name of the component. - * - * @throws RuntimeException - * - * @return string - */ - protected static function getFacadeAccessor() - { - return 'sphinx-service'; - } + return 'sphinx-service'; } +} diff --git a/src/Helpers/Enums/SphinxCache.php b/src/Helpers/Enums/SphinxCache.php index 0b35a35..c46ee44 100644 --- a/src/Helpers/Enums/SphinxCache.php +++ b/src/Helpers/Enums/SphinxCache.php @@ -2,7 +2,7 @@ namespace Hans\Sphinx\Helpers\Enums; - enum SphinxCache: string - { - public const SESSION = 'sphinx_session_cache_'; - } +enum SphinxCache: string +{ + public const SESSION = 'sphinx_session_cache_'; +} diff --git a/src/Models/Session.php b/src/Models/Session.php index 5e1c8f2..37e01e2 100644 --- a/src/Models/Session.php +++ b/src/Models/Session.php @@ -2,77 +2,77 @@ namespace Hans\Sphinx\Models; - use Hans\Sphinx\Helpers\Enums\SphinxCache; - use Illuminate\Database\Eloquent\Model; - use Illuminate\Database\Eloquent\Relations\MorphTo; - use Illuminate\Support\Facades\Cache; +use Hans\Sphinx\Helpers\Enums\SphinxCache; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\MorphTo; +use Illuminate\Support\Facades\Cache; +/** + * Attributes:. + * + * @property int $id + * @property string $ip + * @property string $device + * @property string $browser + * @property string $os + * @property string $secret + * @property int $sessionable_version + * + * Relationships: + * @property Model $sessionable + */ +class Session extends Model +{ /** - * Attributes:. + * The attributes that are mass assignable. * - * @property int $id - * @property string $ip - * @property string $device - * @property string $browser - * @property string $os - * @property string $secret - * @property int $sessionable_version + * @var array + */ + protected $fillable = [ + 'ip', + 'device', + 'browser', + 'os', + 'secret', + 'sessionable_version', + ]; + + /** + * Perform any actions required after the model boots. * - * Relationships: - * @property Model $sessionable + * @return void */ - class Session extends Model + protected static function booted(): void { - /** - * The attributes that are mass assignable. - * - * @var array - */ - protected $fillable = [ - 'ip', - 'device', - 'browser', - 'os', - 'secret', - 'sessionable_version', - ]; - - /** - * Perform any actions required after the model boots. - * - * @return void - */ - protected static function booted(): void - { - self::saved(function (self $model) { - Cache::forget(SphinxCache::SESSION.$model->id); - Cache::forever(SphinxCache::SESSION.$model->id, $model); - }); - self::deleted(fn (self $model) => Cache::forget(SphinxCache::SESSION.$model->id)); - } + self::saved(function (self $model) { + Cache::forget(SphinxCache::SESSION.$model->id); + Cache::forever(SphinxCache::SESSION.$model->id, $model); + }); + self::deleted(fn (self $model) => Cache::forget(SphinxCache::SESSION.$model->id)); + } - /** - * Sessionable relationship. - * - * @return MorphTo - */ - public function sessionable(): MorphTo - { - return $this->morphTo(); - } + /** + * Sessionable relationship. + * + * @return MorphTo + */ + public function sessionable(): MorphTo + { + return $this->morphTo(); + } - /** - * Find the given id and cache the result. - * - * @param int $id - * - * @return Session - */ - public static function findAndCache(int $id): self - { - return Cache::rememberForever( - SphinxCache::SESSION.$id, - fn () => self::query()->findOrFail($id) - ); - } + /** + * Find the given id and cache the result. + * + * @param int $id + * + * @return Session + */ + public static function findAndCache(int $id): self + { + return Cache::rememberForever( + SphinxCache::SESSION.$id, + fn () => self::query()->findOrFail($id) + ); } +} diff --git a/src/Services/SphinxGuard.php b/src/Services/SphinxGuard.php index 474499a..0b670ce 100644 --- a/src/Services/SphinxGuard.php +++ b/src/Services/SphinxGuard.php @@ -2,180 +2,180 @@ namespace Hans\Sphinx\Services; - use Hans\Sphinx\Facades\Sphinx; - use Illuminate\Auth\GuardHelpers; - use Illuminate\Contracts\Auth\Authenticatable; - use Illuminate\Contracts\Auth\Guard; - use Illuminate\Http\Request; - use Illuminate\Support\Traits\Macroable; - - class SphinxGuard implements Authenticatable, Guard +use Hans\Sphinx\Facades\Sphinx; +use Illuminate\Auth\GuardHelpers; +use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Contracts\Auth\Guard; +use Illuminate\Http\Request; +use Illuminate\Support\Traits\Macroable; + +class SphinxGuard implements Authenticatable, Guard +{ + use GuardHelpers; + use Macroable; + + public function __construct( + SphinxUserProvider $provider, + private readonly Request $request, + ) { + $this->provider = $provider; + $this->loginUsingToken($request->bearerToken()); + } + + /** + * Get the name of the unique identifier for the user. + * + * @return string + */ + public function getAuthIdentifierName(): string { - use GuardHelpers; - use Macroable; - - public function __construct( - SphinxUserProvider $provider, - private readonly Request $request, - ) { - $this->provider = $provider; - $this->loginUsingToken($request->bearerToken()); - } + return $this->user->getKeyName(); + } - /** - * Get the name of the unique identifier for the user. - * - * @return string - */ - public function getAuthIdentifierName(): string - { - return $this->user->getKeyName(); - } + /** + * Get the unique identifier for the user. + * + * @return mixed + */ + public function getAuthIdentifier(): mixed + { + return $this->user->{$this->getAuthIdentifierName()}; + } - /** - * Get the unique identifier for the user. - * - * @return mixed - */ - public function getAuthIdentifier(): mixed - { - return $this->user->{$this->getAuthIdentifierName()}; + /** + * Get the password for the user. + * + * @return string + */ + public function getAuthPassword(): string + { + if ($password = $this->user->password) { + return $password; } - /** - * Get the password for the user. - * - * @return string - */ - public function getAuthPassword(): string - { - if ($password = $this->user->password) { - return $password; - } - - return $this->provider->retrieveById($this->user->getAuthIdentifier())->getAuthPassword(); - } + return $this->provider->retrieveById($this->user->getAuthIdentifier())->getAuthPassword(); + } - /** - * Get the token value for the "remember me" session. - * - * @return void - */ - public function getRememberToken(): void - { - // no action needed - } + /** + * Get the token value for the "remember me" session. + * + * @return void + */ + public function getRememberToken(): void + { + // no action needed + } - /** - * Set the token value for the "remember me" session. - * - * @param string $value - * - * @return void - */ - public function setRememberToken($value = null): void - { - // no action needed - } + /** + * Set the token value for the "remember me" session. + * + * @param string $value + * + * @return void + */ + public function setRememberToken($value = null): void + { + // no action needed + } - /** - * Get the column name for the "remember me" token. - * - * @return void - */ - public function getRememberTokenName(): void - { - // no action needed - } + /** + * Get the column name for the "remember me" token. + * + * @return void + */ + public function getRememberTokenName(): void + { + // no action needed + } - /** - * Get the currently authenticated user. - * - * @return Authenticatable|null - */ - public function user(): ?Authenticatable - { - return $this->user ?? null; - } + /** + * Get the currently authenticated user. + * + * @return Authenticatable|null + */ + public function user(): ?Authenticatable + { + return $this->user ?? null; + } - /** - * Attempt to authenticate a user using the given credentials. - * - * @param array $credentials - * - * @return bool - */ - public function attempt(array $credentials): bool - { - $user = $this->provider->retrieveByCredentials($credentials); - if (!is_null($user) and $this->provider->validateCredentials($user, $credentials)) { - $this->login($user); - - return true; - } - - return false; - } + /** + * Attempt to authenticate a user using the given credentials. + * + * @param array $credentials + * + * @return bool + */ + public function attempt(array $credentials): bool + { + $user = $this->provider->retrieveByCredentials($credentials); + if (!is_null($user) and $this->provider->validateCredentials($user, $credentials)) { + $this->login($user); - /** - * Log the given user ID into the application. - * - * @param int $id - * - * @return Authenticatable|null - */ - public function loginUsingId(int $id): ?Authenticatable - { - $this->user = $this->provider->retrieveById($id); - - return $this->user; + return true; } - /** - * Validate a user's credentials. - * - * @param array $credentials - * - * @return bool - */ - public function validate(array $credentials = []): bool - { - $user = $this->provider->retrieveByCredentials($credentials); - if (!is_null($user) and $this->provider->validateCredentials($user, $credentials)) { - return true; - } - - return false; - } + return false; + } + + /** + * Log the given user ID into the application. + * + * @param int $id + * + * @return Authenticatable|null + */ + public function loginUsingId(int $id): ?Authenticatable + { + $this->user = $this->provider->retrieveById($id); - /** - * Log a user into the application. - * - * @param Authenticatable $user - * - * @return void - */ - public function login(Authenticatable $user): void - { - $this->setUser($user); + return $this->user; + } + + /** + * Validate a user's credentials. + * + * @param array $credentials + * + * @return bool + */ + public function validate(array $credentials = []): bool + { + $user = $this->provider->retrieveByCredentials($credentials); + if (!is_null($user) and $this->provider->validateCredentials($user, $credentials)) { + return true; } - /** - * Create the user instance using validated jwt token. - * - * @param string|null $token - * - * @return void - */ - public function loginUsingToken(?string $token): void - { - if ($token and Sphinx::isNotRefreshToken($token)) { - $this->user = $this->provider - ->retrieveByJwtTokenCredentials( - Sphinx::getInnerAccessToken($token) - ->claims() - ->get('user') - ); - } + return false; + } + + /** + * Log a user into the application. + * + * @param Authenticatable $user + * + * @return void + */ + public function login(Authenticatable $user): void + { + $this->setUser($user); + } + + /** + * Create the user instance using validated jwt token. + * + * @param string|null $token + * + * @return void + */ + public function loginUsingToken(?string $token): void + { + if ($token and Sphinx::isNotRefreshToken($token)) { + $this->user = $this->provider + ->retrieveByJwtTokenCredentials( + Sphinx::getInnerAccessToken($token) + ->claims() + ->get('user') + ); } } +} diff --git a/src/Services/SphinxService.php b/src/Services/SphinxService.php index 985f0b7..d75f4d4 100644 --- a/src/Services/SphinxService.php +++ b/src/Services/SphinxService.php @@ -2,515 +2,515 @@ namespace Hans\Sphinx\Services; - use Hans\Sphinx\Drivers\InnerAccessToken; - use Hans\Sphinx\Drivers\InnerRefreshToken; - use Hans\Sphinx\Drivers\WrapperAccessToken; - use Hans\Sphinx\Drivers\WrapperRefreshToken; - use Hans\Sphinx\Exceptions\SphinxErrorCode; - use Hans\Sphinx\Exceptions\SphinxException; - use Hans\Sphinx\Models\Session; - use Illuminate\Contracts\Auth\Authenticatable; - use Lcobucci\JWT\UnencryptedToken; - use Symfony\Component\HttpFoundation\Response as ResponseAlias; - use Throwable; - - class SphinxService +use Hans\Sphinx\Drivers\InnerAccessToken; +use Hans\Sphinx\Drivers\InnerRefreshToken; +use Hans\Sphinx\Drivers\WrapperAccessToken; +use Hans\Sphinx\Drivers\WrapperRefreshToken; +use Hans\Sphinx\Exceptions\SphinxErrorCode; +use Hans\Sphinx\Exceptions\SphinxException; +use Hans\Sphinx\Models\Session; +use Illuminate\Contracts\Auth\Authenticatable; +use Lcobucci\JWT\UnencryptedToken; +use Symfony\Component\HttpFoundation\Response as ResponseAlias; +use Throwable; + +class SphinxService +{ + /** + * Wrapper access token provider instance. + * + * @var WrapperAccessToken + */ + private WrapperAccessToken $wrapperAccessTokenProvider; + + /** + * Inner access token provider instance. + * + * @var InnerAccessToken + */ + private InnerAccessToken $innerAccessTokenProvider; + + /** + * Wrapper refresh token provider instance. + * + * @var WrapperRefreshToken + */ + private WrapperRefreshToken $wrapperRefreshTokenProvider; + + /** + * Inner refresh token provider instance. + * + * @var InnerRefreshToken + */ + private InnerRefreshToken $innerRefreshTokenProvider; + + /** + * Related session instance. + * + * @var Session|null + */ + private ?Session $session = null; + + /** + * @throws SphinxException + */ + public function __construct() { - /** - * Wrapper access token provider instance. - * - * @var WrapperAccessToken - */ - private WrapperAccessToken $wrapperAccessTokenProvider; - - /** - * Inner access token provider instance. - * - * @var InnerAccessToken - */ - private InnerAccessToken $innerAccessTokenProvider; - - /** - * Wrapper refresh token provider instance. - * - * @var WrapperRefreshToken - */ - private WrapperRefreshToken $wrapperRefreshTokenProvider; - - /** - * Inner refresh token provider instance. - * - * @var InnerRefreshToken - */ - private InnerRefreshToken $innerRefreshTokenProvider; - - /** - * Related session instance. - * - * @var Session|null - */ - private ?Session $session = null; - - /** - * @throws SphinxException - */ - public function __construct() - { - $this->wrapperAccessTokenProvider = new WrapperAccessToken(sphinx_config('secret')); - $this->wrapperRefreshTokenProvider = new WrapperRefreshToken(sphinx_config('secret')); - $this->guessSession(); - } + $this->wrapperAccessTokenProvider = new WrapperAccessToken(sphinx_config('secret')); + $this->wrapperRefreshTokenProvider = new WrapperRefreshToken(sphinx_config('secret')); + $this->guessSession(); + } - /** - * Decode the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return UnencryptedToken - */ - public function decode(string $token): UnencryptedToken - { - return $this->wrapperAccessTokenProvider->decode($token); - } + /** + * Decode the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return UnencryptedToken + */ + public function decode(string $token): UnencryptedToken + { + return $this->wrapperAccessTokenProvider->decode($token); + } - /** - * Generate tokens for given user. - * - * @throws SphinxException - */ - public function generateTokenFor(Authenticatable $user): self - { - $this->openASessionFor($user); + /** + * Generate tokens for given user. + * + * @throws SphinxException + */ + public function generateTokenFor(Authenticatable $user): self + { + $this->openASessionFor($user); - $this->createAccessToken($user); - $this->createRefreshToken($user); + $this->createAccessToken($user); + $this->createRefreshToken($user); - return $this; - } + return $this; + } - /** - * Return generated access token. - * - * @return string - */ - public function getAccessToken(): string - { - $this->wrapperAccessTokenProvider - ->claim('_token', $this->innerAccessTokenProvider->getToken()->toString()); + /** + * Return generated access token. + * + * @return string + */ + public function getAccessToken(): string + { + $this->wrapperAccessTokenProvider + ->claim('_token', $this->innerAccessTokenProvider->getToken()->toString()); - return $this->wrapperAccessTokenProvider->getToken()->toString(); - } + return $this->wrapperAccessTokenProvider->getToken()->toString(); + } - /** - * Return generated refresh token. - * - * @return string - */ - public function getRefreshToken(): string - { - $this->wrapperRefreshTokenProvider - ->claim('_token', $this->innerRefreshTokenProvider->getToken()->toString()); + /** + * Return generated refresh token. + * + * @return string + */ + public function getRefreshToken(): string + { + $this->wrapperRefreshTokenProvider + ->claim('_token', $this->innerRefreshTokenProvider->getToken()->toString()); - return $this->wrapperRefreshTokenProvider->getToken()->toString(); - } + return $this->wrapperRefreshTokenProvider->getToken()->toString(); + } - /** - * Add a custom claim to the token. - * - * @param string $key - * @param string|int|array $value - * - * @return $this - */ - public function claim(string $key, string|int|array $value): self - { - $this->innerAccessTokenProvider->claim($key, $value); - - return $this; - } + /** + * Add a custom claim to the token. + * + * @param string $key + * @param string|int|array $value + * + * @return $this + */ + public function claim(string $key, string|int|array $value): self + { + $this->innerAccessTokenProvider->claim($key, $value); - /** - * Add a custom header to the token. - * - * @param string $key - * @param string|int|array $value - * - * @return $this - */ - public function header(string $key, string|int|array $value): self - { - $this->innerAccessTokenProvider->header($key, $value); - - return $this; - } + return $this; + } - /** - * Validate wrapper access token of the given token. - * - * @param string $token - * - * @return bool - */ - public function validateWrapperAccessToken(string $token): bool - { - return $this->wrapperAccessTokenProvider->validate($token); - } + /** + * Add a custom header to the token. + * + * @param string $key + * @param string|int|array $value + * + * @return $this + */ + public function header(string $key, string|int|array $value): self + { + $this->innerAccessTokenProvider->header($key, $value); - /** - * Assert wrapper access token of the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return void - */ - public function assertWrapperAccessToken(string $token): void - { - $this->wrapperAccessTokenProvider->assert($token); - } + return $this; + } - /** - * Validate inner access token of the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return bool - */ - public function validateInnerAccessToken(string $token): bool - { - if (!$this->validateWrapperAccessToken($token)) { - return false; - } - $token = $this->wrapperAccessTokenProvider->decode($token); - $insideToken = $token->claims()->get('_token'); + /** + * Validate wrapper access token of the given token. + * + * @param string $token + * + * @return bool + */ + public function validateWrapperAccessToken(string $token): bool + { + return $this->wrapperAccessTokenProvider->validate($token); + } - return $this->innerAccessTokenProvider->validate($insideToken); - } + /** + * Assert wrapper access token of the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return void + */ + public function assertWrapperAccessToken(string $token): void + { + $this->wrapperAccessTokenProvider->assert($token); + } - /** - * Assert inner access token of the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return void - */ - public function assertInnerAccessToken(string $token): void - { - $this->assertWrapperAccessToken($token); - $token = $this->wrapperAccessTokenProvider->decode($token); - $insideToken = $token->claims()->get('_token'); - - $this->innerAccessTokenProvider->assert($insideToken); + /** + * Validate inner access token of the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return bool + */ + public function validateInnerAccessToken(string $token): bool + { + if (!$this->validateWrapperAccessToken($token)) { + return false; } + $token = $this->wrapperAccessTokenProvider->decode($token); + $insideToken = $token->claims()->get('_token'); - /** - * Return inner access token of the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return UnencryptedToken - */ - public function getInnerAccessToken(string $token): UnencryptedToken - { - $this->assertInnerAccessToken($token); - $token = $this->wrapperAccessTokenProvider->decode($token); - $insideToken = $token->claims()->get('_token'); - - return $this->innerAccessTokenProvider->decode($insideToken); - } + return $this->innerAccessTokenProvider->validate($insideToken); + } - /** - * Validate wrapper refresh token of the given token. - * - * @param string $token - * - * @return bool - */ - public function validateWrapperRefreshToken(string $token): bool - { - return $this->wrapperRefreshTokenProvider->validate($token); - } + /** + * Assert inner access token of the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return void + */ + public function assertInnerAccessToken(string $token): void + { + $this->assertWrapperAccessToken($token); + $token = $this->wrapperAccessTokenProvider->decode($token); + $insideToken = $token->claims()->get('_token'); - /** - * Assert wrapper refresh token of the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return void - */ - public function assertWrapperRefreshToken(string $token): void - { - $this->wrapperRefreshTokenProvider->assert($token); - } + $this->innerAccessTokenProvider->assert($insideToken); + } - /** - * Validate inner refresh token of the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return bool - */ - public function validateInnerRefreshToken(string $token): bool - { - if (!$this->validateWrapperRefreshToken($token)) { - return false; - } - $token = $this->wrapperRefreshTokenProvider->decode($token); - $insideToken = $token->claims()->get('_token'); + /** + * Return inner access token of the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return UnencryptedToken + */ + public function getInnerAccessToken(string $token): UnencryptedToken + { + $this->assertInnerAccessToken($token); + $token = $this->wrapperAccessTokenProvider->decode($token); + $insideToken = $token->claims()->get('_token'); - return $this->innerRefreshTokenProvider->validate($insideToken); - } + return $this->innerAccessTokenProvider->decode($insideToken); + } - /** - * Assert inner refresh token of the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return void - */ - public function assertInnerRefreshToken(string $token): void - { - $token = $this->wrapperRefreshTokenProvider->decode($token); - $insideToken = $token->claims()->get('_token'); - - $this->innerRefreshTokenProvider->assert($insideToken); - } + /** + * Validate wrapper refresh token of the given token. + * + * @param string $token + * + * @return bool + */ + public function validateWrapperRefreshToken(string $token): bool + { + return $this->wrapperRefreshTokenProvider->validate($token); + } - /** - * Return inner refresh token of the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return UnencryptedToken - */ - public function getInnerRefreshToken(string $token): UnencryptedToken - { - $this->assertInnerRefreshToken($token); - $token = $this->wrapperRefreshTokenProvider->decode($token); - $insideToken = $token->claims()->get('_token'); - - return $this->innerRefreshTokenProvider->decode($insideToken); - } + /** + * Assert wrapper refresh token of the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return void + */ + public function assertWrapperRefreshToken(string $token): void + { + $this->wrapperRefreshTokenProvider->assert($token); + } - /** - * Get permissions of the given token. - * - * @param string $token - * - * @throws SphinxException - * - * @return array - */ - public function getPermissions(string $token): array - { - return $this->getInnerAccessToken($token)->claims()->get('permissions'); + /** + * Validate inner refresh token of the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return bool + */ + public function validateInnerRefreshToken(string $token): bool + { + if (!$this->validateWrapperRefreshToken($token)) { + return false; } + $token = $this->wrapperRefreshTokenProvider->decode($token); + $insideToken = $token->claims()->get('_token'); - /** - * Determine the token is refresh token or not. - * - * @param string $token - * - * @throws SphinxException - * - * @return bool - */ - public function isRefreshToken(string $token): bool - { - return $this->decode($token)->headers()->get('refresh', false); - } + return $this->innerRefreshTokenProvider->validate($insideToken); + } - /** - * Determine the token is not a refresh token. - * - * @param string $token - * - * @throws SphinxException - * - * @return bool - */ - public function isNotRefreshToken(string $token): bool - { - return !$this->isRefreshToken($token); - } + /** + * Assert inner refresh token of the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return void + */ + public function assertInnerRefreshToken(string $token): void + { + $token = $this->wrapperRefreshTokenProvider->decode($token); + $insideToken = $token->claims()->get('_token'); - /** - * Return current selected session. - * - * @return Session|null - */ - public function getCurrentSession(): ?Session - { - return $this->session; - } + $this->innerRefreshTokenProvider->assert($insideToken); + } - /** - * Configure wrapper and inner access token instances. - * - * @param Authenticatable $user - * - * @throws SphinxException - * - * @return void - */ - private function createAccessToken(Authenticatable $user): void - { - try { - $this->wrapperAccessTokenProvider - ->encode() - ->expiresAt(sphinx_config('access_expired_at')) - ->header('session_id', $this->session->id) - ->header('sessionable_version', $user->getVersion()) - ->headerWhen( - isset($user->extractRole()['id']), - 'role_id', - fn () => $user->extractRole()['id'] - ) - ->headerWhen( - isset($user->extractRole()['version']), - 'role_version', - fn () => $user->extractRole()['version'] - ); - - $this->innerAccessTokenProvider - ->encode() - ->claim( - 'role', - collect($user->extractRole())->only('id', 'name') + /** + * Return inner refresh token of the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return UnencryptedToken + */ + public function getInnerRefreshToken(string $token): UnencryptedToken + { + $this->assertInnerRefreshToken($token); + $token = $this->wrapperRefreshTokenProvider->decode($token); + $insideToken = $token->claims()->get('_token'); + + return $this->innerRefreshTokenProvider->decode($insideToken); + } + + /** + * Get permissions of the given token. + * + * @param string $token + * + * @throws SphinxException + * + * @return array + */ + public function getPermissions(string $token): array + { + return $this->getInnerAccessToken($token)->claims()->get('permissions'); + } + + /** + * Determine the token is refresh token or not. + * + * @param string $token + * + * @throws SphinxException + * + * @return bool + */ + public function isRefreshToken(string $token): bool + { + return $this->decode($token)->headers()->get('refresh', false); + } + + /** + * Determine the token is not a refresh token. + * + * @param string $token + * + * @throws SphinxException + * + * @return bool + */ + public function isNotRefreshToken(string $token): bool + { + return !$this->isRefreshToken($token); + } + + /** + * Return current selected session. + * + * @return Session|null + */ + public function getCurrentSession(): ?Session + { + return $this->session; + } + + /** + * Configure wrapper and inner access token instances. + * + * @param Authenticatable $user + * + * @throws SphinxException + * + * @return void + */ + private function createAccessToken(Authenticatable $user): void + { + try { + $this->wrapperAccessTokenProvider + ->encode() + ->expiresAt(sphinx_config('access_expired_at')) + ->header('session_id', $this->session->id) + ->header('sessionable_version', $user->getVersion()) + ->headerWhen( + isset($user->extractRole()['id']), + 'role_id', + fn () => $user->extractRole()['id'] + ) + ->headerWhen( + isset($user->extractRole()['version']), + 'role_version', + fn () => $user->extractRole()['version'] + ); + + $this->innerAccessTokenProvider + ->encode() + ->claim( + 'role', + collect($user->extractRole())->only('id', 'name') + ) + ->claim( + 'permissions', + collect($user->extractPermissions()) + ->pluck('name', 'id') + ->toArray() + ) + ->claim( + 'user', + array_merge( + $user->extract(), + [ + 'id' => $user->id, + $user->username() => $user->{$user->username()}, + ] ) - ->claim( - 'permissions', - collect($user->extractPermissions()) - ->pluck('name', 'id') - ->toArray() + ); + } catch (Throwable $e) { + throw new SphinxException( + 'Failed to create token! '.$e->getMessage(), + SphinxErrorCode::FAILED_TO_CREATE_TOKEN, + ResponseAlias::HTTP_FORBIDDEN + ); + } + } + + /** + * Configure wrapper and inner refresh token instances. + * + * @param Authenticatable $user + * + * @throws SphinxException + * + * @return void + */ + private function createRefreshToken(Authenticatable $user): void + { + try { + $this->wrapperRefreshTokenProvider + ->encode() + ->expiresAt(sphinx_config('refresh_expired_at')) + ->header('refresh', true); + $this->innerRefreshTokenProvider + ->encode() + ->claim( + 'user', + array_merge( + $user->extract(), + [ + 'id' => $user->id, + $user->username() => $user->{$user->username()}, + ] ) - ->claim( - 'user', - array_merge( - $user->extract(), - [ - 'id' => $user->id, - $user->username() => $user->{$user->username()}, - ] - ) - ); - } catch (Throwable $e) { - throw new SphinxException( - 'Failed to create token! '.$e->getMessage(), - SphinxErrorCode::FAILED_TO_CREATE_TOKEN, - ResponseAlias::HTTP_FORBIDDEN ); - } + } catch (Throwable $e) { + throw new SphinxException( + 'Failed to create refresh token! '.$e->getMessage(), + SphinxErrorCode::FAILED_TO_CREATE_REFRESH_TOKEN, + ResponseAlias::HTTP_FORBIDDEN + ); } + } + + /** + * Guess the related session using authorization token. + * + * @throws SphinxException + * + * @return void + */ + private function guessSession(): void + { + if ($token = request()->bearerToken()) { + $session_id = $this->wrapperAccessTokenProvider + ->decode($token) + ->headers() + ->get('session_id'); - /** - * Configure wrapper and inner refresh token instances. - * - * @param Authenticatable $user - * - * @throws SphinxException - * - * @return void - */ - private function createRefreshToken(Authenticatable $user): void - { try { - $this->wrapperRefreshTokenProvider - ->encode() - ->expiresAt(sphinx_config('refresh_expired_at')) - ->header('refresh', true); - $this->innerRefreshTokenProvider - ->encode() - ->claim( - 'user', - array_merge( - $user->extract(), - [ - 'id' => $user->id, - $user->username() => $user->{$user->username()}, - ] - ) - ); + $this->session = Session::findAndCache($session_id); } catch (Throwable $e) { throw new SphinxException( - 'Failed to create refresh token! '.$e->getMessage(), - SphinxErrorCode::FAILED_TO_CREATE_REFRESH_TOKEN, + 'Token expired! probably reached your device count limit.', + SphinxErrorCode::TOKEN_EXPIRED, ResponseAlias::HTTP_FORBIDDEN ); } - } - /** - * Guess the related session using authorization token. - * - * @throws SphinxException - * - * @return void - */ - private function guessSession(): void - { - if ($token = request()->bearerToken()) { - $session_id = $this->wrapperAccessTokenProvider - ->decode($token) - ->headers() - ->get('session_id'); - - try { - $this->session = Session::findAndCache($session_id); - } catch (Throwable $e) { - throw new SphinxException( - 'Token expired! probably reached your device count limit.', - SphinxErrorCode::TOKEN_EXPIRED, - ResponseAlias::HTTP_FORBIDDEN - ); - } - - $this->initInnerTokensInstance(); - } + $this->initInnerTokensInstance(); } + } - /** - * Open a new session for given user. - * - * @param Authenticatable $user - * - * @throws SphinxException - * - * @return void - */ - private function openASessionFor(Authenticatable $user): void - { - $capturedSession = capture_session($user); - $this->session = Session::findAndCache($capturedSession->id); + /** + * Open a new session for given user. + * + * @param Authenticatable $user + * + * @throws SphinxException + * + * @return void + */ + private function openASessionFor(Authenticatable $user): void + { + $capturedSession = capture_session($user); + $this->session = Session::findAndCache($capturedSession->id); - $this->initInnerTokensInstance(); - } + $this->initInnerTokensInstance(); + } - /** - * Initialize the inner access tokens. - * - * @return void - */ - private function initInnerTokensInstance(): void - { - $this->innerAccessTokenProvider = new InnerAccessToken($this->session->secret); - $this->innerRefreshTokenProvider = new InnerRefreshToken($this->session->secret); - } + /** + * Initialize the inner access tokens. + * + * @return void + */ + private function initInnerTokensInstance(): void + { + $this->innerAccessTokenProvider = new InnerAccessToken($this->session->secret); + $this->innerRefreshTokenProvider = new InnerRefreshToken($this->session->secret); } +} diff --git a/src/Services/SphinxUserProvider.php b/src/Services/SphinxUserProvider.php index 4658893..1668f8c 100644 --- a/src/Services/SphinxUserProvider.php +++ b/src/Services/SphinxUserProvider.php @@ -2,53 +2,53 @@ namespace Hans\Sphinx\Services; - use Illuminate\Auth\EloquentUserProvider; - use Illuminate\Contracts\Auth\Authenticatable; - use Illuminate\Database\Eloquent\Model; +use Illuminate\Auth\EloquentUserProvider; +use Illuminate\Contracts\Auth\Authenticatable; +use Illuminate\Database\Eloquent\Model; - class SphinxUserProvider extends EloquentUserProvider +class SphinxUserProvider extends EloquentUserProvider +{ + /** + * Retrieve a user by their unique identifier and "remember me" token. + * + * @param mixed $identifier + * @param string $token + * + * @return Authenticatable|null + */ + public function retrieveByToken($identifier, $token = null): ?Authenticatable { - /** - * Retrieve a user by their unique identifier and "remember me" token. - * - * @param mixed $identifier - * @param string $token - * - * @return Authenticatable|null - */ - public function retrieveByToken($identifier, $token = null): ?Authenticatable - { - return $this->retrieveById($identifier); - } + return $this->retrieveById($identifier); + } - /** - * Update the "remember me" token for the given user in storage. - * - * @param Authenticatable|null $user - * @param null $token - * - * @return void - */ - public function updateRememberToken(Authenticatable $user = null, $token = null): void - { - } + /** + * Update the "remember me" token for the given user in storage. + * + * @param Authenticatable|null $user + * @param null $token + * + * @return void + */ + public function updateRememberToken(Authenticatable $user = null, $token = null): void + { + } - /** - * @param array $credentials - * - * @return Model|null - */ - public function retrieveByJwtTokenCredentials(array $credentials): ?Model - { - $instance = $this->createModel(); - if (!isset($credentials[$instance->getAuthIdentifierName()])) { - return null; - } + /** + * @param array $credentials + * + * @return Model|null + */ + public function retrieveByJwtTokenCredentials(array $credentials): ?Model + { + $instance = $this->createModel(); + if (!isset($credentials[$instance->getAuthIdentifierName()])) { + return null; + } - $instance->fill($credentials); - $instance->{$instance->getAuthIdentifierName()} = $credentials[$instance->getAuthIdentifierName()]; - $instance->exists = true; + $instance->fill($credentials); + $instance->{$instance->getAuthIdentifierName()} = $credentials[$instance->getAuthIdentifierName()]; + $instance->exists = true; - return $instance; - } + return $instance; } +} diff --git a/src/SphinxServiceProvider.php b/src/SphinxServiceProvider.php index 0336336..073b987 100644 --- a/src/SphinxServiceProvider.php +++ b/src/SphinxServiceProvider.php @@ -2,61 +2,61 @@ namespace Hans\Sphinx; - use Hans\Sphinx\Services\SphinxGuard; - use Hans\Sphinx\Services\SphinxService; - use Hans\Sphinx\Services\SphinxUserProvider; - use Illuminate\Foundation\Application; - use Illuminate\Support\Facades\Auth; - use Illuminate\Support\ServiceProvider; +use Hans\Sphinx\Services\SphinxGuard; +use Hans\Sphinx\Services\SphinxService; +use Hans\Sphinx\Services\SphinxUserProvider; +use Illuminate\Foundation\Application; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\ServiceProvider; - class SphinxServiceProvider extends ServiceProvider +class SphinxServiceProvider extends ServiceProvider +{ + /** + * Register any application services. + * + * @return void + */ + public function register(): void { - /** - * Register any application services. - * - * @return void - */ - public function register(): void - { - $this->app->bind('sphinx-service', SphinxService::class); + $this->app->bind('sphinx-service', SphinxService::class); - Auth::extend('sphinxJwt', function (Application $app, $name, array $config) { - Auth::provider( - 'sphinx', - fn () => $app->makeWith( - SphinxUserProvider::class, - ['model' => $this->app['config']["auth.providers.{$config['provider']}.model"]] - ) - ); + Auth::extend('sphinxJwt', function (Application $app, $name, array $config) { + Auth::provider( + 'sphinx', + fn () => $app->makeWith( + SphinxUserProvider::class, + ['model' => $this->app['config']["auth.providers.{$config['provider']}.model"]] + ) + ); - return $app->makeWith( - SphinxGuard::class, - [ - 'provider' => Auth::createUserProvider( - $this->app['config']["auth.providers.{$config['provider']}.driver"] - ), - ] - ); - }); - } + return $app->makeWith( + SphinxGuard::class, + [ + 'provider' => Auth::createUserProvider( + $this->app['config']["auth.providers.{$config['provider']}.driver"] + ), + ] + ); + }); + } - /** - * Bootstrap any application services. - * - * @return void - */ - public function boot(): void - { - $this->mergeConfigFrom(__DIR__.'/../config/config.php', 'sphinx'); + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot(): void + { + $this->mergeConfigFrom(__DIR__.'/../config/config.php', 'sphinx'); - if ($this->app->runningInConsole()) { - $this->loadMigrationsFrom(__DIR__.'/../migrations'); - $this->publishes( - [ - __DIR__.'/../config/config.php' => config_path('sphinx.php'), - ], - 'sphinx-config' - ); - } + if ($this->app->runningInConsole()) { + $this->loadMigrationsFrom(__DIR__.'/../migrations'); + $this->publishes( + [ + __DIR__.'/../config/config.php' => config_path('sphinx.php'), + ], + 'sphinx-config' + ); } } +} diff --git a/src/Traits/SphinxMethods.php b/src/Traits/SphinxMethods.php index c9590a3..429e832 100644 --- a/src/Traits/SphinxMethods.php +++ b/src/Traits/SphinxMethods.php @@ -2,95 +2,95 @@ namespace Hans\Sphinx\Traits; - use Hans\Sphinx\Helpers\Enums\SphinxCache; - use Hans\Sphinx\Models\Session; - use Illuminate\Support\Facades\Cache; - use Throwable; +use Hans\Sphinx\Helpers\Enums\SphinxCache; +use Hans\Sphinx\Models\Session; +use Illuminate\Support\Facades\Cache; +use Throwable; - trait SphinxMethods +trait SphinxMethods +{ + /** + * Hooks for increasing version on updates. + * + * @return void + */ + protected static function hooks(): void { - /** - * Hooks for increasing version on updates. - * - * @return void - */ - protected static function hooks(): void - { - static::saved(function (self $model) { - $model->increaseVersion(); - }); - } + static::saved(function (self $model) { + $model->increaseVersion(); + }); + } - /** - * Increase the version and update related sessions. - * - * @return bool - */ - public function increaseVersion(): bool - { - try { - $sessionIds = $this->sessions()->select('id')->get()->pluck('id'); - Session::query() - ->whereIn('id', $sessionIds) - ->increment('sessionable_version'); + /** + * Increase the version and update related sessions. + * + * @return bool + */ + public function increaseVersion(): bool + { + try { + $sessionIds = $this->sessions()->select('id')->get()->pluck('id'); + Session::query() + ->whereIn('id', $sessionIds) + ->increment('sessionable_version'); - $sessions = Session::query()->findMany($sessionIds); - foreach ($sessions as $session) { - Cache::forget($key = SphinxCache::SESSION.$session->id); - Cache::forever($key, $session); - } - } catch (Throwable $e) { - return false; + $sessions = Session::query()->findMany($sessionIds); + foreach ($sessions as $session) { + Cache::forget($key = SphinxCache::SESSION.$session->id); + Cache::forever($key, $session); } - - return true; + } catch (Throwable $e) { + return false; } - /** - * Return user version using the latest opened session. - * - * @return int - */ - public function getVersion(): int - { - return $this->sessions() - ->latest() - ->select('id', 'sessionable_version') - ->first()->sessionable_version ?? 1; - } + return true; + } - /** - * Determine the limitation of logged-in devices using one user credentials. - * - * @return int - */ - abstract public function getDeviceLimit(): int; + /** + * Return user version using the latest opened session. + * + * @return int + */ + public function getVersion(): int + { + return $this->sessions() + ->latest() + ->select('id', 'sessionable_version') + ->first()->sessionable_version ?? 1; + } - /** - * Extract necessary attributes of user. - * - * @return array - */ - abstract public function extract(): array; + /** + * Determine the limitation of logged-in devices using one user credentials. + * + * @return int + */ + abstract public function getDeviceLimit(): int; - /** - * Return username column name. - * - * @return string - */ - abstract public function username(): string; + /** + * Extract necessary attributes of user. + * + * @return array + */ + abstract public function extract(): array; - /** - * Extract attributes of related role. - * - * @return array|null - */ - abstract public function extractRole(): ?array; + /** + * Return username column name. + * + * @return string + */ + abstract public function username(): string; - /** - * Extract related permissions attributes. - * - * @return array|null - */ - abstract public function extractPermissions(): ?array; - } + /** + * Extract attributes of related role. + * + * @return array|null + */ + abstract public function extractRole(): ?array; + + /** + * Extract related permissions attributes. + * + * @return array|null + */ + abstract public function extractPermissions(): ?array; +} diff --git a/src/Traits/SphinxRelationHandler.php b/src/Traits/SphinxRelationHandler.php index 66a4521..add4921 100644 --- a/src/Traits/SphinxRelationHandler.php +++ b/src/Traits/SphinxRelationHandler.php @@ -2,18 +2,18 @@ namespace Hans\Sphinx\Traits; - use Hans\Sphinx\Models\Session; - use Illuminate\Database\Eloquent\Relations\MorphMany; +use Hans\Sphinx\Models\Session; +use Illuminate\Database\Eloquent\Relations\MorphMany; - trait SphinxRelationHandler +trait SphinxRelationHandler +{ + /** + * Relationship definition with session model. + * + * @return MorphMany + */ + public function sessions(): MorphMany { - /** - * Relationship definition with session model. - * - * @return MorphMany - */ - public function sessions(): MorphMany - { - return $this->morphMany(Session::class, 'sessionable'); - } + return $this->morphMany(Session::class, 'sessionable'); } +} diff --git a/src/Traits/SphinxTokenCan.php b/src/Traits/SphinxTokenCan.php index 2fa22eb..2390268 100644 --- a/src/Traits/SphinxTokenCan.php +++ b/src/Traits/SphinxTokenCan.php @@ -2,127 +2,127 @@ namespace Hans\Sphinx\Traits; - use Hans\Sphinx\Facades\Sphinx; - use Illuminate\Support\Str; - - trait SphinxTokenCan +use Hans\Sphinx\Facades\Sphinx; +use Illuminate\Support\Str; + +trait SphinxTokenCan +{ + /** + * @var array + */ + private array $tokenPermissions; + + /** + * Determine if the entity has the given abilities. + * + * @param $abilities + * @param array $arguments + * + * @return bool + */ + public function can($abilities, $arguments = []): bool { - /** - * @var array - */ - private array $tokenPermissions; - - /** - * Determine if the entity has the given abilities. - * - * @param $abilities - * @param array $arguments - * - * @return bool - */ - public function can($abilities, $arguments = []): bool - { - if (is_string($abilities) or is_int($abilities)) { - return $this->tokenCan($abilities); - } + if (is_string($abilities) or is_int($abilities)) { + return $this->tokenCan($abilities); + } - if (is_array($abilities)) { - foreach ($abilities as $ability) { - if (!$this->can($ability)) { - return false; - } + if (is_array($abilities)) { + foreach ($abilities as $ability) { + if (!$this->can($ability)) { + return false; } - - return true; } - return false; + return true; } - /** - * Determine if the entity has any of the given abilities. - * - * @param iterable|string $abilities - * @param array|mixed $arguments - * - * @return bool - */ - public function canAny($abilities, $arguments = []): bool - { - if (is_string($abilities) or is_int($abilities)) { - return $this->can($abilities); - } + return false; + } - if (is_array($abilities)) { - foreach ($abilities as $ability) { - if ($this->can($ability)) { - return true; - } - } + /** + * Determine if the entity has any of the given abilities. + * + * @param iterable|string $abilities + * @param array|mixed $arguments + * + * @return bool + */ + public function canAny($abilities, $arguments = []): bool + { + if (is_string($abilities) or is_int($abilities)) { + return $this->can($abilities); + } - return false; + if (is_array($abilities)) { + foreach ($abilities as $ability) { + if ($this->can($ability)) { + return true; + } } return false; } - /** - * Determine if the entity does not have the given abilities. - * - * @param iterable|string $abilities - * @param array|mixed $arguments - * - * @return bool - */ - public function cant($abilities, $arguments = []): bool - { - return !$this->can($abilities, $arguments); - } + return false; + } - /** - * Alias for cant method. - * - * @param iterable|string $abilities - * @param array|mixed $arguments - * - * @return bool - */ - public function cannot($abilities, $arguments = []): bool - { - return $this->cant($abilities, $arguments); - } + /** + * Determine if the entity does not have the given abilities. + * + * @param iterable|string $abilities + * @param array|mixed $arguments + * + * @return bool + */ + public function cant($abilities, $arguments = []): bool + { + return !$this->can($abilities, $arguments); + } - /** - * Check the token to contains the given ability. - * - * @param string|int $ability - * - * @return bool - */ - private function tokenCan(string|int $ability): bool - { - if (!isset($this->tokenPermissions)) { - $this->tokenPermissions = Sphinx::getPermissions(request()->bearerToken()); - } - $separator = sphinx_config('permission_separator'); - $model = Str::beforeLast($ability, $separator); + /** + * Alias for cant method. + * + * @param iterable|string $abilities + * @param array|mixed $arguments + * + * @return bool + */ + public function cannot($abilities, $arguments = []): bool + { + return $this->cant($abilities, $arguments); + } - // check for super permissions - if (in_array("*{$separator}*", $this->tokenPermissions)) { - return true; - } - if (in_array("{$model}{$separator}*", $this->tokenPermissions)) { - return true; - } + /** + * Check the token to contains the given ability. + * + * @param string|int $ability + * + * @return bool + */ + private function tokenCan(string|int $ability): bool + { + if (!isset($this->tokenPermissions)) { + $this->tokenPermissions = Sphinx::getPermissions(request()->bearerToken()); + } + $separator = sphinx_config('permission_separator'); + $model = Str::beforeLast($ability, $separator); - // check for ability - if (is_int($ability)) { - return in_array($ability, array_keys($this->tokenPermissions)); - } - if (is_string($ability)) { - return in_array($ability, array_values($this->tokenPermissions)); - } + // check for super permissions + if (in_array("*{$separator}*", $this->tokenPermissions)) { + return true; + } + if (in_array("{$model}{$separator}*", $this->tokenPermissions)) { + return true; + } - return false; + // check for ability + if (is_int($ability)) { + return in_array($ability, array_keys($this->tokenPermissions)); + } + if (is_string($ability)) { + return in_array($ability, array_values($this->tokenPermissions)); } + + return false; } +} diff --git a/src/Traits/SphinxTrait.php b/src/Traits/SphinxTrait.php index 7a7c353..9a57c88 100644 --- a/src/Traits/SphinxTrait.php +++ b/src/Traits/SphinxTrait.php @@ -2,9 +2,9 @@ namespace Hans\Sphinx\Traits; - trait SphinxTrait - { - use SphinxTokenCan; - use SphinxRelationHandler; - use SphinxMethods; - } +trait SphinxTrait +{ + use SphinxTokenCan; + use SphinxRelationHandler; + use SphinxMethods; +} diff --git a/tests/Factories/UserFactory.php b/tests/Factories/UserFactory.php index 2ce57c9..a9ce9ed 100644 --- a/tests/Factories/UserFactory.php +++ b/tests/Factories/UserFactory.php @@ -2,80 +2,80 @@ namespace Hans\Sphinx\Tests\Factories; - use App\Models\User; - use Hans\Horus\Exceptions\HorusException; - use Hans\Sphinx\Exceptions\SphinxException; - use Hans\Sphinx\Facades\Sphinx; - use Hans\Sphinx\Services\SphinxService; - use Hans\Sphinx\Tests\TestCase; +use App\Models\User; +use Hans\Horus\Exceptions\HorusException; +use Hans\Sphinx\Exceptions\SphinxException; +use Hans\Sphinx\Facades\Sphinx; +use Hans\Sphinx\Services\SphinxService; +use Hans\Sphinx\Tests\TestCase; - class UserFactory +class UserFactory +{ + /** + * @return User + */ + public static function creatWithoutRole(): User { - /** - * @return User - */ - public static function creatWithoutRole(): User - { - $user = User::factory()->create(); + $user = User::factory()->create(); - return $user->fresh(); - } - - /** - * @throws HorusException - * - * @return User - */ - public static function createNormalUser(): User - { - $user = User::factory()->create(); - $user->assignRole(TestCase::DEFAULT_USERS); + return $user->fresh(); + } - return $user->fresh(); - } + /** + * @throws HorusException + * + * @return User + */ + public static function createNormalUser(): User + { + $user = User::factory()->create(); + $user->assignRole(TestCase::DEFAULT_USERS); - /** - * @throws HorusException - * @throws SphinxException - * - * @return User - */ - public static function createNormalUserWithSession(): User - { - $user = User::factory()->create(); - $user->assignRole(TestCase::DEFAULT_USERS); - capture_session($user); + return $user->fresh(); + } - return $user->fresh(); - } + /** + * @throws HorusException + * @throws SphinxException + * + * @return User + */ + public static function createNormalUserWithSession(): User + { + $user = User::factory()->create(); + $user->assignRole(TestCase::DEFAULT_USERS); + capture_session($user); - /** - * @throws HorusException - * - * @return User - */ - public static function createAdminUser(): User - { - $user = User::factory()->create(); - $user->assignRole(TestCase::DEFAULT_ADMINS); + return $user->fresh(); + } - return $user->fresh(); - } + /** + * @throws HorusException + * + * @return User + */ + public static function createAdminUser(): User + { + $user = User::factory()->create(); + $user->assignRole(TestCase::DEFAULT_ADMINS); - /** - * @param User|null $user - * - * @throws HorusException - * @throws SphinxException - * - * @return SphinxService - */ - public static function generateToken(User $user = null): SphinxService - { - if (is_null($user)) { - $user = self::createNormalUserWithSession(); - } + return $user->fresh(); + } - return Sphinx::generateTokenFor($user); + /** + * @param User|null $user + * + * @throws HorusException + * @throws SphinxException + * + * @return SphinxService + */ + public static function generateToken(User $user = null): SphinxService + { + if (is_null($user)) { + $user = self::createNormalUserWithSession(); } + + return Sphinx::generateTokenFor($user); } +} diff --git a/tests/Feature/Drivers/ConstraintsTest.php b/tests/Feature/Drivers/ConstraintsTest.php index ecc67a9..265e3ba 100644 --- a/tests/Feature/Drivers/ConstraintsTest.php +++ b/tests/Feature/Drivers/ConstraintsTest.php @@ -2,137 +2,137 @@ namespace Hans\Sphinx\Tests\Feature\Drivers; - use Hans\Sphinx\Drivers\Constraints\ExpirationValidator; - use Hans\Sphinx\Drivers\Constraints\RoleIdValidator; - use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; - use Hans\Sphinx\Drivers\Constraints\SessionIdValidator; - use Hans\Sphinx\Drivers\Contracts\JwtToken; - use Hans\Sphinx\Exceptions\SphinxException; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\Instances\JwtTokenWithCustomizableConstraintsInstance; - use Hans\Sphinx\Tests\TestCase; - use Illuminate\Database\Eloquent\Model; - use Lcobucci\JWT\Signer\Hmac\Sha512; - use Lcobucci\JWT\Signer\Key\InMemory; - - class ConstraintsTest extends TestCase +use Hans\Sphinx\Drivers\Constraints\ExpirationValidator; +use Hans\Sphinx\Drivers\Constraints\RoleIdValidator; +use Hans\Sphinx\Drivers\Constraints\SecretVerificationValidator; +use Hans\Sphinx\Drivers\Constraints\SessionIdValidator; +use Hans\Sphinx\Drivers\Contracts\JwtToken; +use Hans\Sphinx\Exceptions\SphinxException; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\Instances\JwtTokenWithCustomizableConstraintsInstance; +use Hans\Sphinx\Tests\TestCase; +use Illuminate\Database\Eloquent\Model; +use Lcobucci\JWT\Signer\Hmac\Sha512; +use Lcobucci\JWT\Signer\Key\InMemory; + +class ConstraintsTest extends TestCase +{ + private JwtToken $instance; + private Model $user; + private string $secret; + + protected function setUp(): void { - private JwtToken $instance; - private Model $user; - private string $secret; - - protected function setUp(): void - { - parent::setUp(); - $this->instance = new JwtTokenWithCustomizableConstraintsInstance($this->secret = generate_secret_key()); - $this->user = UserFactory::createNormalUser(); - } - - /** - * @test - * - * @throws SphinxException - * - * @return void - */ - public function ExpirationValidator(): void - { - $this->instance->registerConstrain(new ExpirationValidator()); - - $token = $this->instance->expiresAt()->getToken()->toString(); - - $this->instance->assert($token); - - $token = $this->instance->expiresAt('-1 second')->getToken()->toString(); - - $this->expectException(SphinxException::class); - $this->expectExceptionMessage('Token expired!'); - - $this->instance->assert($token); - } - - /** - * @test - * - * @throws SphinxException - * - * @return void - */ - public function RoleIdValidator(): void - { - $this->instance->registerConstrain(new RoleIdValidator()); - - $headers = [ - 'role_id' => $this->user->getRole()->id, - 'role_version' => $this->user->getRole()->getVersion(), - ]; - $token = $this->instance->headers($headers)->getToken()->toString(); - - $this->instance->assert($token); - - $this->user->getRole()->increaseVersion(); - - $this->expectException(SphinxException::class); - $this->expectExceptionMessage("User's token is out-of-date!"); - - $this->instance->assert($token); - } - - /** - * @test - * - * @throws SphinxException - * - * @return void - */ - public function SecretVerificationValidator(): void - { - $this->instance->registerConstrain( - new SecretVerificationValidator(new Sha512(), InMemory::plainText($this->secret)) - ); - - $token = $this->instance->encode()->getToken()->toString(); - - $this->instance->assert($token); - - do { - $randomAlpha = fake()->word()[0]; - } while ($randomAlpha == $token[strlen($token) - 1]); - - $token[strlen($token) - 10] = $randomAlpha; - - $this->expectException(SphinxException::class); - $this->expectExceptionMessage('Token signature mismatch!'); - - $this->instance->assert($token); - } - - /** - * @test - * - * @throws SphinxException - * - * @return void - */ - public function SessionIdValidator(): void - { - $this->instance->registerConstrain(new SessionIdValidator()); - - $session = capture_session($this->user); - $headers = [ - 'session_id' => $session->id, - 'sessionable_version' => $session->sessionable->version, - ]; - - $token = $this->instance->headers($headers)->encode()->getToken()->toString(); - - $this->instance->assert($token); - - $session->sessionable->increaseVersion(); - - $this->expectException(SphinxException::class); - $this->expectExceptionMessage('Token is out-of-date!'); + parent::setUp(); + $this->instance = new JwtTokenWithCustomizableConstraintsInstance($this->secret = generate_secret_key()); + $this->user = UserFactory::createNormalUser(); + } + + /** + * @test + * + * @throws SphinxException + * + * @return void + */ + public function ExpirationValidator(): void + { + $this->instance->registerConstrain(new ExpirationValidator()); + + $token = $this->instance->expiresAt()->getToken()->toString(); + + $this->instance->assert($token); + + $token = $this->instance->expiresAt('-1 second')->getToken()->toString(); + + $this->expectException(SphinxException::class); + $this->expectExceptionMessage('Token expired!'); + + $this->instance->assert($token); + } + + /** + * @test + * + * @throws SphinxException + * + * @return void + */ + public function RoleIdValidator(): void + { + $this->instance->registerConstrain(new RoleIdValidator()); + + $headers = [ + 'role_id' => $this->user->getRole()->id, + 'role_version' => $this->user->getRole()->getVersion(), + ]; + $token = $this->instance->headers($headers)->getToken()->toString(); + + $this->instance->assert($token); + + $this->user->getRole()->increaseVersion(); + + $this->expectException(SphinxException::class); + $this->expectExceptionMessage("User's token is out-of-date!"); + + $this->instance->assert($token); + } + + /** + * @test + * + * @throws SphinxException + * + * @return void + */ + public function SecretVerificationValidator(): void + { + $this->instance->registerConstrain( + new SecretVerificationValidator(new Sha512(), InMemory::plainText($this->secret)) + ); + + $token = $this->instance->encode()->getToken()->toString(); + + $this->instance->assert($token); + + do { + $randomAlpha = fake()->word()[0]; + } while ($randomAlpha == $token[strlen($token) - 1]); + + $token[strlen($token) - 10] = $randomAlpha; + + $this->expectException(SphinxException::class); + $this->expectExceptionMessage('Token signature mismatch!'); + + $this->instance->assert($token); + } + + /** + * @test + * + * @throws SphinxException + * + * @return void + */ + public function SessionIdValidator(): void + { + $this->instance->registerConstrain(new SessionIdValidator()); + + $session = capture_session($this->user); + $headers = [ + 'session_id' => $session->id, + 'sessionable_version' => $session->sessionable->version, + ]; + + $token = $this->instance->headers($headers)->encode()->getToken()->toString(); + + $this->instance->assert($token); + + $session->sessionable->increaseVersion(); + + $this->expectException(SphinxException::class); + $this->expectExceptionMessage('Token is out-of-date!'); - $this->instance->assert($token); - } + $this->instance->assert($token); } +} diff --git a/tests/Feature/Drivers/JwtTokenTest.php b/tests/Feature/Drivers/JwtTokenTest.php index bd7ed74..109e5f6 100644 --- a/tests/Feature/Drivers/JwtTokenTest.php +++ b/tests/Feature/Drivers/JwtTokenTest.php @@ -2,453 +2,453 @@ namespace Hans\Sphinx\Tests\Feature\Drivers; - use DateTimeImmutable; - use Hans\Sphinx\Drivers\Contracts\JwtToken; - use Hans\Sphinx\Exceptions\SphinxException; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\Instances\JwtTokenInstance; - use Hans\Sphinx\Tests\TestCase; - use Illuminate\Database\Eloquent\Model; - use Lcobucci\JWT\Token\Plain; - - class JwtTokenTest extends TestCase +use DateTimeImmutable; +use Hans\Sphinx\Drivers\Contracts\JwtToken; +use Hans\Sphinx\Exceptions\SphinxException; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\Instances\JwtTokenInstance; +use Hans\Sphinx\Tests\TestCase; +use Illuminate\Database\Eloquent\Model; +use Lcobucci\JWT\Token\Plain; + +class JwtTokenTest extends TestCase +{ + private JwtToken $instance; + private Model $user; + + protected function setUp(): void { - private JwtToken $instance; - private Model $user; - - protected function setUp(): void - { - parent::setUp(); - $this->instance = new JwtTokenInstance(generate_secret_key()); - $this->user = UserFactory::createNormalUser(); - } - - /** - * @test - * - * @return void - */ - public function issuedBy(): void - { - self::assertArrayNotHasKey('iss', $this->instance->getToken()->claims()->all()); - - $this->instance->issuedBy($this->user->name); - - self::assertArrayHasKey('iss', $this->instance->getToken()->claims()->all()); - self::assertStringEqualsStringIgnoringLineEndings( - $this->user->name, - $this->instance->getToken()->claims()->get('iss') - ); - } - - /** - * @test - * - * @return void - */ - public function permittedFor(): void - { - self::assertArrayNotHasKey('aud', $this->instance->getToken()->claims()->all()); - - $this->instance->permittedFor($website = fake()->domainName()); - - self::assertArrayHasKey('aud', $this->instance->getToken()->claims()->all()); - self::assertContains( - $website, - $this->instance->getToken()->claims()->get('aud') - ); - } - - /** - * @test - * - * @return void - */ - public function identifiedBy(): void - { - self::assertArrayNotHasKey('jti', $this->instance->getToken()->claims()->all()); - - $this->instance->identifiedBy($identifier = generate_secret_key()); - - self::assertArrayHasKey('jti', $this->instance->getToken()->claims()->all()); - self::assertStringEqualsStringIgnoringLineEndings( - $identifier, - $this->instance->getToken()->claims()->get('jti') - ); - } - - /** - * @test - * - * @return void - */ - public function canOnlyBeUsedAfter(): void - { - self::assertArrayNotHasKey('nbf', $this->instance->getToken()->claims()->all()); - - $this->instance->canOnlyBeUsedAfter('+5 minute'); - - self::assertArrayHasKey('nbf', $this->instance->getToken()->claims()->all()); - self::assertInstanceOf( - DateTimeImmutable::class, - $this->instance->getToken()->claims()->get('nbf') - ); - - $nbf = $this->instance->getToken()->claims()->get('nbf'); - $now = new DateTimeImmutable(); - - self::assertEquals(4, $now->diff($nbf)->i); - self::assertEquals(59, $now->diff($nbf)->s); - } - - /** - * @test - * - * @return void - */ - public function expiresAt(): void - { - self::assertArrayNotHasKey('exp', $this->instance->getToken()->claims()->all()); - - $this->instance->expiresAt('+5 minute'); - - self::assertArrayHasKey('exp', $this->instance->getToken()->claims()->all()); - self::assertInstanceOf( - DateTimeImmutable::class, - $this->instance->getToken()->claims()->get('exp') - ); - - $nbf = $this->instance->getToken()->claims()->get('exp'); - $now = new DateTimeImmutable(); - - self::assertEquals(4, $now->diff($nbf)->i); - self::assertEquals(59, $now->diff($nbf)->s); - } - - /** - * @test - * - * @throws SphinxException - * - * @return void - */ - public function claims(): void - { - $claims = [ - 'G.O.A.T.' => 'G-Eazy', - 'Tulips&Roses' => 'Nothing ever last for ever.', - ]; - - self::assertArrayNotHasKey( - array_keys($claims)[0], - $this->instance->getToken()->claims()->all() - ); - self::assertArrayNotHasKey( - array_keys($claims)[1], - $this->instance->getToken()->claims()->all() - ); - - $this->instance->claims($claims); - - self::assertArrayHasKey( - array_keys($claims)[0], - $this->instance->getToken()->claims()->all() - ); - self::assertArrayHasKey( - array_keys($claims)[1], - $this->instance->getToken()->claims()->all() - ); - - self::assertStringEqualsStringIgnoringLineEndings( - $claims[array_keys($claims)[0]], - $this->instance->getToken()->claims()->get(array_keys($claims)[0]) - ); - self::assertStringEqualsStringIgnoringLineEndings( - $claims[array_keys($claims)[1]], - $this->instance->getToken()->claims()->get(array_keys($claims)[1]) - ); - } - - /** - * @test - * - * @return void - */ - public function claim(): void - { - $key = 'DontLetMeGo'; - $value = 'Even the brightest color turns gray.'; - self::assertArrayNotHasKey( - $key, - $this->instance->getToken()->claims()->all() - ); - - $this->instance->claim($key, $value); - - self::assertArrayHasKey( - $key, - $this->instance->getToken()->claims()->all() - ); - - self::assertStringEqualsStringIgnoringLineEndings( - $value, - $this->instance->getToken()->claims()->get($key) - ); - } - - /** - * @test - * - * @return void - */ - public function claimWhen(): void - { - $key = 'LifeStyleOfReachAndHated'; - $value = fn () => 'No one believed in me at first. You just laughed and said i hope it works.'; - self::assertArrayNotHasKey( - $key, - $this->instance->getToken()->claims()->all() - ); - - $this->instance->claimWhen(true, $key, $value); - - self::assertArrayHasKey( - $key, - $this->instance->getToken()->claims()->all() - ); - - self::assertStringEqualsStringIgnoringLineEndings( - $value(), - $this->instance->getToken()->claims()->get($key) - ); - } - - /** - * @test - * - * @throws SphinxException - * - * @return void - */ - public function headers(): void - { - $headers = [ - 'G-Eazy' => 'I bring up facts, You bring us boll shit, you should relax.', - 'G.O.A.T.' => 'Life can be worse, What can i do but enjoy the perks?', - ]; - - self::assertArrayNotHasKey( - array_keys($headers)[0], - $this->instance->getToken()->headers()->all() - ); - self::assertArrayNotHasKey( - array_keys($headers)[1], - $this->instance->getToken()->headers()->all() - ); - - $this->instance->headers($headers); - - self::assertArrayHasKey( - array_keys($headers)[0], - $this->instance->getToken()->headers()->all() - ); - self::assertArrayHasKey( - array_keys($headers)[1], - $this->instance->getToken()->headers()->all() - ); - - self::assertStringEqualsStringIgnoringLineEndings( - $headers[array_keys($headers)[0]], - $this->instance->getToken()->headers()->get(array_keys($headers)[0]) - ); - self::assertStringEqualsStringIgnoringLineEndings( - $headers[array_keys($headers)[1]], - $this->instance->getToken()->headers()->get(array_keys($headers)[1]) - ); - } - - /** - * @test - * - * @return void - */ - public function header(): void - { - $key = 'HadEnough'; - $value = 'Watch out, remember CARMA\'s real. That bull shit comes back to bite you.'; - self::assertArrayNotHasKey( - $key, - $this->instance->getToken()->headers()->all() - ); - - $this->instance->header($key, $value); - - self::assertArrayHasKey( - $key, - $this->instance->getToken()->headers()->all() - ); - - self::assertStringEqualsStringIgnoringLineEndings( - $value, - $this->instance->getToken()->headers()->get($key) - ); - } - - /** - * @test - * - * @return void - */ - public function headerWhen(): void - { - $key = 'Spectacular now'; - $value = fn () => 'See all the things i don\'t like in me, i can\'t bear my self.'; - self::assertArrayNotHasKey( - $key, - $this->instance->getToken()->headers()->all() - ); - - $this->instance->headerWhen(true, $key, $value); - - self::assertArrayHasKey( - $key, - $this->instance->getToken()->headers()->all() - ); - - self::assertStringEqualsStringIgnoringLineEndings( - $value(), - $this->instance->getToken()->headers()->get($key) - ); - } - - /** - * @test - * - * @return void - */ - public function encode(): void - { - self::assertArrayNotHasKey( - 'iat', - $this->instance->getToken()->claims()->all() - ); - - $this->instance->encode(); - - self::assertArrayHasKey( - 'iat', - $this->instance->getToken()->claims()->all() - ); - self::assertInstanceOf( - DateTimeImmutable::class, - $this->instance->getToken()->claims()->get('iat') - ); - self::assertEquals( - 0, - ( new DateTimeImmutable() )->diff($this->instance->getToken()->claims()->get('iat'))->s - ); - } - - /** - * @test - * - * @throws SphinxException - * - * @return void - */ - public function decode(): void - { - $encoded = $this->instance - ->claim($claimKey = 'Ruthless', $claimValue = 'Gave you my heart and you fuck around and broke that.') - ->header($headerKey = 'Him&I', $headerValue = 'Cross my heart, I hope to die.') - ->encode() - ->getToken() - ->toString(); - - $decoded = $this->instance->decode($encoded); - - self::assertArrayHasKey( - $claimKey, - $decoded->claims()->all() - ); - self::assertStringEqualsStringIgnoringLineEndings( - $claimValue, - $decoded->claims()->get($claimKey) - ); - - self::assertArrayHasKey( - $headerKey, - $decoded->headers()->all() - ); - self::assertStringEqualsStringIgnoringLineEndings( - $headerValue, - $decoded->headers()->get($headerKey) - ); - } - - /** - * @test - * - * @throws SphinxException - * - * @return void - */ - public function assert(): void - { - $token = $this->instance - ->expiresAt() - ->encode() - ->getToken() - ->toString(); - - $this->instance->assert($token); - - $token = $this->instance - ->expiresAt('-1 second') - ->encode() - ->getToken() - ->toString(); - - $this->expectException(SphinxException::class); - $this->expectExceptionMessage('Token expired!'); - - $this->instance->assert($token); - } - - /** - * @test - * - * @return void - */ - public function validate(): void - { - $token = $this->instance - ->expiresAt() - ->encode() - ->getToken() - ->toString(); - - self::assertTrue($this->instance->validate($token)); - - $token = $this->instance - ->expiresAt('-1 second') - ->encode() - ->getToken() - ->toString(); - - self::assertFalse($this->instance->validate($token)); - } - - /** - * @test - * - * @return void - */ - public function getToken(): void - { - self::assertInstanceOf( - Plain::class, - $this->instance->encode()->getToken() - ); - } + parent::setUp(); + $this->instance = new JwtTokenInstance(generate_secret_key()); + $this->user = UserFactory::createNormalUser(); } + + /** + * @test + * + * @return void + */ + public function issuedBy(): void + { + self::assertArrayNotHasKey('iss', $this->instance->getToken()->claims()->all()); + + $this->instance->issuedBy($this->user->name); + + self::assertArrayHasKey('iss', $this->instance->getToken()->claims()->all()); + self::assertStringEqualsStringIgnoringLineEndings( + $this->user->name, + $this->instance->getToken()->claims()->get('iss') + ); + } + + /** + * @test + * + * @return void + */ + public function permittedFor(): void + { + self::assertArrayNotHasKey('aud', $this->instance->getToken()->claims()->all()); + + $this->instance->permittedFor($website = fake()->domainName()); + + self::assertArrayHasKey('aud', $this->instance->getToken()->claims()->all()); + self::assertContains( + $website, + $this->instance->getToken()->claims()->get('aud') + ); + } + + /** + * @test + * + * @return void + */ + public function identifiedBy(): void + { + self::assertArrayNotHasKey('jti', $this->instance->getToken()->claims()->all()); + + $this->instance->identifiedBy($identifier = generate_secret_key()); + + self::assertArrayHasKey('jti', $this->instance->getToken()->claims()->all()); + self::assertStringEqualsStringIgnoringLineEndings( + $identifier, + $this->instance->getToken()->claims()->get('jti') + ); + } + + /** + * @test + * + * @return void + */ + public function canOnlyBeUsedAfter(): void + { + self::assertArrayNotHasKey('nbf', $this->instance->getToken()->claims()->all()); + + $this->instance->canOnlyBeUsedAfter('+5 minute'); + + self::assertArrayHasKey('nbf', $this->instance->getToken()->claims()->all()); + self::assertInstanceOf( + DateTimeImmutable::class, + $this->instance->getToken()->claims()->get('nbf') + ); + + $nbf = $this->instance->getToken()->claims()->get('nbf'); + $now = new DateTimeImmutable(); + + self::assertEquals(4, $now->diff($nbf)->i); + self::assertEquals(59, $now->diff($nbf)->s); + } + + /** + * @test + * + * @return void + */ + public function expiresAt(): void + { + self::assertArrayNotHasKey('exp', $this->instance->getToken()->claims()->all()); + + $this->instance->expiresAt('+5 minute'); + + self::assertArrayHasKey('exp', $this->instance->getToken()->claims()->all()); + self::assertInstanceOf( + DateTimeImmutable::class, + $this->instance->getToken()->claims()->get('exp') + ); + + $nbf = $this->instance->getToken()->claims()->get('exp'); + $now = new DateTimeImmutable(); + + self::assertEquals(4, $now->diff($nbf)->i); + self::assertEquals(59, $now->diff($nbf)->s); + } + + /** + * @test + * + * @throws SphinxException + * + * @return void + */ + public function claims(): void + { + $claims = [ + 'G.O.A.T.' => 'G-Eazy', + 'Tulips&Roses' => 'Nothing ever last for ever.', + ]; + + self::assertArrayNotHasKey( + array_keys($claims)[0], + $this->instance->getToken()->claims()->all() + ); + self::assertArrayNotHasKey( + array_keys($claims)[1], + $this->instance->getToken()->claims()->all() + ); + + $this->instance->claims($claims); + + self::assertArrayHasKey( + array_keys($claims)[0], + $this->instance->getToken()->claims()->all() + ); + self::assertArrayHasKey( + array_keys($claims)[1], + $this->instance->getToken()->claims()->all() + ); + + self::assertStringEqualsStringIgnoringLineEndings( + $claims[array_keys($claims)[0]], + $this->instance->getToken()->claims()->get(array_keys($claims)[0]) + ); + self::assertStringEqualsStringIgnoringLineEndings( + $claims[array_keys($claims)[1]], + $this->instance->getToken()->claims()->get(array_keys($claims)[1]) + ); + } + + /** + * @test + * + * @return void + */ + public function claim(): void + { + $key = 'DontLetMeGo'; + $value = 'Even the brightest color turns gray.'; + self::assertArrayNotHasKey( + $key, + $this->instance->getToken()->claims()->all() + ); + + $this->instance->claim($key, $value); + + self::assertArrayHasKey( + $key, + $this->instance->getToken()->claims()->all() + ); + + self::assertStringEqualsStringIgnoringLineEndings( + $value, + $this->instance->getToken()->claims()->get($key) + ); + } + + /** + * @test + * + * @return void + */ + public function claimWhen(): void + { + $key = 'LifeStyleOfReachAndHated'; + $value = fn () => 'No one believed in me at first. You just laughed and said i hope it works.'; + self::assertArrayNotHasKey( + $key, + $this->instance->getToken()->claims()->all() + ); + + $this->instance->claimWhen(true, $key, $value); + + self::assertArrayHasKey( + $key, + $this->instance->getToken()->claims()->all() + ); + + self::assertStringEqualsStringIgnoringLineEndings( + $value(), + $this->instance->getToken()->claims()->get($key) + ); + } + + /** + * @test + * + * @throws SphinxException + * + * @return void + */ + public function headers(): void + { + $headers = [ + 'G-Eazy' => 'I bring up facts, You bring us boll shit, you should relax.', + 'G.O.A.T.' => 'Life can be worse, What can i do but enjoy the perks?', + ]; + + self::assertArrayNotHasKey( + array_keys($headers)[0], + $this->instance->getToken()->headers()->all() + ); + self::assertArrayNotHasKey( + array_keys($headers)[1], + $this->instance->getToken()->headers()->all() + ); + + $this->instance->headers($headers); + + self::assertArrayHasKey( + array_keys($headers)[0], + $this->instance->getToken()->headers()->all() + ); + self::assertArrayHasKey( + array_keys($headers)[1], + $this->instance->getToken()->headers()->all() + ); + + self::assertStringEqualsStringIgnoringLineEndings( + $headers[array_keys($headers)[0]], + $this->instance->getToken()->headers()->get(array_keys($headers)[0]) + ); + self::assertStringEqualsStringIgnoringLineEndings( + $headers[array_keys($headers)[1]], + $this->instance->getToken()->headers()->get(array_keys($headers)[1]) + ); + } + + /** + * @test + * + * @return void + */ + public function header(): void + { + $key = 'HadEnough'; + $value = 'Watch out, remember CARMA\'s real. That bull shit comes back to bite you.'; + self::assertArrayNotHasKey( + $key, + $this->instance->getToken()->headers()->all() + ); + + $this->instance->header($key, $value); + + self::assertArrayHasKey( + $key, + $this->instance->getToken()->headers()->all() + ); + + self::assertStringEqualsStringIgnoringLineEndings( + $value, + $this->instance->getToken()->headers()->get($key) + ); + } + + /** + * @test + * + * @return void + */ + public function headerWhen(): void + { + $key = 'Spectacular now'; + $value = fn () => 'See all the things i don\'t like in me, i can\'t bear my self.'; + self::assertArrayNotHasKey( + $key, + $this->instance->getToken()->headers()->all() + ); + + $this->instance->headerWhen(true, $key, $value); + + self::assertArrayHasKey( + $key, + $this->instance->getToken()->headers()->all() + ); + + self::assertStringEqualsStringIgnoringLineEndings( + $value(), + $this->instance->getToken()->headers()->get($key) + ); + } + + /** + * @test + * + * @return void + */ + public function encode(): void + { + self::assertArrayNotHasKey( + 'iat', + $this->instance->getToken()->claims()->all() + ); + + $this->instance->encode(); + + self::assertArrayHasKey( + 'iat', + $this->instance->getToken()->claims()->all() + ); + self::assertInstanceOf( + DateTimeImmutable::class, + $this->instance->getToken()->claims()->get('iat') + ); + self::assertEquals( + 0, + ( new DateTimeImmutable() )->diff($this->instance->getToken()->claims()->get('iat'))->s + ); + } + + /** + * @test + * + * @throws SphinxException + * + * @return void + */ + public function decode(): void + { + $encoded = $this->instance + ->claim($claimKey = 'Ruthless', $claimValue = 'Gave you my heart and you fuck around and broke that.') + ->header($headerKey = 'Him&I', $headerValue = 'Cross my heart, I hope to die.') + ->encode() + ->getToken() + ->toString(); + + $decoded = $this->instance->decode($encoded); + + self::assertArrayHasKey( + $claimKey, + $decoded->claims()->all() + ); + self::assertStringEqualsStringIgnoringLineEndings( + $claimValue, + $decoded->claims()->get($claimKey) + ); + + self::assertArrayHasKey( + $headerKey, + $decoded->headers()->all() + ); + self::assertStringEqualsStringIgnoringLineEndings( + $headerValue, + $decoded->headers()->get($headerKey) + ); + } + + /** + * @test + * + * @throws SphinxException + * + * @return void + */ + public function assert(): void + { + $token = $this->instance + ->expiresAt() + ->encode() + ->getToken() + ->toString(); + + $this->instance->assert($token); + + $token = $this->instance + ->expiresAt('-1 second') + ->encode() + ->getToken() + ->toString(); + + $this->expectException(SphinxException::class); + $this->expectExceptionMessage('Token expired!'); + + $this->instance->assert($token); + } + + /** + * @test + * + * @return void + */ + public function validate(): void + { + $token = $this->instance + ->expiresAt() + ->encode() + ->getToken() + ->toString(); + + self::assertTrue($this->instance->validate($token)); + + $token = $this->instance + ->expiresAt('-1 second') + ->encode() + ->getToken() + ->toString(); + + self::assertFalse($this->instance->validate($token)); + } + + /** + * @test + * + * @return void + */ + public function getToken(): void + { + self::assertInstanceOf( + Plain::class, + $this->instance->encode()->getToken() + ); + } +} diff --git a/tests/Feature/Helpers/FunctionsTest.php b/tests/Feature/Helpers/FunctionsTest.php index 68d0f94..c5b35ee 100644 --- a/tests/Feature/Helpers/FunctionsTest.php +++ b/tests/Feature/Helpers/FunctionsTest.php @@ -2,127 +2,127 @@ namespace Hans\Sphinx\Tests\Feature\Helpers; - use Hans\Horus\Exceptions\HorusException; - use Hans\Sphinx\Exceptions\SphinxException; - use Hans\Sphinx\Helpers\Enums\SphinxCache; - use Hans\Sphinx\Models\Session; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\TestCase; - use Illuminate\Support\Facades\Cache; +use Hans\Horus\Exceptions\HorusException; +use Hans\Sphinx\Exceptions\SphinxException; +use Hans\Sphinx\Helpers\Enums\SphinxCache; +use Hans\Sphinx\Models\Session; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\TestCase; +use Illuminate\Support\Facades\Cache; - class FunctionsTest extends TestCase +class FunctionsTest extends TestCase +{ + /** + * @test + * + * @throws HorusException|SphinxException + * + * @return void + */ + public function capture_session(): void { - /** - * @test - * - * @throws HorusException|SphinxException - * - * @return void - */ - public function capture_session(): void - { - $user = UserFactory::createNormalUser(); - $session = capture_session($user); + $user = UserFactory::createNormalUser(); + $session = capture_session($user); - self::assertInstanceOf( - Session::class, - $session - ); - self::assertEquals( - $user->withoutRelations()->toArray(), - $session->sessionable->toArray() - ); - } + self::assertInstanceOf( + Session::class, + $session + ); + self::assertEquals( + $user->withoutRelations()->toArray(), + $session->sessionable->toArray() + ); + } - /** - * @test - * - * @throws HorusException|SphinxException - * - * @return void - */ - public function capture_sessionWithSeveralCalls(): void - { - $user = UserFactory::createNormalUser(); - $deviceLimit = $user->getDeviceLimit(); + /** + * @test + * + * @throws HorusException|SphinxException + * + * @return void + */ + public function capture_sessionWithSeveralCalls(): void + { + $user = UserFactory::createNormalUser(); + $deviceLimit = $user->getDeviceLimit(); - // hit device limit - foreach (range(1, $deviceLimit) as $counter) { - $sessions[] = capture_session($user); - } - // capture new session + // hit device limit + foreach (range(1, $deviceLimit) as $counter) { $sessions[] = capture_session($user); - // old session should be deleted from DB and Cache - self::assertCount( - 2, - $user->sessions - ); - $this->assertModelMissing($sessions[0]); - self::assertFalse(Cache::has(SphinxCache::SESSION.$sessions[0]->id)); - self::assertEquals( - $sessions[1]->withoutRelations()->toArray(), - $user->sessions[0]->toArray() - ); - self::assertEquals( - $sessions[2]->withoutRelations()->toArray(), - $user->sessions[1]->toArray() - ); } + // capture new session + $sessions[] = capture_session($user); + // old session should be deleted from DB and Cache + self::assertCount( + 2, + $user->sessions + ); + $this->assertModelMissing($sessions[0]); + self::assertFalse(Cache::has(SphinxCache::SESSION.$sessions[0]->id)); + self::assertEquals( + $sessions[1]->withoutRelations()->toArray(), + $user->sessions[0]->toArray() + ); + self::assertEquals( + $sessions[2]->withoutRelations()->toArray(), + $user->sessions[1]->toArray() + ); + } - /** - * @test - * - * @throws HorusException - * @throws SphinxException - * - * @return void - */ - public function capture_sessionAsSecondSession(): void - { - $user = UserFactory::createNormalUser(); - $sessions[] = capture_session($user); // version should be 1 - $user->update(['name' => fake()->name()]); // version has increased - $sessions[] = capture_session($user); // version should be 2 + /** + * @test + * + * @throws HorusException + * @throws SphinxException + * + * @return void + */ + public function capture_sessionAsSecondSession(): void + { + $user = UserFactory::createNormalUser(); + $sessions[] = capture_session($user); // version should be 1 + $user->update(['name' => fake()->name()]); // version has increased + $sessions[] = capture_session($user); // version should be 2 - self::assertEquals( - 1, - $sessions[0]->sessionable_version - ); - self::assertEquals( - 2, - $sessions[1]->sessionable_version - ); - } + self::assertEquals( + 1, + $sessions[0]->sessionable_version + ); + self::assertEquals( + 2, + $sessions[1]->sessionable_version + ); + } - /** - * @test - * - * @return void - */ - public function sphinx_config(): void - { - $config = require __DIR__.'/../../../config/config.php'; - $key = 'access_expired_at'; - $default = 'Not found!'; + /** + * @test + * + * @return void + */ + public function sphinx_config(): void + { + $config = require __DIR__.'/../../../config/config.php'; + $key = 'access_expired_at'; + $default = 'Not found!'; - self::assertStringEqualsStringIgnoringLineEndings( - $config[$key], - sphinx_config($key) - ); + self::assertStringEqualsStringIgnoringLineEndings( + $config[$key], + sphinx_config($key) + ); - self::assertEquals( - $default, - sphinx_config('wrong', $default) - ); - } + self::assertEquals( + $default, + sphinx_config('wrong', $default) + ); + } - /** - * @test - * - * @return void - */ - public function generate_secret_key(): void - { - self::assertIsString(generate_secret_key()); - } + /** + * @test + * + * @return void + */ + public function generate_secret_key(): void + { + self::assertIsString(generate_secret_key()); } +} diff --git a/tests/Feature/PerformanceTest.php b/tests/Feature/PerformanceTest.php index 895b79c..ce2c8e8 100644 --- a/tests/Feature/PerformanceTest.php +++ b/tests/Feature/PerformanceTest.php @@ -2,42 +2,42 @@ namespace Hans\Sphinx\Tests\Feature; - use App\Models\User; - use Hans\Sphinx\Facades\Sphinx; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\TestCase; - use Illuminate\Support\Facades\DB; +use App\Models\User; +use Hans\Sphinx\Facades\Sphinx; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\TestCase; +use Illuminate\Support\Facades\DB; - class PerformanceTest extends TestCase - { - private User $user; +class PerformanceTest extends TestCase +{ + private User $user; - protected function setUp(): void - { - parent::setUp(); - $this->user = UserFactory::createNormalUser(); - } + protected function setUp(): void + { + parent::setUp(); + $this->user = UserFactory::createNormalUser(); + } - /** - * @test - * - * @return void - */ - public function noQueryDuringAuthenticatingUsingToken(): void - { - $token = Sphinx::generateTokenFor($this->user)->getAccessToken(); + /** + * @test + * + * @return void + */ + public function noQueryDuringAuthenticatingUsingToken(): void + { + $token = Sphinx::generateTokenFor($this->user)->getAccessToken(); - DB::enableQueryLog(); - $this->getJson( - uri: route('test.me'), - headers: [ - 'Authorization' => "Bearer $token", - ] - ); + DB::enableQueryLog(); + $this->getJson( + uri: route('test.me'), + headers: [ + 'Authorization' => "Bearer $token", + ] + ); - self::assertCount( - 0, - DB::getQueryLog() - ); - } + self::assertCount( + 0, + DB::getQueryLog() + ); } +} diff --git a/tests/Feature/Services/SphinxGuardTest.php b/tests/Feature/Services/SphinxGuardTest.php index d472c05..55db6e2 100644 --- a/tests/Feature/Services/SphinxGuardTest.php +++ b/tests/Feature/Services/SphinxGuardTest.php @@ -2,218 +2,218 @@ namespace Hans\Sphinx\Tests\Feature\Services; - use Hans\Horus\Exceptions\HorusException; - use Hans\Sphinx\Facades\Sphinx; - use Hans\Sphinx\Services\SphinxGuard; - use Hans\Sphinx\Services\SphinxUserProvider; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\TestCase; - use Illuminate\Database\Eloquent\Model; - - class SphinxGuardTest extends TestCase +use Hans\Horus\Exceptions\HorusException; +use Hans\Sphinx\Facades\Sphinx; +use Hans\Sphinx\Services\SphinxGuard; +use Hans\Sphinx\Services\SphinxUserProvider; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\TestCase; +use Illuminate\Database\Eloquent\Model; + +class SphinxGuardTest extends TestCase +{ + private SphinxGuard $guard; + private Model $user; + + protected function setUp(): void { - private SphinxGuard $guard; - private Model $user; - - protected function setUp(): void - { - parent::setUp(); - $this->user = UserFactory::createNormalUser(); - request()->headers - ->set( - 'Authorization', - 'Bearer '.Sphinx::generateTokenFor($this->user)->getAccessToken() - ); - $this->guard = app(SphinxGuard::class, [ - 'provider' => app( - SphinxUserProvider::class, - ['model' => $this->app['config']['auth.providers.sphinxUsers.model']] - ), - ]); - } - - /** - * @test - * - * @return void - */ - public function getAuthIdentifierName(): void - { - self::assertEquals( - $this->user->getKeyName(), - $this->guard->getAuthIdentifierName() - ); - } - - /** - * @test - * - * @return void - */ - public function getAuthIdentifier(): void - { - self::assertEquals( - $this->user->id, - $this->guard->getAuthIdentifier() - ); - } - - /** - * @test - * - * @return void - */ - public function getAuthPassword(): void - { - self::assertEquals( - $this->user->password, - $this->guard->getAuthPassword() - ); - } - - /** - * @test - * - * @return void - */ - public function getRememberToken(): void - { - self::assertNull($this->guard->getRememberToken()); - } - - /** - * @test - * - * @return void - */ - public function setRememberToken(): void - { - self::assertNull($this->guard->setRememberToken()); - } - - /** - * @test - * - * @return void - */ - public function getRememberTokenName(): void - { - self::assertNull($this->guard->getRememberTokenName()); - } - - /** - * @test - * - * @return void - */ - public function user(): void - { - self::assertEquals( - $this->user->only('id', 'name', 'email', 'version'), - $this->guard->user()->toArray() - ); - } - - /** - * @test - * - * @return void - */ - public function attempt(): void - { - self::assertTrue( - $this->guard->attempt(['id' => $this->user->id, 'password' => 'password']) - ); - self::assertEquals( - $this->user->withoutRelations()->toArray(), - $this->guard->user()->toArray() - ); + parent::setUp(); + $this->user = UserFactory::createNormalUser(); + request()->headers + ->set( + 'Authorization', + 'Bearer '.Sphinx::generateTokenFor($this->user)->getAccessToken() + ); + $this->guard = app(SphinxGuard::class, [ + 'provider' => app( + SphinxUserProvider::class, + ['model' => $this->app['config']['auth.providers.sphinxUsers.model']] + ), + ]); + } - self::assertFalse( - $this->guard->attempt(['id' => $this->user->id + 512, 'password' => 'password']) - ); - self::assertFalse( - $this->guard->attempt(['id' => $this->user->id, 'password' => 'wrong']) - ); - } - - /** - * @test - * - * @return void - */ - public function loginUsingId(): void - { - self::assertEquals( - $this->user->withoutRelations()->toArray(), - $this->guard->loginUsingId($this->user->id)->toArray() - ); + /** + * @test + * + * @return void + */ + public function getAuthIdentifierName(): void + { + self::assertEquals( + $this->user->getKeyName(), + $this->guard->getAuthIdentifierName() + ); + } - self::assertEquals( - null, - $this->guard->loginUsingId($this->user->id + 512) - ); - } - - /** - * @test - * - * @return void - */ - public function validate(): void - { - self::assertTrue( - $this->guard->validate(['id' => $this->user->id, 'password' => 'password']) - ); - self::assertTrue( - $this->guard->validate(['email' => $this->user->email, 'password' => 'password']) - ); + /** + * @test + * + * @return void + */ + public function getAuthIdentifier(): void + { + self::assertEquals( + $this->user->id, + $this->guard->getAuthIdentifier() + ); + } - self::assertFalse( - $this->guard->validate(['id' => $this->user->id + 512, 'password' => 'password']) - ); - self::assertFalse( - $this->guard->validate(['email' => fake()->email(), 'password' => 'password']) - ); - self::assertFalse( - $this->guard->validate(['email' => $this->user->email, 'password' => 'wrong']) - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function login(): void - { - $user = UserFactory::createNormalUser(); - $this->guard->login($user); - - self::assertEquals( - $user->withoutRelations()->toArray(), - $this->guard->user()->toArray() - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function loginUsingToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user)->getAccessToken(); - - $this->guard->loginUsingToken($token); - self::assertEquals( - $user->withoutRelations()->only('id', 'name', 'email', 'version'), - $this->guard->user()->toArray() - ); - } + /** + * @test + * + * @return void + */ + public function getAuthPassword(): void + { + self::assertEquals( + $this->user->password, + $this->guard->getAuthPassword() + ); + } + + /** + * @test + * + * @return void + */ + public function getRememberToken(): void + { + self::assertNull($this->guard->getRememberToken()); + } + + /** + * @test + * + * @return void + */ + public function setRememberToken(): void + { + self::assertNull($this->guard->setRememberToken()); + } + + /** + * @test + * + * @return void + */ + public function getRememberTokenName(): void + { + self::assertNull($this->guard->getRememberTokenName()); + } + + /** + * @test + * + * @return void + */ + public function user(): void + { + self::assertEquals( + $this->user->only('id', 'name', 'email', 'version'), + $this->guard->user()->toArray() + ); + } + + /** + * @test + * + * @return void + */ + public function attempt(): void + { + self::assertTrue( + $this->guard->attempt(['id' => $this->user->id, 'password' => 'password']) + ); + self::assertEquals( + $this->user->withoutRelations()->toArray(), + $this->guard->user()->toArray() + ); + + self::assertFalse( + $this->guard->attempt(['id' => $this->user->id + 512, 'password' => 'password']) + ); + self::assertFalse( + $this->guard->attempt(['id' => $this->user->id, 'password' => 'wrong']) + ); + } + + /** + * @test + * + * @return void + */ + public function loginUsingId(): void + { + self::assertEquals( + $this->user->withoutRelations()->toArray(), + $this->guard->loginUsingId($this->user->id)->toArray() + ); + + self::assertEquals( + null, + $this->guard->loginUsingId($this->user->id + 512) + ); + } + + /** + * @test + * + * @return void + */ + public function validate(): void + { + self::assertTrue( + $this->guard->validate(['id' => $this->user->id, 'password' => 'password']) + ); + self::assertTrue( + $this->guard->validate(['email' => $this->user->email, 'password' => 'password']) + ); + + self::assertFalse( + $this->guard->validate(['id' => $this->user->id + 512, 'password' => 'password']) + ); + self::assertFalse( + $this->guard->validate(['email' => fake()->email(), 'password' => 'password']) + ); + self::assertFalse( + $this->guard->validate(['email' => $this->user->email, 'password' => 'wrong']) + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function login(): void + { + $user = UserFactory::createNormalUser(); + $this->guard->login($user); + + self::assertEquals( + $user->withoutRelations()->toArray(), + $this->guard->user()->toArray() + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function loginUsingToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user)->getAccessToken(); + + $this->guard->loginUsingToken($token); + self::assertEquals( + $user->withoutRelations()->only('id', 'name', 'email', 'version'), + $this->guard->user()->toArray() + ); } +} diff --git a/tests/Feature/Services/SphinxServiceTest.php b/tests/Feature/Services/SphinxServiceTest.php index c59add7..a704ca9 100644 --- a/tests/Feature/Services/SphinxServiceTest.php +++ b/tests/Feature/Services/SphinxServiceTest.php @@ -2,469 +2,469 @@ namespace Hans\Sphinx\Tests\Feature\Services; - use Hans\Horus\Exceptions\HorusException; - use Hans\Sphinx\Exceptions\SphinxException; - use Hans\Sphinx\Facades\Sphinx; - use Hans\Sphinx\Services\SphinxService; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\TestCase; - use Lcobucci\JWT\UnencryptedToken; +use Hans\Horus\Exceptions\HorusException; +use Hans\Sphinx\Exceptions\SphinxException; +use Hans\Sphinx\Facades\Sphinx; +use Hans\Sphinx\Services\SphinxService; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\TestCase; +use Lcobucci\JWT\UnencryptedToken; + +use function PHPUnit\Framework\assertStringEqualsStringIgnoringLineEndings; + +class SphinxServiceTest extends TestCase +{ + /** + * @test + * + * @throws HorusException + * @throws SphinxException + * + * @return void + */ + public function decode(): void + { + $token = UserFactory::generateToken()->getAccessToken(); + + self::assertInstanceOf( + UnencryptedToken::class, + $decoded = Sphinx::decode($token) + ); + + self::assertIsString($decoded->toString()); + self::assertStringEqualsStringIgnoringLineEndings( + $decoded->toString(), + $token + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function generateTokenFor(): void + { + $user = UserFactory::createNormalUser(); + $instance = Sphinx::generateTokenFor($user); + + self::assertInstanceOf( + SphinxService::class, + $instance + ); + self::assertIsString($instance->getAccessToken()); + self::assertIsString($instance->getRefreshToken()); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function getAccessToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user)->getAccessToken(); + + self::assertIsString($token); + + $decoded = Sphinx::decode($token); + + self::assertTrue($decoded->claims()->has('_token')); + self::assertStringEqualsStringIgnoringLineEndings( + Sphinx::getInnerAccessToken($token)->toString(), + $decoded->claims()->get('_token') + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function getRefreshToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user)->getRefreshToken(); + + self::assertIsString($token); + + $decoded = Sphinx::decode($token); + + self::assertTrue($decoded->claims()->has('_token')); + self::assertStringEqualsStringIgnoringLineEndings( + Sphinx::getInnerRefreshToken($token)->toString(), + $decoded->claims()->get('_token') + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function claim(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->claim('new', 'test') + ->getAccessToken(); + + self::assertFalse(Sphinx::decode($token)->claims()->has('new')); + self::assertTrue(Sphinx::getInnerAccessToken($token)->claims()->has('new')); + + assertStringEqualsStringIgnoringLineEndings( + 'test', + Sphinx::getInnerAccessToken($token)->claims()->get('new') + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function header(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->header('new', 'test') + ->getAccessToken(); + + self::assertFalse(Sphinx::decode($token)->headers()->has('new')); + self::assertTrue(Sphinx::getInnerAccessToken($token)->headers()->has('new')); + + assertStringEqualsStringIgnoringLineEndings( + 'test', + Sphinx::getInnerAccessToken($token)->headers()->get('new') + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function validateWrapperAccessToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getAccessToken(); + + self::assertTrue(Sphinx::validateWrapperAccessToken($token)); + + $index = rand(0, strlen($token) - 1); + do { + $randomAlphabet = fake()->word()[0]; + } while ($token[$index] == $randomAlphabet); + $token[$index] = $randomAlphabet; + self::assertFalse(Sphinx::validateWrapperAccessToken($token)); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function assertWrapperAccessToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getAccessToken(); + + Sphinx::assertWrapperAccessToken($token); + + $index = rand(0, strlen($token) - 1); + do { + $randomAlphabet = fake()->word()[0]; + } while ($token[$index] == $randomAlphabet); + $token[$index] = $randomAlphabet; + + $this->expectException(SphinxException::class); + + Sphinx::assertWrapperAccessToken($token); + } - use function PHPUnit\Framework\assertStringEqualsStringIgnoringLineEndings; + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function validateInnerAccessToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getAccessToken(); + + self::assertTrue(Sphinx::validateInnerAccessToken($token)); + + $index = rand(0, strlen($token) - 1); + do { + $randomAlphabet = fake()->word()[0]; + } while ($token[$index] == $randomAlphabet); + $token[$index] = $randomAlphabet; - class SphinxServiceTest extends TestCase + self::assertFalse(Sphinx::validateInnerAccessToken($token)); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function assertInnerAccessToken(): void { - /** - * @test - * - * @throws HorusException - * @throws SphinxException - * - * @return void - */ - public function decode(): void - { - $token = UserFactory::generateToken()->getAccessToken(); - - self::assertInstanceOf( - UnencryptedToken::class, - $decoded = Sphinx::decode($token) - ); - - self::assertIsString($decoded->toString()); - self::assertStringEqualsStringIgnoringLineEndings( - $decoded->toString(), - $token - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function generateTokenFor(): void - { - $user = UserFactory::createNormalUser(); - $instance = Sphinx::generateTokenFor($user); - - self::assertInstanceOf( - SphinxService::class, - $instance - ); - self::assertIsString($instance->getAccessToken()); - self::assertIsString($instance->getRefreshToken()); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function getAccessToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user)->getAccessToken(); - - self::assertIsString($token); - - $decoded = Sphinx::decode($token); - - self::assertTrue($decoded->claims()->has('_token')); - self::assertStringEqualsStringIgnoringLineEndings( - Sphinx::getInnerAccessToken($token)->toString(), - $decoded->claims()->get('_token') - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function getRefreshToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user)->getRefreshToken(); - - self::assertIsString($token); - - $decoded = Sphinx::decode($token); - - self::assertTrue($decoded->claims()->has('_token')); - self::assertStringEqualsStringIgnoringLineEndings( - Sphinx::getInnerRefreshToken($token)->toString(), - $decoded->claims()->get('_token') - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function claim(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->claim('new', 'test') - ->getAccessToken(); - - self::assertFalse(Sphinx::decode($token)->claims()->has('new')); - self::assertTrue(Sphinx::getInnerAccessToken($token)->claims()->has('new')); - - assertStringEqualsStringIgnoringLineEndings( - 'test', - Sphinx::getInnerAccessToken($token)->claims()->get('new') - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function header(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->header('new', 'test') - ->getAccessToken(); - - self::assertFalse(Sphinx::decode($token)->headers()->has('new')); - self::assertTrue(Sphinx::getInnerAccessToken($token)->headers()->has('new')); - - assertStringEqualsStringIgnoringLineEndings( - 'test', - Sphinx::getInnerAccessToken($token)->headers()->get('new') - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function validateWrapperAccessToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getAccessToken(); - - self::assertTrue(Sphinx::validateWrapperAccessToken($token)); - - $index = rand(0, strlen($token) - 1); - do { - $randomAlphabet = fake()->word()[0]; - } while ($token[$index] == $randomAlphabet); - $token[$index] = $randomAlphabet; - self::assertFalse(Sphinx::validateWrapperAccessToken($token)); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function assertWrapperAccessToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getAccessToken(); - - Sphinx::assertWrapperAccessToken($token); - - $index = rand(0, strlen($token) - 1); - do { - $randomAlphabet = fake()->word()[0]; - } while ($token[$index] == $randomAlphabet); - $token[$index] = $randomAlphabet; - - $this->expectException(SphinxException::class); - - Sphinx::assertWrapperAccessToken($token); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function validateInnerAccessToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getAccessToken(); - - self::assertTrue(Sphinx::validateInnerAccessToken($token)); - - $index = rand(0, strlen($token) - 1); - do { - $randomAlphabet = fake()->word()[0]; - } while ($token[$index] == $randomAlphabet); - $token[$index] = $randomAlphabet; - - self::assertFalse(Sphinx::validateInnerAccessToken($token)); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function assertInnerAccessToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getAccessToken(); - - Sphinx::assertWrapperAccessToken($token); - - $index = rand(0, strlen($token) - 1); - do { - $randomAlphabet = fake()->word()[0]; - } while ($token[$index] == $randomAlphabet); - $token[$index] = $randomAlphabet; - - $this->expectException(SphinxException::class); - - Sphinx::assertWrapperAccessToken($token); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function getInnerAccessToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getAccessToken(); - - $inner = Sphinx::getInnerAccessToken($token); - self::assertStringEqualsStringIgnoringLineEndings( - Sphinx::decode($token)->claims()->get('_token'), - $inner->toString() - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function validateWrapperRefreshToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getRefreshToken(); - - self::assertTrue(Sphinx::validateWrapperRefreshToken($token)); - - $index = rand(0, strlen($token) - 1); - do { - $randomAlphabet = fake()->word()[0]; - } while ($token[$index] == $randomAlphabet); - $token[$index] = $randomAlphabet; - self::assertFalse(Sphinx::validateWrapperRefreshToken($token)); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function assertWrapperRefreshToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getRefreshToken(); - - Sphinx::assertWrapperRefreshToken($token); - - $index = rand(0, strlen($token) - 1); - do { - $randomAlphabet = fake()->word()[0]; - } while ($token[$index] == $randomAlphabet); - $token[$index] = $randomAlphabet; - - $this->expectException(SphinxException::class); - - Sphinx::assertWrapperRefreshToken($token); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function validateInnerRefreshToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getRefreshToken(); - - self::assertTrue(Sphinx::validateInnerRefreshToken($token)); - - $index = rand(0, strlen($token) - 1); - do { - $randomAlphabet = fake()->word()[0]; - } while ($token[$index] == $randomAlphabet); - $token[$index] = $randomAlphabet; - - self::assertFalse(Sphinx::validateInnerRefreshToken($token)); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function assertInnerRefreshToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getRefreshToken(); - - Sphinx::assertInnerRefreshToken($token); - - $index = rand(0, strlen($token) - 1); - do { - $randomAlphabet = fake()->word()[0]; - } while ($token[$index] == $randomAlphabet); - $token[$index] = $randomAlphabet; - - $this->expectException(SphinxException::class); - - Sphinx::assertInnerRefreshToken($token); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function getInnerRefreshToken(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getRefreshToken(); - - $inner = Sphinx::getInnerRefreshToken($token); - self::assertStringEqualsStringIgnoringLineEndings( - Sphinx::decode($token)->claims()->get('_token'), - $inner->toString() - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function getPermissions(): void - { - $user = UserFactory::createNormalUser(); - $token = Sphinx::generateTokenFor($user) - ->getAccessToken(); - - self::assertCount( - $user->getAllPermissions()->count(), - Sphinx::getPermissions($token) - ); - self::assertEquals( - $user->getAllPermissions()->pluck('name', 'id')->toArray(), - Sphinx::getPermissions($token) - ); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function isRefreshToken(): void - { - $user = UserFactory::createNormalUser(); - $instance = Sphinx::generateTokenFor($user); - $access = $instance->getAccessToken(); - $refresh = $instance->getRefreshToken(); - - self::assertFalse(Sphinx::isRefreshToken($access)); - self::assertTrue(Sphinx::isRefreshToken($refresh)); - } - - /** - * @test - * - * @throws HorusException - * - * @return void - */ - public function isNotRefreshToken(): void - { - $user = UserFactory::createNormalUser(); - $instance = Sphinx::generateTokenFor($user); - $access = $instance->getAccessToken(); - $refresh = $instance->getRefreshToken(); - - self::assertTrue(Sphinx::isNotRefreshToken($access)); - self::assertFalse(Sphinx::isNotRefreshToken($refresh)); - } - - /** - * @test - * - * @throws HorusException - * @throws SphinxException - * - * @return void - */ - public function getCurrentSessionAndGuessSession(): void - { - $user = UserFactory::createNormalUser(); - $access = ( new SphinxService() )->generateTokenFor($user)->getAccessToken(); - - request()->headers->set('Authorization', "Bearer $access"); - - self::assertEquals( - $user->sessions()->first()->toArray(), - ( new SphinxService() )->getCurrentSession()->toArray() - ); - } + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getAccessToken(); + + Sphinx::assertWrapperAccessToken($token); + + $index = rand(0, strlen($token) - 1); + do { + $randomAlphabet = fake()->word()[0]; + } while ($token[$index] == $randomAlphabet); + $token[$index] = $randomAlphabet; + + $this->expectException(SphinxException::class); + + Sphinx::assertWrapperAccessToken($token); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function getInnerAccessToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getAccessToken(); + + $inner = Sphinx::getInnerAccessToken($token); + self::assertStringEqualsStringIgnoringLineEndings( + Sphinx::decode($token)->claims()->get('_token'), + $inner->toString() + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function validateWrapperRefreshToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getRefreshToken(); + + self::assertTrue(Sphinx::validateWrapperRefreshToken($token)); + + $index = rand(0, strlen($token) - 1); + do { + $randomAlphabet = fake()->word()[0]; + } while ($token[$index] == $randomAlphabet); + $token[$index] = $randomAlphabet; + self::assertFalse(Sphinx::validateWrapperRefreshToken($token)); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function assertWrapperRefreshToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getRefreshToken(); + + Sphinx::assertWrapperRefreshToken($token); + + $index = rand(0, strlen($token) - 1); + do { + $randomAlphabet = fake()->word()[0]; + } while ($token[$index] == $randomAlphabet); + $token[$index] = $randomAlphabet; + + $this->expectException(SphinxException::class); + + Sphinx::assertWrapperRefreshToken($token); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function validateInnerRefreshToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getRefreshToken(); + + self::assertTrue(Sphinx::validateInnerRefreshToken($token)); + + $index = rand(0, strlen($token) - 1); + do { + $randomAlphabet = fake()->word()[0]; + } while ($token[$index] == $randomAlphabet); + $token[$index] = $randomAlphabet; + + self::assertFalse(Sphinx::validateInnerRefreshToken($token)); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function assertInnerRefreshToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getRefreshToken(); + + Sphinx::assertInnerRefreshToken($token); + + $index = rand(0, strlen($token) - 1); + do { + $randomAlphabet = fake()->word()[0]; + } while ($token[$index] == $randomAlphabet); + $token[$index] = $randomAlphabet; + + $this->expectException(SphinxException::class); + + Sphinx::assertInnerRefreshToken($token); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function getInnerRefreshToken(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getRefreshToken(); + + $inner = Sphinx::getInnerRefreshToken($token); + self::assertStringEqualsStringIgnoringLineEndings( + Sphinx::decode($token)->claims()->get('_token'), + $inner->toString() + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function getPermissions(): void + { + $user = UserFactory::createNormalUser(); + $token = Sphinx::generateTokenFor($user) + ->getAccessToken(); + + self::assertCount( + $user->getAllPermissions()->count(), + Sphinx::getPermissions($token) + ); + self::assertEquals( + $user->getAllPermissions()->pluck('name', 'id')->toArray(), + Sphinx::getPermissions($token) + ); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function isRefreshToken(): void + { + $user = UserFactory::createNormalUser(); + $instance = Sphinx::generateTokenFor($user); + $access = $instance->getAccessToken(); + $refresh = $instance->getRefreshToken(); + + self::assertFalse(Sphinx::isRefreshToken($access)); + self::assertTrue(Sphinx::isRefreshToken($refresh)); + } + + /** + * @test + * + * @throws HorusException + * + * @return void + */ + public function isNotRefreshToken(): void + { + $user = UserFactory::createNormalUser(); + $instance = Sphinx::generateTokenFor($user); + $access = $instance->getAccessToken(); + $refresh = $instance->getRefreshToken(); + + self::assertTrue(Sphinx::isNotRefreshToken($access)); + self::assertFalse(Sphinx::isNotRefreshToken($refresh)); + } + + /** + * @test + * + * @throws HorusException + * @throws SphinxException + * + * @return void + */ + public function getCurrentSessionAndGuessSession(): void + { + $user = UserFactory::createNormalUser(); + $access = ( new SphinxService() )->generateTokenFor($user)->getAccessToken(); + + request()->headers->set('Authorization', "Bearer $access"); + + self::assertEquals( + $user->sessions()->first()->toArray(), + ( new SphinxService() )->getCurrentSession()->toArray() + ); } +} diff --git a/tests/Feature/Services/SphinxUserProviderTest.php b/tests/Feature/Services/SphinxUserProviderTest.php index 91041f0..48707c5 100644 --- a/tests/Feature/Services/SphinxUserProviderTest.php +++ b/tests/Feature/Services/SphinxUserProviderTest.php @@ -2,68 +2,68 @@ namespace Hans\Sphinx\Tests\Feature\Services; - use App\Models\User; - use Hans\Sphinx\Facades\Sphinx; - use Hans\Sphinx\Services\SphinxUserProvider; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\TestCase; +use App\Models\User; +use Hans\Sphinx\Facades\Sphinx; +use Hans\Sphinx\Services\SphinxUserProvider; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\TestCase; - class SphinxUserProviderTest extends TestCase - { - private User $user; - private SphinxUserProvider $provider; +class SphinxUserProviderTest extends TestCase +{ + private User $user; + private SphinxUserProvider $provider; - protected function setUp(): void - { - parent::setUp(); - $this->user = UserFactory::createNormalUser(); - $this->provider = app( - SphinxUserProvider::class, - ['model' => User::class] - ); - } + protected function setUp(): void + { + parent::setUp(); + $this->user = UserFactory::createNormalUser(); + $this->provider = app( + SphinxUserProvider::class, + ['model' => User::class] + ); + } - /** - * @test - * - * @return void - */ - public function retrieveByToken(): void - { - self::assertEquals( - $this->user->withoutRelations()->toArray(), - $this->provider->retrieveByToken($this->user->id)->toArray() - ); - } + /** + * @test + * + * @return void + */ + public function retrieveByToken(): void + { + self::assertEquals( + $this->user->withoutRelations()->toArray(), + $this->provider->retrieveByToken($this->user->id)->toArray() + ); + } - /** - * @test - * - * @return void - */ - public function updateRememberToken(): void - { - self::assertNull( - $this->provider->updateRememberToken() - ); - } + /** + * @test + * + * @return void + */ + public function updateRememberToken(): void + { + self::assertNull( + $this->provider->updateRememberToken() + ); + } - /** - * @test - * - * @return void - */ - public function retrieveByJwtTokenCredentials(): void - { - Sphinx::generateTokenFor($this->user)->getAccessToken(); + /** + * @test + * + * @return void + */ + public function retrieveByJwtTokenCredentials(): void + { + Sphinx::generateTokenFor($this->user)->getAccessToken(); - self::assertEquals( - $this->user->only('id', 'email'), - $this->provider - ->retrieveByJwtTokenCredentials( - ['id' => $this->user->id, 'email' => $this->user->email] - ) - ->toArray() - ); - } + self::assertEquals( + $this->user->only('id', 'email'), + $this->provider + ->retrieveByJwtTokenCredentials( + ['id' => $this->user->id, 'email' => $this->user->email] + ) + ->toArray() + ); } +} diff --git a/tests/Feature/Traits/SphinxMethodsTest.php b/tests/Feature/Traits/SphinxMethodsTest.php index df20ad6..3fe4c78 100644 --- a/tests/Feature/Traits/SphinxMethodsTest.php +++ b/tests/Feature/Traits/SphinxMethodsTest.php @@ -2,91 +2,91 @@ namespace Hans\Sphinx\Tests\Feature\Traits; - use App\Models\User; - use Hans\Horus\Exceptions\HorusException; - use Hans\Sphinx\Exceptions\SphinxException; - use Hans\Sphinx\Helpers\Enums\SphinxCache; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\TestCase; - use Illuminate\Database\Eloquent\Model; - use Illuminate\Support\Facades\Cache; +use App\Models\User; +use Hans\Horus\Exceptions\HorusException; +use Hans\Sphinx\Exceptions\SphinxException; +use Hans\Sphinx\Helpers\Enums\SphinxCache; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\TestCase; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Cache; - class SphinxMethodsTest extends TestCase - { - private Model $user; +class SphinxMethodsTest extends TestCase +{ + private Model $user; - protected function setUp(): void - { - parent::setUp(); - $this->user = UserFactory::createNormalUser(); - } + protected function setUp(): void + { + parent::setUp(); + $this->user = UserFactory::createNormalUser(); + } - /** - * @test - * - * @return void - */ - public function increaseVersionUsingNoSession(): void - { - $version = $this->user->getVersion(); + /** + * @test + * + * @return void + */ + public function increaseVersionUsingNoSession(): void + { + $version = $this->user->getVersion(); - $this->user->update(['name' => fake()->name()]); + $this->user->update(['name' => fake()->name()]); - self::assertEquals( - $version, // no change - $this->user->getVersion() - ); - } + self::assertEquals( + $version, // no change + $this->user->getVersion() + ); + } - /** - * @test - * - * @throws HorusException|SphinxException - * - * @return void - */ - public function increaseVersionUsingSession(): void - { - capture_session($this->user); + /** + * @test + * + * @throws HorusException|SphinxException + * + * @return void + */ + public function increaseVersionUsingSession(): void + { + capture_session($this->user); - $version = $this->user->getVersion(); - $session = $this->user->sessions->first(); - $key = SphinxCache::SESSION.$session->id; + $version = $this->user->getVersion(); + $session = $this->user->sessions->first(); + $key = SphinxCache::SESSION.$session->id; - self::assertEquals( - $version, - Cache::get($key)->sessionable_version - ); + self::assertEquals( + $version, + Cache::get($key)->sessionable_version + ); - $this->user->update(['name' => fake()->name()]); + $this->user->update(['name' => fake()->name()]); - self::assertEquals( - $version + 1, - $this->user->getVersion() - ); - self::assertEquals( - $version + 1, - Cache::get($key)->sessionable_version - ); - } + self::assertEquals( + $version + 1, + $this->user->getVersion() + ); + self::assertEquals( + $version + 1, + Cache::get($key)->sessionable_version + ); + } - /** - * @test - * - * @return void - */ - public function getVersion(): void - { - self::assertEquals( - $this->user->version, - $this->user->getVersion() - ); + /** + * @test + * + * @return void + */ + public function getVersion(): void + { + self::assertEquals( + $this->user->version, + $this->user->getVersion() + ); - $user = User::query()->find($this->user->id, ['id']); + $user = User::query()->find($this->user->id, ['id']); - self::assertEquals( - $this->user->getVersion(), - $user->getVersion() - ); - } + self::assertEquals( + $this->user->getVersion(), + $user->getVersion() + ); } +} diff --git a/tests/Feature/Traits/SphinxTokenCanTest.php b/tests/Feature/Traits/SphinxTokenCanTest.php index b85c91b..fec93c6 100644 --- a/tests/Feature/Traits/SphinxTokenCanTest.php +++ b/tests/Feature/Traits/SphinxTokenCanTest.php @@ -2,117 +2,117 @@ namespace Hans\Sphinx\Tests\Feature\Traits; - use App\Models\User; - use Hans\Sphinx\Facades\Sphinx; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\TestCase; - use Spatie\Permission\Models\Permission; +use App\Models\User; +use Hans\Sphinx\Facades\Sphinx; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\TestCase; +use Spatie\Permission\Models\Permission; - class SphinxTokenCanTest extends TestCase - { - private User $user; +class SphinxTokenCanTest extends TestCase +{ + private User $user; - protected function setUp(): void - { - parent::setUp(); - $this->user = UserFactory::createAdminUser(); - request()->headers->set( - 'Authorization', - 'Bearer '.Sphinx::generateTokenFor($this->user)->getAccessToken() - ); - } + protected function setUp(): void + { + parent::setUp(); + $this->user = UserFactory::createAdminUser(); + request()->headers->set( + 'Authorization', + 'Bearer '.Sphinx::generateTokenFor($this->user)->getAccessToken() + ); + } - /** - * @test - * - * @return void - */ - public function can(): void - { - self::assertTrue( - $this->user->can('user-view') - ); - self::assertTrue( - $this->user->can(Permission::findByName('user-view')->id) - ); - self::assertTrue( - $this->user->can('user-*') - ); + /** + * @test + * + * @return void + */ + public function can(): void + { + self::assertTrue( + $this->user->can('user-view') + ); + self::assertTrue( + $this->user->can(Permission::findByName('user-view')->id) + ); + self::assertTrue( + $this->user->can('user-*') + ); - self::assertFalse( - $this->user->can('wrong-view') - ); - } + self::assertFalse( + $this->user->can('wrong-view') + ); + } - /** - * @test - * - * @return void - */ - public function canAny(): void - { - self::assertTrue( - $this->user->canAny(['wrong-update', 'user-view', 'wrong-view']) - ); - self::assertTrue( - $this->user->canAny(['wrong-update', 'user-*', 'wrong-view']) - ); - self::assertTrue( - $this->user->canAny(Permission::findByName('user-view')->id) - ); + /** + * @test + * + * @return void + */ + public function canAny(): void + { + self::assertTrue( + $this->user->canAny(['wrong-update', 'user-view', 'wrong-view']) + ); + self::assertTrue( + $this->user->canAny(['wrong-update', 'user-*', 'wrong-view']) + ); + self::assertTrue( + $this->user->canAny(Permission::findByName('user-view')->id) + ); - self::assertFalse( - $this->user->canAny(['wrong-view', 'wrong-update']) - ); - } + self::assertFalse( + $this->user->canAny(['wrong-view', 'wrong-update']) + ); + } - /** - * @test - * - * @return void - */ - public function cannot(): void - { - self::assertTrue( - $this->user->cannot('wrong-update') - ); - self::assertTrue( - $this->user->cannot(['wrong-view', 'wrong-update']) - ); + /** + * @test + * + * @return void + */ + public function cannot(): void + { + self::assertTrue( + $this->user->cannot('wrong-update') + ); + self::assertTrue( + $this->user->cannot(['wrong-view', 'wrong-update']) + ); - self::assertFalse( - $this->user->cannot('user-view') - ); - self::assertFalse( - $this->user->cannot('user-*') - ); - self::assertFalse( - $this->user->cannot(['user-view', 'user-*']) - ); - } + self::assertFalse( + $this->user->cannot('user-view') + ); + self::assertFalse( + $this->user->cannot('user-*') + ); + self::assertFalse( + $this->user->cannot(['user-view', 'user-*']) + ); + } - /** - * @test - * - * @return void - */ - public function cant(): void - { - self::assertTrue( - $this->user->cant('wrong-update') - ); - self::assertTrue( - $this->user->cant(['wrong-view', 'wrong-update']) - ); + /** + * @test + * + * @return void + */ + public function cant(): void + { + self::assertTrue( + $this->user->cant('wrong-update') + ); + self::assertTrue( + $this->user->cant(['wrong-view', 'wrong-update']) + ); - self::assertFalse( - $this->user->cant('user-view') - ); - self::assertFalse( - $this->user->cant('user-*') - ); - self::assertFalse( - $this->user->cant(['user-view', 'user-*']) - ); - } + self::assertFalse( + $this->user->cant('user-view') + ); + self::assertFalse( + $this->user->cant('user-*') + ); + self::assertFalse( + $this->user->cant(['user-view', 'user-*']) + ); } +} diff --git a/tests/Instances/JwtTokenInstance.php b/tests/Instances/JwtTokenInstance.php index 6174d9b..8e65857 100644 --- a/tests/Instances/JwtTokenInstance.php +++ b/tests/Instances/JwtTokenInstance.php @@ -2,18 +2,18 @@ namespace Hans\Sphinx\Tests\Instances; - use Hans\Sphinx\Drivers\Constraints\ExpirationValidator; - use Hans\Sphinx\Drivers\Contracts\JwtToken; +use Hans\Sphinx\Drivers\Constraints\ExpirationValidator; +use Hans\Sphinx\Drivers\Contracts\JwtToken; - class JwtTokenInstance extends JwtToken +class JwtTokenInstance extends JwtToken +{ + /** + * @return array + */ + protected function getAvailableConstrains(): array { - /** - * @return array - */ - protected function getAvailableConstrains(): array - { - return [ - new ExpirationValidator(), - ]; - } + return [ + new ExpirationValidator(), + ]; } +} diff --git a/tests/Instances/JwtTokenWithCustomizableConstraintsInstance.php b/tests/Instances/JwtTokenWithCustomizableConstraintsInstance.php index d0eb43a..dc4b637 100644 --- a/tests/Instances/JwtTokenWithCustomizableConstraintsInstance.php +++ b/tests/Instances/JwtTokenWithCustomizableConstraintsInstance.php @@ -2,28 +2,28 @@ namespace Hans\Sphinx\Tests\Instances; - use Hans\Sphinx\Drivers\Contracts\JwtToken; - use Lcobucci\JWT\Validation\Constraint; +use Hans\Sphinx\Drivers\Contracts\JwtToken; +use Lcobucci\JWT\Validation\Constraint; - class JwtTokenWithCustomizableConstraintsInstance extends JwtToken - { - private array $constraints = []; +class JwtTokenWithCustomizableConstraintsInstance extends JwtToken +{ + private array $constraints = []; - /** - * @return array - */ - protected function getAvailableConstrains(): array - { - return $this->constraints; - } + /** + * @return array + */ + protected function getAvailableConstrains(): array + { + return $this->constraints; + } - public function registerConstrain(Constraint $constraint): self - { - $this->constraints[] = $constraint; + public function registerConstrain(Constraint $constraint): self + { + $this->constraints[] = $constraint; - $this->configuration->setValidationConstraints(...$this->getAvailableConstrains()); - $this->instance = $this->configuration->builder(); + $this->configuration->setValidationConstraints(...$this->getAvailableConstrains()); + $this->instance = $this->configuration->builder(); - return $this; - } + return $this; } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 47e5e9d..6e77a72 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,160 +2,160 @@ namespace Hans\Sphinx\Tests; - use App\Models\RoleDelegate; - use App\Models\User; - use Hans\Horus\Facades\Horus; - use Hans\Horus\HorusServiceProvider; - use Hans\Sphinx\SphinxServiceProvider; - use Illuminate\Foundation\Application; - use Illuminate\Foundation\Testing\RefreshDatabase; - use Illuminate\Routing\Router; - use Orchestra\Testbench\TestCase as BaseTestCase; - use Spatie\Permission\PermissionServiceProvider; - - class TestCase extends BaseTestCase +use App\Models\RoleDelegate; +use App\Models\User; +use Hans\Horus\Facades\Horus; +use Hans\Horus\HorusServiceProvider; +use Hans\Sphinx\SphinxServiceProvider; +use Illuminate\Foundation\Application; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Routing\Router; +use Orchestra\Testbench\TestCase as BaseTestCase; +use Spatie\Permission\PermissionServiceProvider; + +class TestCase extends BaseTestCase +{ + use RefreshDatabase; + + const ADMIN_AREA = 'employees'; + const DEFAULT_ADMINS = 'admin'; + + const USER_AREA = 'customers'; + const DEFAULT_USERS = 'user'; + + /** + * Setup the test environment. + */ + protected function setUp(): void { - use RefreshDatabase; - - const ADMIN_AREA = 'employees'; - const DEFAULT_ADMINS = 'admin'; - - const USER_AREA = 'customers'; - const DEFAULT_USERS = 'user'; - - /** - * Setup the test environment. - */ - protected function setUp(): void - { - parent::setUp(); - config()->set('cache.default', 'array'); - config()->set( - 'sphinx.secret', - 'XELnlAjESvqWDS3utBoN9cEA8eF3PlTtyXJ1OmCUIhxfIJKdePkoof8aKCbfucOCqpuygSDv4ZobA4936UXqzshfJrw' - ); - config()->set( - 'sphinx.role_model', - RoleDelegate::class - ); - - $this->seedHorus(); - } - - private function seedHorus(): void - { - Horus::createPermissions([User::class]); - - Horus::createSuperPermissions([User::class]); - - Horus::createRoles([self::DEFAULT_ADMINS, self::DEFAULT_USERS]); - - Horus::assignPermissionsToRole( - self::DEFAULT_ADMINS, - [ - User::class => [ - 'view', - 'update', - ], - ] - ); - - Horus::assignPermissionsToRole(self::DEFAULT_USERS, [User::class => ['view']]); - - Horus::assignSuperPermissionsToRole(self::DEFAULT_ADMINS, [User::class]); - } - - /** - * Get application timezone. - * - * @param Application $app - * - * @return string|null - */ - protected function getApplicationTimezone($app): ?string - { - return 'UTC'; - } - - /** - * Get package providers. - * - * @param Application $app - * - * @return array - */ - protected function getPackageProviders($app): array - { - return [ - SphinxServiceProvider::class, - HorusServiceProvider::class, - PermissionServiceProvider::class, - ]; - } - - /** - * Override application aliases. - * - * @param Application $app - * - * @return array - */ - protected function getPackageAliases($app): array - { - return [// 'Acme' => 'Acme\Facade', - ]; - } - - /** - * Define environment setup. - * - * @param Application $app - * - * @return void - */ - protected function defineEnvironment($app): void - { - // Setup default database to use sqlite :memory: - $app['config']->set('database.default', 'testbench'); - $app['config']->set('database.connections.testbench', [ - 'driver' => 'sqlite', - 'database' => ':memory:', - 'prefix' => '', - ]); - } - - /** - * Define routes setup. - * - * @param Router $router - * - * @return void - */ - protected function defineRoutes($router): void - { - $router->get('/me', function () { - return auth()->user(); - }) - ->name('test.me'); - } - - /** - * Define database migrations. - * - * @return void - */ - protected function defineDatabaseMigrations(): void - { - $this->loadLaravelMigrations(); - } - - /** - * Get base path. - * - * @return string - */ - protected function getBasePath(): string - { - return __DIR__.'/skeleton/laravel-10.x'; - } + parent::setUp(); + config()->set('cache.default', 'array'); + config()->set( + 'sphinx.secret', + 'XELnlAjESvqWDS3utBoN9cEA8eF3PlTtyXJ1OmCUIhxfIJKdePkoof8aKCbfucOCqpuygSDv4ZobA4936UXqzshfJrw' + ); + config()->set( + 'sphinx.role_model', + RoleDelegate::class + ); + + $this->seedHorus(); } + + private function seedHorus(): void + { + Horus::createPermissions([User::class]); + + Horus::createSuperPermissions([User::class]); + + Horus::createRoles([self::DEFAULT_ADMINS, self::DEFAULT_USERS]); + + Horus::assignPermissionsToRole( + self::DEFAULT_ADMINS, + [ + User::class => [ + 'view', + 'update', + ], + ] + ); + + Horus::assignPermissionsToRole(self::DEFAULT_USERS, [User::class => ['view']]); + + Horus::assignSuperPermissionsToRole(self::DEFAULT_ADMINS, [User::class]); + } + + /** + * Get application timezone. + * + * @param Application $app + * + * @return string|null + */ + protected function getApplicationTimezone($app): ?string + { + return 'UTC'; + } + + /** + * Get package providers. + * + * @param Application $app + * + * @return array + */ + protected function getPackageProviders($app): array + { + return [ + SphinxServiceProvider::class, + HorusServiceProvider::class, + PermissionServiceProvider::class, + ]; + } + + /** + * Override application aliases. + * + * @param Application $app + * + * @return array + */ + protected function getPackageAliases($app): array + { + return [// 'Acme' => 'Acme\Facade', + ]; + } + + /** + * Define environment setup. + * + * @param Application $app + * + * @return void + */ + protected function defineEnvironment($app): void + { + // Setup default database to use sqlite :memory: + $app['config']->set('database.default', 'testbench'); + $app['config']->set('database.connections.testbench', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + } + + /** + * Define routes setup. + * + * @param Router $router + * + * @return void + */ + protected function defineRoutes($router): void + { + $router->get('/me', function () { + return auth()->user(); + }) + ->name('test.me'); + } + + /** + * Define database migrations. + * + * @return void + */ + protected function defineDatabaseMigrations(): void + { + $this->loadLaravelMigrations(); + } + + /** + * Get base path. + * + * @return string + */ + protected function getBasePath(): string + { + return __DIR__.'/skeleton/laravel-10.x'; + } +} diff --git a/tests/Unit/SessionModelTest.php b/tests/Unit/SessionModelTest.php index bf7f0c1..de50f79 100644 --- a/tests/Unit/SessionModelTest.php +++ b/tests/Unit/SessionModelTest.php @@ -2,54 +2,54 @@ namespace Hans\Sphinx\Tests\Unit; - use Hans\Horus\Exceptions\HorusException; - use Hans\Sphinx\Exceptions\SphinxException; - use Hans\Sphinx\Helpers\Enums\SphinxCache; - use Hans\Sphinx\Models\Session; - use Hans\Sphinx\Tests\Factories\UserFactory; - use Hans\Sphinx\Tests\TestCase; - use Illuminate\Cache\ArrayStore; - use Illuminate\Support\Facades\Cache; - use Mockery; - - class SessionModelTest extends TestCase +use Hans\Horus\Exceptions\HorusException; +use Hans\Sphinx\Exceptions\SphinxException; +use Hans\Sphinx\Helpers\Enums\SphinxCache; +use Hans\Sphinx\Models\Session; +use Hans\Sphinx\Tests\Factories\UserFactory; +use Hans\Sphinx\Tests\TestCase; +use Illuminate\Cache\ArrayStore; +use Illuminate\Support\Facades\Cache; +use Mockery; + +class SessionModelTest extends TestCase +{ + /** + * @test + * + * @throws HorusException + * @throws SphinxException + * + * @return void + */ + public function create(): void { - /** - * @test - * - * @throws HorusException - * @throws SphinxException - * - * @return void - */ - public function create(): void - { - $user = UserFactory::createNormalUser(); - $model = capture_session($user); - - $this->assertModelExists($model); - } - - /** - * @test - * - * @throws HorusException - * @throws SphinxException - * - * @return void - */ - public function findAndCache(): void - { - $user = UserFactory::createNormalUser(); - $model = capture_session($user); - - Cache::forget(SphinxCache::SESSION.$model->id); - self::assertNull(Cache::get(SphinxCache::SESSION.$model->id)); - - $mock = Mockery::spy(ArrayStore::class)->makePartial(); - $mock->shouldReceive('forever')->once(); - Cache::setStore($mock); - - Session::findAndCache($model->id); - } + $user = UserFactory::createNormalUser(); + $model = capture_session($user); + + $this->assertModelExists($model); + } + + /** + * @test + * + * @throws HorusException + * @throws SphinxException + * + * @return void + */ + public function findAndCache(): void + { + $user = UserFactory::createNormalUser(); + $model = capture_session($user); + + Cache::forget(SphinxCache::SESSION.$model->id); + self::assertNull(Cache::get(SphinxCache::SESSION.$model->id)); + + $mock = Mockery::spy(ArrayStore::class)->makePartial(); + $mock->shouldReceive('forever')->once(); + Cache::setStore($mock); + + Session::findAndCache($model->id); } +} diff --git a/tests/skeleton/laravel-10.x/app/Http/Middleware/ValidateSignature.php b/tests/skeleton/laravel-10.x/app/Http/Middleware/ValidateSignature.php index f25ce76..093bf64 100644 --- a/tests/skeleton/laravel-10.x/app/Http/Middleware/ValidateSignature.php +++ b/tests/skeleton/laravel-10.x/app/Http/Middleware/ValidateSignature.php @@ -2,21 +2,21 @@ namespace App\Http\Middleware; - use Illuminate\Routing\Middleware\ValidateSignature as Middleware; +use Illuminate\Routing\Middleware\ValidateSignature as Middleware; - class ValidateSignature extends Middleware - { - /** - * The names of the query string parameters that should be ignored. - * - * @var array - */ - protected $except = [ - // 'fbclid', - // 'utm_campaign', - // 'utm_content', - // 'utm_medium', - // 'utm_source', - // 'utm_term', - ]; - } +class ValidateSignature extends Middleware +{ + /** + * The names of the query string parameters that should be ignored. + * + * @var array + */ + protected $except = [ + // 'fbclid', + // 'utm_campaign', + // 'utm_content', + // 'utm_medium', + // 'utm_source', + // 'utm_term', + ]; +} diff --git a/tests/skeleton/laravel-10.x/app/Models/RoleDelegate.php b/tests/skeleton/laravel-10.x/app/Models/RoleDelegate.php index db0e367..5ae2b18 100644 --- a/tests/skeleton/laravel-10.x/app/Models/RoleDelegate.php +++ b/tests/skeleton/laravel-10.x/app/Models/RoleDelegate.php @@ -2,59 +2,59 @@ namespace App\Models; - use Hans\Horus\Helpers\Enums\CacheEnum; - use Illuminate\Support\Facades\Cache; - use Spatie\Permission\Models\Role; - use Throwable; +use Hans\Horus\Helpers\Enums\CacheEnum; +use Illuminate\Support\Facades\Cache; +use Spatie\Permission\Models\Role; +use Throwable; - // TODO: not documented in horus - class RoleDelegate extends Role +// TODO: not documented in horus +class RoleDelegate extends Role +{ + /** + * @param int $id + * + * @return static + */ + public static function findAndCache(int $id): self { - /** - * @param int $id - * - * @return static - */ - public static function findAndCache(int $id): self - { - return Cache::rememberForever( - self::cacheKey($id), - fn () => self::query()->findOrFail($id) - ); - } - - /** - * @return int - */ - public function getVersion(): int - { - return $this->version ?: self::query()->findOrFail($this->id, ['id', 'version'])->version; - } + return Cache::rememberForever( + self::cacheKey($id), + fn () => self::query()->findOrFail($id) + ); + } - /** - * @return bool - */ - public function increaseVersion(): bool - { - try { - $this->increment('version'); - $this->fill(['version' => $this->getVersion() + 1])->saveQuietly(); - Cache::forget(self::cacheKey($this->id)); - Cache::forever(self::cacheKey($this->id), $this); - } catch (Throwable $e) { - return false; - } + /** + * @return int + */ + public function getVersion(): int + { + return $this->version ?: self::query()->findOrFail($this->id, ['id', 'version'])->version; + } - return true; + /** + * @return bool + */ + public function increaseVersion(): bool + { + try { + $this->increment('version'); + $this->fill(['version' => $this->getVersion() + 1])->saveQuietly(); + Cache::forget(self::cacheKey($this->id)); + Cache::forever(self::cacheKey($this->id), $this); + } catch (Throwable $e) { + return false; } - /** - * @param int $id - * - * @return string - */ - private static function cacheKey(int $id): string - { - return CacheEnum::ROLE->value."_$id"; - } + return true; + } + + /** + * @param int $id + * + * @return string + */ + private static function cacheKey(int $id): string + { + return CacheEnum::ROLE->value."_$id"; } +} diff --git a/tests/skeleton/laravel-10.x/app/Models/User.php b/tests/skeleton/laravel-10.x/app/Models/User.php index 3c6397c..66df65e 100644 --- a/tests/skeleton/laravel-10.x/app/Models/User.php +++ b/tests/skeleton/laravel-10.x/app/Models/User.php @@ -2,90 +2,90 @@ namespace App\Models; - use Hans\Sphinx\Traits\SphinxTrait; - use Illuminate\Database\Eloquent\Factories\HasFactory; - use Illuminate\Foundation\Auth\User as Authenticatable; - use Illuminate\Notifications\Notifiable; - use Spatie\Permission\Models\Role; - use Spatie\Permission\Traits\HasRoles; +use Hans\Sphinx\Traits\SphinxTrait; +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Notifications\Notifiable; +use Spatie\Permission\Models\Role; +use Spatie\Permission\Traits\HasRoles; - class User extends Authenticatable - { - use HasFactory; - use Notifiable; - use SphinxTrait, SphinxTrait { - SphinxTrait::hooks as private handleCaching; - } - use HasRoles; +class User extends Authenticatable +{ + use HasFactory; + use Notifiable; + use SphinxTrait, SphinxTrait { + SphinxTrait::hooks as private handleCaching; + } + use HasRoles; - /** - * The attributes that are mass assignable. - * - * @var array - */ - protected $fillable = [ - 'name', - 'email', - 'password', - 'version', - ]; + /** + * The attributes that are mass assignable. + * + * @var array + */ + protected $fillable = [ + 'name', + 'email', + 'password', + 'version', + ]; - /** - * The attributes that should be hidden for serialization. - * - * @var array - */ - protected $hidden = [ - 'password', - 'remember_token', - ]; + /** + * The attributes that should be hidden for serialization. + * + * @var array + */ + protected $hidden = [ + 'password', + 'remember_token', + ]; - /** - * The attributes that should be cast. - * - * @var array - */ - protected $casts = [ - 'email_verified_at' => 'datetime', - 'password' => 'encrypted', - ]; + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = [ + 'email_verified_at' => 'datetime', + 'password' => 'encrypted', + ]; - protected static function booted() - { - self::handleCaching(); - } + protected static function booted() + { + self::handleCaching(); + } - public function getRole(): ?Role - { - return $this->roles()->first(); - } + public function getRole(): ?Role + { + return $this->roles()->first(); + } - public function getDeviceLimit(): int - { - return 2; - } + public function getDeviceLimit(): int + { + return 2; + } - public function extract(): array - { - return [ - 'name' => $this->name, - 'email' => $this->email, - 'version' => $this->getVersion(), - ]; - } + public function extract(): array + { + return [ + 'name' => $this->name, + 'email' => $this->email, + 'version' => $this->getVersion(), + ]; + } - public function username(): string - { - return 'email'; - } + public function username(): string + { + return 'email'; + } - public function extractRole(): ?array - { - return $this->roles()->first()?->toArray(); - } + public function extractRole(): ?array + { + return $this->roles()->first()?->toArray(); + } - public function extractPermissions(): array - { - return $this->getAllPermissions()->toArray(); - } + public function extractPermissions(): array + { + return $this->getAllPermissions()->toArray(); } +} diff --git a/tests/skeleton/laravel-10.x/database/seeders/DatabaseSeeder.php b/tests/skeleton/laravel-10.x/database/seeders/DatabaseSeeder.php index 064bbc2..232457d 100644 --- a/tests/skeleton/laravel-10.x/database/seeders/DatabaseSeeder.php +++ b/tests/skeleton/laravel-10.x/database/seeders/DatabaseSeeder.php @@ -2,21 +2,21 @@ namespace Database\Seeders; - // use Illuminate\Database\Console\Seeds\WithoutModelEvents; - use Illuminate\Database\Seeder; +// use Illuminate\Database\Console\Seeds\WithoutModelEvents; +use Illuminate\Database\Seeder; - class DatabaseSeeder extends Seeder +class DatabaseSeeder extends Seeder +{ + /** + * Seed the application's database. + */ + public function run(): void { - /** - * Seed the application's database. - */ - public function run(): void - { - // \App\Models\User::factory(10)->create(); + // \App\Models\User::factory(10)->create(); - // \App\Models\User::factory()->create([ + // \App\Models\User::factory()->create([ // 'name' => 'Test User', // 'email' => 'test@example.com', - // ]); - } + // ]); } +}