diff --git a/src/Authentication/Authenticators/AccessTokens.php b/src/Authentication/Authenticators/AccessTokens.php index 762e21fe6..973e6197c 100644 --- a/src/Authentication/Authenticators/AccessTokens.php +++ b/src/Authentication/Authenticators/AccessTokens.php @@ -115,6 +115,8 @@ public function check(array $credentials): Result ]); } + assert($token->last_used_at instanceof Time || $token->last_used_at === null); + // Hasn't been used in a long time if ( $token->last_used_at diff --git a/src/Entities/AccessToken.php b/src/Entities/AccessToken.php index b93670bac..efdfe9f6a 100644 --- a/src/Entities/AccessToken.php +++ b/src/Entities/AccessToken.php @@ -5,12 +5,15 @@ namespace CodeIgniter\Shield\Entities; use CodeIgniter\Entity\Entity; +use CodeIgniter\I18n\Time; /** * Class AccessToken * * Represents a single Personal Access Token, used * for authenticating users for an API. + * + * @property Time|null $last_used_at */ class AccessToken extends Entity { diff --git a/src/Entities/User.php b/src/Entities/User.php index fa85958ef..3b4d53eeb 100644 --- a/src/Entities/User.php +++ b/src/Entities/User.php @@ -5,12 +5,20 @@ namespace CodeIgniter\Shield\Entities; use CodeIgniter\Database\Exceptions\DataException; +use CodeIgniter\I18n\Time; use CodeIgniter\Shield\Authentication\Authenticators\Session; use CodeIgniter\Shield\Authentication\Traits\HasAccessTokens; use CodeIgniter\Shield\Authorization\Traits\Authorizable; use CodeIgniter\Shield\Models\LoginModel; use CodeIgniter\Shield\Models\UserIdentityModel; +/** + * @property string|null $email + * @property UserIdentity[]|null $identities + * @property Time|null $last_active + * @property string|null $password + * @property string|null $password_hash + */ class User extends Entity { use Authorizable; diff --git a/src/Entities/UserIdentity.php b/src/Entities/UserIdentity.php index 5d659ba6a..541ab26dc 100644 --- a/src/Entities/UserIdentity.php +++ b/src/Entities/UserIdentity.php @@ -4,6 +4,7 @@ namespace CodeIgniter\Shield\Entities; +use CodeIgniter\I18n\Time; use CodeIgniter\Shield\Authentication\Passwords; /** @@ -19,6 +20,8 @@ * OAUTH or JWT tokens, etc. A user can have multiple of each, * though a Authenticator may want to enforce only one exists for that * user, like a password. + * + * @property Time|null $last_used_at */ class UserIdentity extends Entity { diff --git a/src/Models/UserModel.php b/src/Models/UserModel.php index 08d053050..74167b356 100644 --- a/src/Models/UserModel.php +++ b/src/Models/UserModel.php @@ -5,6 +5,7 @@ namespace CodeIgniter\Shield\Models; use CodeIgniter\Database\Exceptions\DataException; +use CodeIgniter\I18n\Time; use CodeIgniter\Model; use CodeIgniter\Shield\Authentication\Authenticators\Session; use CodeIgniter\Shield\Entities\User; @@ -325,6 +326,8 @@ protected function saveEmailIdentity(array $data): array */ public function updateActiveDate(User $user): void { + assert($user->last_active instanceof Time); + // Safe date string for database $last_active = $user->last_active->format('Y-m-d H:i:s'); diff --git a/tests/Controllers/LoginTest.php b/tests/Controllers/LoginTest.php index e56392ed1..429bfae52 100644 --- a/tests/Controllers/LoginTest.php +++ b/tests/Controllers/LoginTest.php @@ -89,6 +89,7 @@ public function testLoginActionEmailSuccess(): void ]); // Last Used date should have been set $identity = $this->user->getEmailIdentity(); + $this->assertInstanceOf(Time::class, $identity->last_used_at); $this->assertSame(Time::now()->getTimestamp(), $identity->last_used_at->getTimestamp()); // Session should have `logged_in` value with user's id @@ -151,6 +152,7 @@ public function testLoginActionUsernameSuccess(): void ]); // Last Used date should have been set $identity = $this->user->getEmailIdentity(); + $this->assertInstanceOf(Time::class, $identity->last_used_at); $this->assertSame(Time::now()->getTimestamp(), $identity->last_used_at->getTimestamp()); // Session should have `logged_in` value with user's id