diff --git a/bin/composer-post-install-script.php b/bin/composer-post-install-script.php index 20671c9..3d02d44 100644 --- a/bin/composer-post-install-script.php +++ b/bin/composer-post-install-script.php @@ -54,7 +54,12 @@ function getEnvironment(): string ], [ 'source' => 'vendor/dotkernel/dot-mail/config/mail.global.php.dist', - 'destination' => 'config/autoload/mail.global.php', + 'destination' => 'config/autoload/mail.local.php', + 'environment' => [ENVIRONMENT_DEVELOPMENT, ENVIRONMENT_PRODUCTION], + ], + [ + 'source' => 'vendor/dotkernel/dot-mail/config/mail.global.php.dist', + 'destination' => 'config/autoload/mail.local.php.dist', 'environment' => [ENVIRONMENT_DEVELOPMENT, ENVIRONMENT_PRODUCTION], ], ]; diff --git a/composer.json b/composer.json index db256b1..21496fe 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ "laminas/laminas-component-installer": "^3.7.0", "laminas/laminas-config-aggregator": "^1.19.0", "mezzio/mezzio": "^3.26.0", - "mezzio/mezzio-authentication-oauth2": "^2.13.0", + "mezzio/mezzio-authentication-oauth2": "^3.0.1", "mezzio/mezzio-authorization-rbac": "^1.10.0", "mezzio/mezzio-cors": "^1.15.0", "mezzio/mezzio-fastroute": "^3.14.0", diff --git a/src/Admin/src/Service/AdminLoginService.php b/src/Admin/src/Service/AdminLoginService.php index ffd0c6e..28588a4 100644 --- a/src/Admin/src/Service/AdminLoginService.php +++ b/src/Admin/src/Service/AdminLoginService.php @@ -57,7 +57,11 @@ public function getAdminLogins(array $params): array 'login.osVersion', 'login.clientType', 'login.clientName', - 'login.isCrawler', + 'login.deviceBrand', + 'login.deviceModel', + 'login.osPlatform', + 'login.clientEngine', + 'login.clientVersion', 'login.loginStatus', 'login.identity', 'login.created', @@ -75,7 +79,7 @@ public function getAdminLogins(array $params): array } /** - * @param non-empty-array $serverParams + * @param array{HTTP_X_FORWARDED_FOR?: string, HTTP_CLIENT_IP?: string, REMOTE_ADDR: string} $serverParams * @throws Exception */ public function logFailedLogin(array $serverParams, string $name): AdminLogin @@ -84,7 +88,7 @@ public function logFailedLogin(array $serverParams, string $name): AdminLogin } /** - * @param non-empty-array $serverParams + * @param array{HTTP_X_FORWARDED_FOR?: string, HTTP_CLIENT_IP?: string, REMOTE_ADDR: string} $serverParams * @throws Exception */ public function logSuccessfulLogin(array $serverParams, string $name): AdminLogin @@ -93,7 +97,7 @@ public function logSuccessfulLogin(array $serverParams, string $name): AdminLogi } /** - * @param non-empty-array $serverParams + * @param array{HTTP_X_FORWARDED_FOR?: string, HTTP_CLIENT_IP?: string, REMOTE_ADDR: string} $serverParams * @throws Exception */ private function logAdminVisit(array $serverParams, string $name, SuccessFailureEnum $status): AdminLogin @@ -111,7 +115,8 @@ private function logAdminVisit(array $serverParams, string $name, SuccessFailure */ $browser = new stdClass(); if (ini_get('browscap')) { - $browser = get_browser($_SERVER['HTTP_USER_AGENT']); + $result = get_browser($_SERVER['HTTP_USER_AGENT']); + $browser = $result instanceof stdClass ? $result : $browser; } $adminLogin = (new AdminLogin()) @@ -128,7 +133,11 @@ private function logAdminVisit(array $serverParams, string $name, SuccessFailure ->setClientType(! empty($browser->browser_type) ? $browser->browser_type : null) ->setClientName(! empty($browser->browser) ? $browser->browser : null) ->setLoginStatus($status) - ->setIsCrawler(! empty($browser->crawler) ? YesNoEnum::Yes : YesNoEnum::No) + ->setDeviceBrand(! empty($browser->device_brand) ? $browser->device_brand : null) + ->setDeviceBrand(! empty($browser->device_model) ? $browser->device_model : null) + ->setDeviceBrand(! empty($browser->platform_version) ? $browser->platform_version : null) + ->setDeviceBrand(! empty($browser->browser_engine) ? $browser->browser_engine : null) + ->setDeviceBrand(! empty($browser->browser_version) ? $browser->browser_version : null) ->setIdentity($name); $this->adminLoginRepository->saveResource($adminLogin); diff --git a/src/Admin/templates/admin/list-admin-login.html.twig b/src/Admin/templates/admin/list-admin-login.html.twig index cab7aa7..df59bff 100644 --- a/src/Admin/templates/admin/list-admin-login.html.twig +++ b/src/Admin/templates/admin/list-admin-login.html.twig @@ -91,8 +91,20 @@ {{ sortableColumn('admin::list-admin-login', {}, pagination.queryParams, 'login.clientName', 'Client Name') }} - - {{ sortableColumn('admin::list-admin-login', {}, pagination.queryParams, 'login.isCrawler', 'Is Crawler') }} + + {{ sortableColumn('admin::list-admin-login', {}, pagination.queryParams, 'login.deviceBrand', 'Device Brand') }} + + + {{ sortableColumn('admin::list-admin-login', {}, pagination.queryParams, 'login.deviceModel', 'Device Model') }} + + + {{ sortableColumn('admin::list-admin-login', {}, pagination.queryParams, 'login.osPlatform', 'Os Platform') }} + + + {{ sortableColumn('admin::list-admin-login', {}, pagination.queryParams, 'login.clientEngine', 'Client Engine') }} + + + {{ sortableColumn('admin::list-admin-login', {}, pagination.queryParams, 'login.clientVersion', 'Client Version') }} {{ sortableColumn('admin::list-admin-login', {}, pagination.queryParams, 'login.created', 'Created') }} @@ -126,13 +138,11 @@ {{ login.osVersion }} {{ login.clientType }} {{ login.clientName }} - - {% if login.isCrawler.value == 'yes' %} - Yes - {% else %} - No - {% endif %} - + {{ login.deviceBrand }} + {{ login.deviceModel }} + {{ login.osPlatform }} + {{ login.clientEngine }} + {{ login.clientVersion }} {{ login.getCreated()|date('Y-m-d H:i:s') }} {% endfor %} diff --git a/src/Core/src/Admin/src/Entity/Admin.php b/src/Core/src/Admin/src/Entity/Admin.php index d24326a..fde0af4 100644 --- a/src/Core/src/Admin/src/Entity/Admin.php +++ b/src/Core/src/Admin/src/Entity/Admin.php @@ -32,9 +32,9 @@ class Admin extends AbstractEntity implements UserEntityInterface use TimestampsTrait; use UuidIdentifierTrait; - /** @var non-empty-string|null $identity */ + /** @var non-empty-string $identity */ #[ORM\Column(name: 'identity', type: 'string', length: 191, unique: true)] - protected ?string $identity = null; + protected string $identity; #[ORM\Column(name: 'firstName', type: 'string', length: 191, nullable: true)] protected ?string $firstName = null; @@ -43,7 +43,7 @@ class Admin extends AbstractEntity implements UserEntityInterface protected ?string $lastName = null; #[ORM\Column(name: 'password', type: 'string', length: 191)] - protected ?string $password = null; + protected string $password; #[ORM\Column( type: 'admin_status_enum', @@ -71,16 +71,11 @@ public function __construct() $this->settings = new ArrayCollection(); } - public function getIdentity(): ?string + public function getIdentity(): string { return $this->identity; } - public function hasIdentity(): bool - { - return $this->identity !== null; - } - /** * @param non-empty-string $identity */ @@ -91,6 +86,11 @@ public function setIdentity(string $identity): self return $this; } + public function hasIdentity(): bool + { + return ! empty($this->identity); + } + public function getFirstName(): ?string { return $this->firstName; @@ -115,7 +115,7 @@ public function setLastName(string $lastName): self return $this; } - public function getPassword(): ?string + public function getPassword(): string { return $this->password; } @@ -213,9 +213,12 @@ public function isActive(): bool return $this->status === AdminStatusEnum::Active; } + /** + * @return non-empty-string + */ public function getIdentifier(): string { - return (string) $this->identity; + return $this->identity; } /** diff --git a/src/Core/src/Admin/src/Entity/AdminLogin.php b/src/Core/src/Admin/src/Entity/AdminLogin.php index d530479..1ced9af 100644 --- a/src/Core/src/Admin/src/Entity/AdminLogin.php +++ b/src/Core/src/Admin/src/Entity/AdminLogin.php @@ -39,6 +39,12 @@ class AdminLogin extends AbstractEntity #[ORM\Column(name: 'deviceType', type: 'string', length: 191, nullable: true)] protected ?string $deviceType = null; + #[ORM\Column(name: 'deviceBrand', type: 'string', length: 191, nullable: true)] + protected ?string $deviceBrand = null; + + #[ORM\Column(name: 'deviceModel', type: 'string', length: 40, nullable: true)] + protected ?string $deviceModel = null; + #[ORM\Column(type: 'yes_no_enum', nullable: true, enumType: YesNoEnum::class)] protected YesNoEnum $isMobile = YesNoEnum::No; @@ -48,14 +54,20 @@ class AdminLogin extends AbstractEntity #[ORM\Column(name: 'osVersion', type: 'string', length: 191, nullable: true)] protected ?string $osVersion = null; + #[ORM\Column(name: 'osPlatform', type: 'string', length: 191, nullable: true)] + protected ?string $osPlatform = null; + #[ORM\Column(name: 'clientType', type: 'string', length: 191, nullable: true)] protected ?string $clientType = null; #[ORM\Column(name: 'clientName', type: 'string', length: 191, nullable: true)] protected ?string $clientName = null; - #[ORM\Column(type: 'yes_no_enum', nullable: true, enumType: YesNoEnum::class)] - protected YesNoEnum $isCrawler = YesNoEnum::No; + #[ORM\Column(name: 'clientEngine', type: 'string', length: 191, nullable: true)] + protected ?string $clientEngine = null; + + #[ORM\Column(name: 'clientVersion', type: 'string', length: 191, nullable: true)] + protected ?string $clientVersion = null; #[ORM\Column(type: 'success_failure_enum', nullable: true, enumType: SuccessFailureEnum::class)] protected SuccessFailureEnum $loginStatus = SuccessFailureEnum::Fail; @@ -132,6 +144,30 @@ public function setDeviceType(?string $deviceType): self return $this; } + public function getDeviceBrand(): ?string + { + return $this->deviceBrand; + } + + public function setDeviceBrand(?string $deviceBrand): self + { + $this->deviceBrand = $deviceBrand; + + return $this; + } + + public function getDeviceModel(): ?string + { + return $this->deviceModel; + } + + public function setDeviceModel(?string $deviceModel): self + { + $this->deviceModel = $deviceModel; + + return $this; + } + public function getIsMobile(): ?YesNoEnum { return $this->isMobile; @@ -168,6 +204,18 @@ public function setOsVersion(?string $osVersion): self return $this; } + public function getOsPlatform(): ?string + { + return $this->osPlatform; + } + + public function setOsPlatform(?string $osPlatform): self + { + $this->osPlatform = $osPlatform; + + return $this; + } + public function getClientType(): ?string { return $this->clientType; @@ -192,14 +240,26 @@ public function setClientName(?string $clientName): self return $this; } - public function getIsCrawler(): ?YesNoEnum + public function getClientEngine(): ?string + { + return $this->clientEngine; + } + + public function setClientEngine(?string $clientEngine): self + { + $this->clientEngine = $clientEngine; + + return $this; + } + + public function getClientVersion(): ?string { - return $this->isCrawler; + return $this->clientVersion; } - public function setIsCrawler(YesNoEnum $isCrawler): self + public function setClientVersion(?string $clientVersion): self { - $this->isCrawler = $isCrawler; + $this->clientVersion = $clientVersion; return $this; } @@ -225,12 +285,16 @@ public function setLoginStatus(SuccessFailureEnum $loginStatus): self * continent: string|null, * organization: string|null, * deviceType: string|null, - * isMobile: 'no'|'yes', + * deviceBrand: string|null, + * deviceModel: string|null, + * isMobile: string, * osName: string|null, * osVersion: string|null, + * osPlatform: string|null, * clientType: string|null, * clientName: string|null, - * isCrawler: 'no'|'yes', + * clientEngine: string|null, + * clientVersion: string|null, * loginStatus: string, * created: DateTimeImmutable|null, * updated: DateTimeImmutable|null, @@ -239,22 +303,26 @@ public function setLoginStatus(SuccessFailureEnum $loginStatus): self public function getArrayCopy(): array { return [ - 'id' => $this->id->toString(), - 'identity' => $this->identity, - 'adminIp' => $this->adminIp, - 'country' => $this->country, - 'continent' => $this->continent, - 'organization' => $this->organization, - 'deviceType' => $this->deviceType, - 'isMobile' => $this->isMobile->value, - 'osName' => $this->osName, - 'osVersion' => $this->osVersion, - 'clientType' => $this->clientType, - 'clientName' => $this->clientName, - 'isCrawler' => $this->isCrawler->value, - 'loginStatus' => $this->loginStatus->value, - 'created' => $this->created, - 'updated' => $this->updated, + 'id' => $this->id->toString(), + 'identity' => $this->identity, + 'adminIp' => $this->adminIp, + 'country' => $this->country, + 'continent' => $this->continent, + 'organization' => $this->organization, + 'deviceType' => $this->deviceType, + 'deviceBrand' => $this->deviceBrand, + 'deviceModel' => $this->deviceModel, + 'isMobile' => $this->isMobile->value, + 'osName' => $this->osName, + 'osVersion' => $this->osVersion, + 'osPlatform' => $this->osPlatform, + 'clientType' => $this->clientType, + 'clientName' => $this->clientName, + 'clientEngine' => $this->clientEngine, + 'clientVersion' => $this->clientVersion, + 'loginStatus' => $this->loginStatus->value, + 'created' => $this->created, + 'updated' => $this->updated, ]; } } diff --git a/src/Core/src/App/src/Entity/NumericIdentifierTrait.php b/src/Core/src/App/src/Entity/NumericIdentifierTrait.php index 54fb41a..6383bbc 100644 --- a/src/Core/src/App/src/Entity/NumericIdentifierTrait.php +++ b/src/Core/src/App/src/Entity/NumericIdentifierTrait.php @@ -11,9 +11,9 @@ trait NumericIdentifierTrait #[ORM\Id] #[ORM\Column(name: 'id', type: 'integer', options: ['unsigned' => true])] #[ORM\GeneratedValue(strategy: 'AUTO')] - protected ?int $id; + protected int $id; - public function getId(): ?int + public function getId(): int { return $this->id; } diff --git a/src/Core/src/App/src/Service/IpService.php b/src/Core/src/App/src/Service/IpService.php index efe224c..bb766c7 100644 --- a/src/Core/src/App/src/Service/IpService.php +++ b/src/Core/src/App/src/Service/IpService.php @@ -19,7 +19,7 @@ class IpService * @phpstan-param array{ * HTTP_X_FORWARDED_FOR?: string, * HTTP_CLIENT_IP?: string, - * REMOTE_ADDR?: string, + * REMOTE_ADDR: string, * } $server */ public static function getUserIp(array $server): mixed @@ -28,17 +28,17 @@ public static function getUserIp(array $server): mixed // check if HTTP_X_FORWARDED_FOR is public network IP if (isset($server['HTTP_X_FORWARDED_FOR']) && self::isPublicIp($server['HTTP_X_FORWARDED_FOR'])) { $realIp = $server['HTTP_X_FORWARDED_FOR']; - // check if HTTP_CLIENT_IP is public network IP + // check if HTTP_CLIENT_IP is public network IP } elseif (isset($server['HTTP_CLIENT_IP']) && self::isPublicIp($server['HTTP_CLIENT_IP'])) { $realIp = $server['HTTP_CLIENT_IP']; } else { - $realIp = $server['REMOTE_ADDR'] ?? null; + $realIp = $server['REMOTE_ADDR']; } } else { // check if HTTP_X_FORWARDED_FOR is public network IP if (getenv('HTTP_X_FORWARDED_FOR') && self::isPublicIp((string) getenv('HTTP_X_FORWARDED_FOR'))) { $realIp = getenv('HTTP_X_FORWARDED_FOR'); - // check if HTTP_CLIENT_IP is public network IP + // check if HTTP_CLIENT_IP is public network IP } elseif (getenv('HTTP_CLIENT_IP') && self::isPublicIp((string) getenv('HTTP_CLIENT_IP'))) { $realIp = getenv('HTTP_CLIENT_IP'); } else { diff --git a/src/Core/src/Security/src/Entity/OAuthAccessToken.php b/src/Core/src/Security/src/Entity/OAuthAccessToken.php index db7af22..bda2994 100644 --- a/src/Core/src/Security/src/Entity/OAuthAccessToken.php +++ b/src/Core/src/Security/src/Entity/OAuthAccessToken.php @@ -15,7 +15,7 @@ use Lcobucci\JWT\Signer\Key\InMemory; use Lcobucci\JWT\Signer\Rsa\Sha256; use Lcobucci\JWT\Token; -use League\OAuth2\Server\CryptKey; +use League\OAuth2\Server\CryptKeyInterface; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\ScopeEntityInterface; @@ -33,8 +33,9 @@ class OAuthAccessToken implements AccessTokenEntityInterface #[ORM\JoinColumn(name: 'client_id', referencedColumnName: 'id')] private ClientEntityInterface $client; - #[ORM\Column(name: 'user_id', type: 'string', length: 25, nullable: true)] - private ?string $userId = null; + /** @var non-empty-string $userId */ + #[ORM\Column(name: 'user_id', type: 'string', length: 25)] + private string $userId; /** @var non-empty-string $token */ #[ORM\Column(name: 'token', type: 'string', length: 100)] @@ -53,7 +54,7 @@ class OAuthAccessToken implements AccessTokenEntityInterface #[ORM\Column(name: 'expires_at', type: 'datetime_immutable')] private DateTimeImmutable $expiresAt; - private ?CryptKey $privateKey = null; + private ?CryptKeyInterface $privateKey = null; private ?Configuration $jwtConfiguration = null; @@ -62,11 +63,9 @@ public function __construct() $this->scopes = new ArrayCollection(); } - public function setClient(ClientEntityInterface $client): self + public function setClient(ClientEntityInterface $client): void { $this->client = $client; - - return $this; } public function getClient(): ClientEntityInterface @@ -85,11 +84,9 @@ public function getToken(): string /** * @param non-empty-string $token */ - public function setToken(string $token): self + public function setToken(string $token): void { $this->token = $token; - - return $this; } public function setIsRevoked(bool $isRevoked): self @@ -122,37 +119,33 @@ public function getIdentifier(): string /** * @param mixed $identifier */ - public function setIdentifier($identifier): self + public function setIdentifier($identifier): void { - return $this->setToken($identifier); + $this->setToken($identifier); } /** - * @param string|int|null $identifier + * @param non-empty-string|int $identifier */ - public function setUserIdentifier($identifier): self + public function setUserIdentifier($identifier): void { if (is_int($identifier)) { $identifier = (string) $identifier; } $this->userId = $identifier; - - return $this; } - public function getUserIdentifier(): ?string + public function getUserIdentifier(): string { return $this->userId; } - public function addScope(ScopeEntityInterface $scope): self + public function addScope(ScopeEntityInterface $scope): void { if (! $this->scopes->contains($scope)) { $this->scopes->add($scope); } - - return $this; } public function removeScope(OAuthScope $scope): self @@ -178,18 +171,14 @@ public function getExpiryDateTime(): DateTimeImmutable return $this->expiresAt; } - public function setExpiryDateTime(DateTimeImmutable $dateTime): self + public function setExpiryDateTime(DateTimeImmutable $dateTime): void { $this->expiresAt = $dateTime; - - return $this; } - public function setPrivateKey(CryptKey $privateKey): self + public function setPrivateKey(CryptKeyInterface $privateKey): void { $this->privateKey = $privateKey; - - return $this; } public function initJwtConfiguration(): self @@ -238,4 +227,9 @@ public function __toString(): string { return $this->convertToJWT()->toString(); } + + public function toString(): string + { + return $this->convertToJWT()->toString(); + } } diff --git a/src/Core/src/Security/src/Entity/OAuthAuthCode.php b/src/Core/src/Security/src/Entity/OAuthAuthCode.php index 2b184ea..b7bfa99 100644 --- a/src/Core/src/Security/src/Entity/OAuthAuthCode.php +++ b/src/Core/src/Security/src/Entity/OAuthAuthCode.php @@ -48,11 +48,9 @@ public function __construct() $this->scopes = new ArrayCollection(); } - public function setClient(ClientEntityInterface $client): self + public function setClient(ClientEntityInterface $client): void { $this->client = $client; - - return $this; } public function getClient(): ClientEntityInterface @@ -68,19 +66,17 @@ public function getIdentifier(): string /** * @param mixed $identifier */ - public function setIdentifier($identifier): self + public function setIdentifier($identifier): void { $this->setId($identifier); - - return $this; } /** * @param string|int|null $identifier */ - public function setUserIdentifier($identifier): self + public function setUserIdentifier($identifier): void { - return $this; + $this->setIdentifier($identifier); } public function getUserIdentifier(): ?string @@ -114,13 +110,11 @@ public function revoke(): self return $this; } - public function addScope(ScopeEntityInterface $scope): self + public function addScope(ScopeEntityInterface $scope): void { if (! $this->scopes->contains($scope)) { $this->scopes->add($scope); } - - return $this; } public function removeScope(ScopeEntityInterface $scope): self @@ -156,8 +150,8 @@ public function getExpiryDateTime(): DateTimeImmutable return $this->getExpiresDatetime(); } - public function setExpiryDateTime(DateTimeImmutable $dateTime): self + public function setExpiryDateTime(DateTimeImmutable $dateTime): void { - return $this->setExpiresDatetime($dateTime); + $this->setExpiresDatetime($dateTime); } } diff --git a/src/Core/src/Security/src/Entity/OAuthClient.php b/src/Core/src/Security/src/Entity/OAuthClient.php index a52ace1..434b601 100644 --- a/src/Core/src/Security/src/Entity/OAuthClient.php +++ b/src/Core/src/Security/src/Entity/OAuthClient.php @@ -16,13 +16,14 @@ class OAuthClient implements ClientEntityInterface { use NumericIdentifierTrait; - public const NAME_ADMIN = 'admin'; - public const NAME_FRONTEND = 'frontend'; + public const string NAME_ADMIN = 'admin'; + public const string NAME_FRONTEND = 'frontend'; #[ORM\ManyToOne(targetEntity: User::class)] #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: true)] private ?User $user = null; + /** @var non-empty-string */ #[ORM\Column(name: 'name', type: 'string', length: 40)] private string $name; @@ -55,11 +56,15 @@ public function getIdentity(): string return $this->getName(); } + /** + * @return non-empty-string + */ public function getIdentifier(): string { return $this->getName(); } + /** @param non-empty-string $name */ public function setName(string $name): self { $this->name = $name; @@ -67,6 +72,9 @@ public function setName(string $name): self return $this; } + /** + * @return non-empty-string + */ public function getName(): string { return $this->name; @@ -96,7 +104,7 @@ public function getRedirect(): string return $this->redirect; } - public function getRedirectUri(): ?string + public function getRedirectUri(): string { return $this->getRedirect(); } diff --git a/src/Core/src/Security/src/Entity/OAuthRefreshToken.php b/src/Core/src/Security/src/Entity/OAuthRefreshToken.php index ae6dc16..e65172a 100644 --- a/src/Core/src/Security/src/Entity/OAuthRefreshToken.php +++ b/src/Core/src/Security/src/Entity/OAuthRefreshToken.php @@ -32,16 +32,13 @@ public function getIdentifier(): string return (string) $this->getId(); } - public function setIdentifier(mixed $identifier): self + public function setIdentifier(mixed $identifier): void { - return $this; } - public function setAccessToken(AccessTokenEntityInterface $accessToken): self + public function setAccessToken(AccessTokenEntityInterface $accessToken): void { $this->accessToken = $accessToken; - - return $this; } public function getAccessToken(): OAuthAccessToken|AccessTokenEntityInterface @@ -73,10 +70,8 @@ public function getExpiryDateTime(): DateTimeImmutable return $this->expiresAt; } - public function setExpiryDateTime(DateTimeImmutable $dateTime): self + public function setExpiryDateTime(DateTimeImmutable $dateTime): void { $this->expiresAt = $dateTime; - - return $this; } } diff --git a/src/Core/src/Security/src/Entity/OAuthScope.php b/src/Core/src/Security/src/Entity/OAuthScope.php index 9afe161..b0f5d68 100644 --- a/src/Core/src/Security/src/Entity/OAuthScope.php +++ b/src/Core/src/Security/src/Entity/OAuthScope.php @@ -22,8 +22,9 @@ class OAuthScope implements ScopeEntityInterface use NumericIdentifierTrait; use ScopeTrait; + /** @var non-empty-string */ #[ORM\Column(name: 'scope', type: 'string', length: 191)] - private string $scope = ''; + private string $scope; /** @var Collection */ #[ORM\ManyToMany(targetEntity: OAuthAccessToken::class, mappedBy: 'scopes')] @@ -39,11 +40,13 @@ public function __construct() $this->authCodes = new ArrayCollection(); } + /** @return non-empty-string */ public function getIdentifier(): string { return $this->getScope(); } + /** @param non-empty-string $scope */ public function setScope(string $scope): self { $this->scope = $scope; @@ -51,6 +54,7 @@ public function setScope(string $scope): self return $this; } + /** @return non-empty-string */ public function getScope(): string { return $this->scope; diff --git a/src/Core/src/Security/src/Repository/OAuthAccessTokenRepository.php b/src/Core/src/Security/src/Repository/OAuthAccessTokenRepository.php index 3cd6b17..1f39aba 100644 --- a/src/Core/src/Security/src/Repository/OAuthAccessTokenRepository.php +++ b/src/Core/src/Security/src/Repository/OAuthAccessTokenRepository.php @@ -42,7 +42,8 @@ public function getNewToken( array $scopes, $userIdentifier = null ): OAuthAccessToken { - $accessToken = (new OAuthAccessToken())->setClient($clientEntity); + $accessToken = new OAuthAccessToken(); + $accessToken->setClient($clientEntity); foreach ($scopes as $scope) { $accessToken->addScope($scope); } @@ -71,10 +72,7 @@ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEnt $this->getEntityManager()->flush(); } - /** - * @param string $tokenId - */ - public function revokeAccessToken($tokenId): void + public function revokeAccessToken(string $tokenId): void { $accessTokenEntity = $this->findOneBy(['token' => $tokenId]); if ($accessTokenEntity instanceof OAuthAccessToken) { @@ -83,10 +81,7 @@ public function revokeAccessToken($tokenId): void } } - /** - * @param string $tokenId - */ - public function isAccessTokenRevoked($tokenId): bool + public function isAccessTokenRevoked(string $tokenId): bool { $accessTokenEntity = $this->findOneBy(['token' => $tokenId]); if ($accessTokenEntity instanceof OAuthAccessToken) { diff --git a/src/Core/src/Security/src/Repository/OAuthAuthCodeRepository.php b/src/Core/src/Security/src/Repository/OAuthAuthCodeRepository.php index a606ee0..ea42fb7 100644 --- a/src/Core/src/Security/src/Repository/OAuthAuthCodeRepository.php +++ b/src/Core/src/Security/src/Repository/OAuthAuthCodeRepository.php @@ -24,10 +24,7 @@ public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity): voi $this->getEntityManager()->flush(); } - /** - * @param string $codeId - */ - public function revokeAuthCode($codeId): void + public function revokeAuthCode(string $codeId): void { $authCodeEntity = $this->find($codeId); if ($authCodeEntity instanceof OAuthAuthCode) { @@ -36,10 +33,7 @@ public function revokeAuthCode($codeId): void } } - /** - * @param string $codeId - */ - public function isAuthCodeRevoked($codeId): bool + public function isAuthCodeRevoked(string $codeId): bool { $authCodeEntity = $this->find($codeId); if ($authCodeEntity instanceof OAuthAuthCode) { diff --git a/src/Core/src/Security/src/Repository/OAuthClientRepository.php b/src/Core/src/Security/src/Repository/OAuthClientRepository.php index 53dd362..590ff7d 100644 --- a/src/Core/src/Security/src/Repository/OAuthClientRepository.php +++ b/src/Core/src/Security/src/Repository/OAuthClientRepository.php @@ -16,22 +16,19 @@ #[Entity(name: OAuthClient::class)] class OAuthClientRepository extends AbstractRepository implements ClientRepositoryInterface { - private const GRANT_TYPE_CLIENT_CREDENTIALS = 'client_credentials'; - private const GRANT_TYPE_AUTHORIZATION_CODE = 'authorization_code'; - private const GRANT_TYPE_REFRESH_TOKEN = 'refresh_token'; - private const GRANT_TYPE_PASSWORD = 'password'; + private const string GRANT_TYPE_CLIENT_CREDENTIALS = 'client_credentials'; + private const string GRANT_TYPE_AUTHORIZATION_CODE = 'authorization_code'; + private const string GRANT_TYPE_REFRESH_TOKEN = 'refresh_token'; + private const string GRANT_TYPE_PASSWORD = 'password'; - private const GRANT_TYPES = [ + private const array GRANT_TYPES = [ self::GRANT_TYPE_CLIENT_CREDENTIALS, self::GRANT_TYPE_AUTHORIZATION_CODE, self::GRANT_TYPE_REFRESH_TOKEN, self::GRANT_TYPE_PASSWORD, ]; - /** - * @param string $clientIdentifier - */ - public function getClientEntity($clientIdentifier): ?ClientEntityInterface + public function getClientEntity(string $clientIdentifier): ?ClientEntityInterface { $client = $this->findOneBy(['name' => $clientIdentifier]); if ($client instanceof OAuthClient) { @@ -41,12 +38,7 @@ public function getClientEntity($clientIdentifier): ?ClientEntityInterface return null; } - /** - * @param string $clientIdentifier - * @param null|string $clientSecret - * @param null|string $grantType - */ - public function validateClient($clientIdentifier, $clientSecret, $grantType): bool + public function validateClient(string $clientIdentifier, ?string $clientSecret, ?string $grantType): bool { $client = $this->getClientEntity($clientIdentifier); if (! $client instanceof OAuthClient) { diff --git a/src/Core/src/Security/src/Repository/OAuthRefreshTokenRepository.php b/src/Core/src/Security/src/Repository/OAuthRefreshTokenRepository.php index 07b1414..d0afc07 100644 --- a/src/Core/src/Security/src/Repository/OAuthRefreshTokenRepository.php +++ b/src/Core/src/Security/src/Repository/OAuthRefreshTokenRepository.php @@ -24,10 +24,7 @@ public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshToken $this->getEntityManager()->flush(); } - /** - * @param string $tokenId - */ - public function revokeRefreshToken($tokenId): void + public function revokeRefreshToken(string $tokenId): void { $refreshTokenEntity = $this->find($tokenId); if ($refreshTokenEntity instanceof OAuthRefreshToken) { @@ -36,10 +33,7 @@ public function revokeRefreshToken($tokenId): void } } - /** - * @param string $tokenId - */ - public function isRefreshTokenRevoked($tokenId): bool + public function isRefreshTokenRevoked(string $tokenId): bool { $refreshTokenEntity = $this->find($tokenId); if ($refreshTokenEntity instanceof OAuthRefreshToken) { diff --git a/src/Core/src/Security/src/Repository/OAuthScopeRepository.php b/src/Core/src/Security/src/Repository/OAuthScopeRepository.php index a78c4ae..7e096ae 100644 --- a/src/Core/src/Security/src/Repository/OAuthScopeRepository.php +++ b/src/Core/src/Security/src/Repository/OAuthScopeRepository.php @@ -27,16 +27,12 @@ public function getScopeEntityByIdentifier($identifier): ?ScopeEntityInterface return null; } - /** - * @param string $grantType - * @param null|string $userIdentifier - * @return ScopeEntityInterface[] - */ public function finalizeScopes( array $scopes, - $grantType, + string $grantType, ClientEntityInterface $clientEntity, - $userIdentifier = null + string|null $userIdentifier = null, + ?string $authCodeId = null ): array { return $scopes; } diff --git a/src/Core/src/User/src/Entity/User.php b/src/Core/src/User/src/Entity/User.php index 604748b..d6d9886 100644 --- a/src/Core/src/User/src/Entity/User.php +++ b/src/Core/src/User/src/Entity/User.php @@ -54,12 +54,12 @@ class User extends AbstractEntity implements UserEntityInterface #[ORM\InverseJoinColumn(name: 'role_id', referencedColumnName: 'id')] protected Collection $roles; - /** @var non-empty-string|null $identity */ + /** @var non-empty-string $identity */ #[ORM\Column(name: 'identity', type: 'string', length: 191, unique: true)] - protected ?string $identity = null; + protected string $identity; #[ORM\Column(name: 'password', type: 'string', length: 191)] - protected ?string $password = null; + protected string $password; #[ORM\Column( type: 'user_status_enum', @@ -200,16 +200,11 @@ public function setRoles(array $roles): self return $this; } - public function getIdentity(): ?string + public function getIdentity(): string { return $this->identity; } - public function hasIdentity(): bool - { - return $this->identity !== null; - } - /** * @param non-empty-string $identity */ @@ -220,7 +215,12 @@ public function setIdentity(string $identity): self return $this; } - public function getPassword(): ?string + public function hasIdentity(): bool + { + return ! empty($this->identity); + } + + public function getPassword(): string { return $this->password; } @@ -261,7 +261,7 @@ public function setHash(string $hash): self public function getIdentifier(): string { - return (string) $this->identity; + return $this->identity; } public function activate(): self diff --git a/src/Core/src/User/src/Repository/UserRepository.php b/src/Core/src/User/src/Repository/UserRepository.php index f82e675..2bef654 100644 --- a/src/Core/src/User/src/Repository/UserRepository.php +++ b/src/Core/src/User/src/Repository/UserRepository.php @@ -87,16 +87,13 @@ public function getUsers(array $params = [], array $filters = []): QueryBuilder return $queryBuilder; } - /** - * @param string $username - * @param string $password - * @param string $grantType + /** @param non-empty-string $username * @throws OAuthServerException */ public function getUserEntityByUserCredentials( - $username, - $password, - $grantType, + string $username, + string $password, + string $grantType, ClientEntityInterface $clientEntity ): ?UserEntity { $qb = $this->getEntityManager()->createQueryBuilder(); diff --git a/test/Unit/Admin/Entity/AdminLoginTest.php b/test/Unit/Admin/Entity/AdminLoginTest.php index 3dfce8b..5af37bc 100644 --- a/test/Unit/Admin/Entity/AdminLoginTest.php +++ b/test/Unit/Admin/Entity/AdminLoginTest.php @@ -93,11 +93,30 @@ public function testAccessors(): void $this->assertSame(AdminLogin::class, $adminLogin::class); $this->assertSame('test', $adminLogin->getClientName()); - $this->assertSame(YesNoEnum::No, $adminLogin->getIsCrawler()); - $adminLogin = $adminLogin->setIsCrawler(YesNoEnum::Yes); + $this->assertNull($adminLogin->getDeviceBrand()); + $adminLogin = $adminLogin->setDeviceBrand('test'); $this->assertSame(AdminLogin::class, $adminLogin::class); - $this->assertNotNull($adminLogin->getIsCrawler()); - $this->assertSame('yes', $adminLogin->getIsCrawler()->value); + $this->assertSame('test', $adminLogin->getDeviceBrand()); + + $this->assertNull($adminLogin->getDeviceModel()); + $adminLogin = $adminLogin->setDeviceModel('test'); + $this->assertSame(AdminLogin::class, $adminLogin::class); + $this->assertSame('test', $adminLogin->getDeviceModel()); + + $this->assertNull($adminLogin->getOsPlatform()); + $adminLogin = $adminLogin->setOsPlatform('test'); + $this->assertSame(AdminLogin::class, $adminLogin::class); + $this->assertSame('test', $adminLogin->getOsPlatform()); + + $this->assertNull($adminLogin->getClientEngine()); + $adminLogin = $adminLogin->setClientEngine('test'); + $this->assertSame(AdminLogin::class, $adminLogin::class); + $this->assertSame('test', $adminLogin->getClientEngine()); + + $this->assertNull($adminLogin->getClientVersion()); + $adminLogin = $adminLogin->setClientVersion('test'); + $this->assertSame(AdminLogin::class, $adminLogin::class); + $this->assertSame('test', $adminLogin->getClientVersion()); $this->assertSame(SuccessFailureEnum::Fail, $adminLogin->getLoginStatus()); $adminLogin = $adminLogin->setLoginStatus(SuccessFailureEnum::Success); diff --git a/test/Unit/App/Service/IpServiceTest.php b/test/Unit/App/Service/IpServiceTest.php index 2158f0f..8e1d083 100644 --- a/test/Unit/App/Service/IpServiceTest.php +++ b/test/Unit/App/Service/IpServiceTest.php @@ -23,10 +23,12 @@ public function testWillGetUserIpFromServerParams(): void { $this->assertSame($this->ipAddress, IpService::getUserIp([ 'HTTP_X_FORWARDED_FOR' => $this->ipAddress, + 'REMOTE_ADDR' => '', ])); $this->assertSame($this->ipAddress, IpService::getUserIp([ 'HTTP_CLIENT_IP' => $this->ipAddress, + 'REMOTE_ADDR' => '', ])); $this->assertSame($this->ipAddress, IpService::getUserIp([ @@ -36,16 +38,19 @@ public function testWillGetUserIpFromServerParams(): void public function testWillGetUserIpFromEnv(): void { + /** @var array{HTTP_X_FORWARDED_FOR?: string, HTTP_CLIENT_IP?: string, REMOTE_ADDR: string} $emptyServer */ + $emptyServer = []; + putenv(sprintf('HTTP_X_FORWARDED_FOR=%s', $this->ipAddress)); - $this->assertSame($this->ipAddress, IpService::getUserIp([])); + $this->assertSame($this->ipAddress, IpService::getUserIp($emptyServer)); putenv('HTTP_X_FORWARDED_FOR'); putenv(sprintf('HTTP_CLIENT_IP=%s', $this->ipAddress)); - $this->assertSame($this->ipAddress, IpService::getUserIp([])); + $this->assertSame($this->ipAddress, IpService::getUserIp($emptyServer)); putenv('HTTP_CLIENT_IP'); putenv(sprintf('REMOTE_ADDR=%s', $this->ipAddress)); - $this->assertSame($this->ipAddress, IpService::getUserIp([])); + $this->assertSame($this->ipAddress, IpService::getUserIp($emptyServer)); putenv('REMOTE_ADDR'); } @@ -56,7 +61,7 @@ public function testWillDetectPublicIp(): void $this->assertFalse(IpService::isPublicIp("::1")); $this->assertFalse(IpService::isPublicIp("fd12:3456:789a:1::1")); - $this->assertTrue(IpService::isPublicIp("8.8.8.8")); // google - $this->assertTrue(IpService::isPublicIp("2607:f8b0:4003:c00::6a")); //google + $this->assertTrue(IpService::isPublicIp("8.8.8.8")); + $this->assertTrue(IpService::isPublicIp("2607:f8b0:4003:c00::6a")); } }