mirror of
				https://github.com/elyby/accounts.git
				synced 2025-05-31 14:11:46 +05:30 
			
		
		
		
	Upgrade project to PHP 8.3, add PHPStan, upgrade almost every dependency (#36)
* start updating to PHP 8.3 * taking off! Co-authored-by: ErickSkrauch <erickskrauch@yandex.ru> Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * dropped this Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * migrate to symfonymailer Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * this is so stupid 😭 Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * ah, free, at last. Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * oh, Gabriel. Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * now dawns thy reckoning. Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * and thy gore shall GLISTEN before the temples of man. Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * creature of steel. Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * my gratitude upon thee for my freedom. Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * but the crimes thy kind has committed against humanity Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * Upgrade PHP-CS-Fixer and do fix the codebase * First review round (maybe I have broken something) * are NOT forgotten. Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * Enable parallel PHP-CS-Fixer runner * PHPStan level 1 * PHPStan level 2 * PHPStan level 3 * PHPStan level 4 * PHPStan level 5 * Levels 6 and 7 takes too much effort. Generate a baseline and fix them eventually * Resolve TODO's related to the php-mock * Drastically reduce baseline size with the Rector * More code modernization with help of the Rector * Update GitLab CI --------- Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> Co-authored-by: ErickSkrauch <erickskrauch@yandex.ru>
This commit is contained in:
		@@ -18,13 +18,13 @@ use yii\web\User as YiiUserComponent;
 | 
			
		||||
 */
 | 
			
		||||
class Component extends YiiUserComponent {
 | 
			
		||||
 | 
			
		||||
    public const KEEP_MINECRAFT_SESSIONS = 1;
 | 
			
		||||
    public const KEEP_SITE_SESSIONS = 2;
 | 
			
		||||
    public const KEEP_CURRENT_SESSION = 4;
 | 
			
		||||
    public const int KEEP_MINECRAFT_SESSIONS = 1;
 | 
			
		||||
    public const int KEEP_SITE_SESSIONS = 2;
 | 
			
		||||
    public const int KEEP_CURRENT_SESSION = 4;
 | 
			
		||||
 | 
			
		||||
    public $enableSession = false;
 | 
			
		||||
 | 
			
		||||
    public $loginUrl = null;
 | 
			
		||||
    public $loginUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * We don't use the standard web authorization mechanism via cookies.
 | 
			
		||||
@@ -57,12 +57,13 @@ class Component extends YiiUserComponent {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $sessionId = $identity->getToken()->getClaim('jti', false);
 | 
			
		||||
        if ($sessionId === false) {
 | 
			
		||||
        /** @var int|null $sessionId */
 | 
			
		||||
        $sessionId = $identity->getToken()->claims()->get('jti');
 | 
			
		||||
        if ($sessionId === null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return AccountSession::findOne($sessionId);
 | 
			
		||||
        return AccountSession::findOne(['id' => (int)$sessionId]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function terminateSessions(Account $account, int $mode = 0): void {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,57 +5,54 @@ namespace api\components\User;
 | 
			
		||||
 | 
			
		||||
use api\components\Tokens\TokenReader;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use Carbon\FactoryImmutable;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\OauthClient;
 | 
			
		||||
use common\models\OauthSession;
 | 
			
		||||
use DateTimeImmutable;
 | 
			
		||||
use Exception;
 | 
			
		||||
use Lcobucci\JWT\Token;
 | 
			
		||||
use Lcobucci\JWT\ValidationData;
 | 
			
		||||
use Lcobucci\JWT\UnencryptedToken;
 | 
			
		||||
use Lcobucci\JWT\Validation\Constraint\LooseValidAt;
 | 
			
		||||
use Lcobucci\JWT\Validation\Validator;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\base\NotSupportedException;
 | 
			
		||||
use yii\web\UnauthorizedHttpException;
 | 
			
		||||
 | 
			
		||||
class JwtIdentity implements IdentityInterface {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Token
 | 
			
		||||
     */
 | 
			
		||||
    private $token;
 | 
			
		||||
    private ?TokenReader $reader = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var TokenReader|null
 | 
			
		||||
     */
 | 
			
		||||
    private $reader;
 | 
			
		||||
 | 
			
		||||
    private function __construct(Token $token) {
 | 
			
		||||
        $this->token = $token;
 | 
			
		||||
    private function __construct(
 | 
			
		||||
        private readonly UnencryptedToken $token,
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function findIdentityByAccessToken($rawToken, $type = null): IdentityInterface {
 | 
			
		||||
    public static function findIdentityByAccessToken($token, $type = null): IdentityInterface {
 | 
			
		||||
        try {
 | 
			
		||||
            $token = Yii::$app->tokens->parse($rawToken);
 | 
			
		||||
            $parsedToken = Yii::$app->tokens->parse($token);
 | 
			
		||||
        } catch (Exception $e) {
 | 
			
		||||
            Yii::error($e);
 | 
			
		||||
            throw new UnauthorizedHttpException('Incorrect token');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!Yii::$app->tokens->verify($token)) {
 | 
			
		||||
        if (!Yii::$app->tokens->verify($parsedToken)) {
 | 
			
		||||
            throw new UnauthorizedHttpException('Incorrect token');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $now = Carbon::now();
 | 
			
		||||
        if ($token->isExpired($now)) {
 | 
			
		||||
        if ($parsedToken->isExpired($now)) {
 | 
			
		||||
            throw new UnauthorizedHttpException('Token expired');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!$token->validate(new ValidationData($now->getTimestamp()))) {
 | 
			
		||||
        if (!(new Validator())->validate($parsedToken, new LooseValidAt(FactoryImmutable::getDefaultInstance()))) {
 | 
			
		||||
            throw new UnauthorizedHttpException('Incorrect token');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $tokenReader = new TokenReader($token);
 | 
			
		||||
        $tokenReader = new TokenReader($parsedToken);
 | 
			
		||||
        $accountId = $tokenReader->getAccountId();
 | 
			
		||||
        if ($accountId !== null) {
 | 
			
		||||
            $iat = $token->getClaim('iat');
 | 
			
		||||
            /** @var DateTimeImmutable $iat */
 | 
			
		||||
            $iat = $parsedToken->claims()->get('iat');
 | 
			
		||||
            if ($tokenReader->getMinecraftClientToken() !== null
 | 
			
		||||
             && self::isRevoked($accountId, OauthClient::UNAUTHORIZED_MINECRAFT_GAME_LAUNCHER, $iat)
 | 
			
		||||
            ) {
 | 
			
		||||
@@ -69,10 +66,10 @@ class JwtIdentity implements IdentityInterface {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new self($token);
 | 
			
		||||
        return new self($parsedToken);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getToken(): Token {
 | 
			
		||||
    public function getToken(): UnencryptedToken {
 | 
			
		||||
        return $this->token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -85,10 +82,10 @@ class JwtIdentity implements IdentityInterface {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getId(): string {
 | 
			
		||||
        return (string)$this->token;
 | 
			
		||||
        return $this->token->toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @codeCoverageIgnoreStart
 | 
			
		||||
    /** @codeCoverageIgnoreStart */
 | 
			
		||||
    public function getAuthKey() {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
@@ -97,17 +94,19 @@ class JwtIdentity implements IdentityInterface {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @throws NotSupportedException
 | 
			
		||||
     */
 | 
			
		||||
    public static function findIdentity($id) {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static function isRevoked(int $accountId, string $clientId, int $iat): bool {
 | 
			
		||||
    private static function isRevoked(int $accountId, string $clientId, DateTimeImmutable $iat): bool {
 | 
			
		||||
        $session = OauthSession::findOne(['account_id' => $accountId, 'client_id' => $clientId]);
 | 
			
		||||
        return $session !== null && $session->revoked_at !== null && $session->revoked_at > $iat;
 | 
			
		||||
        return $session !== null && $session->revoked_at !== null && $session->revoked_at > $iat->getTimestamp();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @codeCoverageIgnoreEnd
 | 
			
		||||
 | 
			
		||||
    /** @codeCoverageIgnoreEnd */
 | 
			
		||||
    private function getReader(): TokenReader {
 | 
			
		||||
        if ($this->reader === null) {
 | 
			
		||||
            $this->reader = new TokenReader($this->token);
 | 
			
		||||
 
 | 
			
		||||
@@ -10,33 +10,21 @@ use Yii;
 | 
			
		||||
use yii\base\NotSupportedException;
 | 
			
		||||
use yii\web\UnauthorizedHttpException;
 | 
			
		||||
 | 
			
		||||
class LegacyOAuth2Identity implements IdentityInterface {
 | 
			
		||||
readonly class LegacyOAuth2Identity implements IdentityInterface {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string
 | 
			
		||||
     * @param string[] $scopes
 | 
			
		||||
     */
 | 
			
		||||
    private $accessToken;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    private $sessionId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string[]
 | 
			
		||||
     */
 | 
			
		||||
    private $scopes;
 | 
			
		||||
 | 
			
		||||
    private function __construct(string $accessToken, int $sessionId, array $scopes) {
 | 
			
		||||
        $this->accessToken = $accessToken;
 | 
			
		||||
        $this->sessionId = $sessionId;
 | 
			
		||||
        $this->scopes = $scopes;
 | 
			
		||||
    private function __construct(
 | 
			
		||||
        private string $accessToken,
 | 
			
		||||
        private int $sessionId,
 | 
			
		||||
        private array $scopes,
 | 
			
		||||
    ) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     * @throws UnauthorizedHttpException
 | 
			
		||||
     * @return IdentityInterface
 | 
			
		||||
     */
 | 
			
		||||
    public static function findIdentityByAccessToken($token, $type = null): IdentityInterface {
 | 
			
		||||
        $tokenParams = self::findRecordOnLegacyStorage($token);
 | 
			
		||||
@@ -48,16 +36,11 @@ class LegacyOAuth2Identity implements IdentityInterface {
 | 
			
		||||
            throw new UnauthorizedHttpException('Token expired');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new static($token, $tokenParams['session_id'], $tokenParams['scopes']);
 | 
			
		||||
        return new self($token, $tokenParams['session_id'], $tokenParams['scopes']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getAccount(): ?Account {
 | 
			
		||||
        $session = $this->getSession();
 | 
			
		||||
        if ($session === null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $session->account;
 | 
			
		||||
        return $this->getSession()?->account;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -71,7 +54,7 @@ class LegacyOAuth2Identity implements IdentityInterface {
 | 
			
		||||
        return $this->accessToken;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @codeCoverageIgnoreStart
 | 
			
		||||
    /** @codeCoverageIgnoreStart */
 | 
			
		||||
    public function getAuthKey() {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
@@ -84,8 +67,7 @@ class LegacyOAuth2Identity implements IdentityInterface {
 | 
			
		||||
        throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @codeCoverageIgnoreEnd
 | 
			
		||||
 | 
			
		||||
    /** @codeCoverageIgnoreEnd */
 | 
			
		||||
    private static function findRecordOnLegacyStorage(string $accessToken): ?array {
 | 
			
		||||
        $record = Yii::$app->redis->get("oauth:access:tokens:{$accessToken}");
 | 
			
		||||
        if ($record === null) {
 | 
			
		||||
@@ -93,8 +75,8 @@ class LegacyOAuth2Identity implements IdentityInterface {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $data = json_decode($record, true, 512, JSON_THROW_ON_ERROR);
 | 
			
		||||
        } catch (Exception $e) {
 | 
			
		||||
            $data = json_decode((string)$record, true, 512, JSON_THROW_ON_ERROR);
 | 
			
		||||
        } catch (Exception) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user