From 0c110213f44ff2cea470f00728c8f2049f91cf93 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Fri, 14 Jun 2024 05:42:35 +0200 Subject: [PATCH] Remove minecraft_access_keys table and all related code --- api/components/User/Component.php | 4 - .../authserver/models/RefreshTokenForm.php | 24 ++---- .../validators/AccessTokenValidator.php | 31 -------- api/modules/session/models/JoinForm.php | 75 ++++++++----------- .../functional/authlibInjector/JoinCest.php | 4 +- .../functional/authserver/RefreshCest.php | 36 +-------- .../functional/authserver/ValidateCest.php | 24 +----- .../functional/sessionserver/JoinCest.php | 8 +- .../unit/components/User/ComponentTest.php | 5 -- common/models/Account.php | 5 -- common/models/MinecraftAccessKey.php | 63 ---------------- common/tasks/ClearAccountSessions.php | 5 -- common/tests/_support/FixtureHelper.php | 1 - .../fixtures/MinecraftAccessKeyFixture.php | 17 ----- .../fixtures/data/minecraft-access-keys.php | 31 -------- .../unit/tasks/ClearAccountSessionsTest.php | 2 - common/tests/unit/tasks/DeleteAccountTest.php | 4 - console/controllers/CleanupController.php | 14 ---- ...24554_drop_minecraft_access_keys_table.php | 24 ++++++ .../controllers/CleanupControllerTest.php | 12 --- docker/cron/cleanup | 1 - 21 files changed, 69 insertions(+), 321 deletions(-) delete mode 100644 common/models/MinecraftAccessKey.php delete mode 100644 common/tests/fixtures/MinecraftAccessKeyFixture.php delete mode 100644 common/tests/fixtures/data/minecraft-access-keys.php create mode 100644 console/migrations/m240614_024554_drop_minecraft_access_keys_table.php diff --git a/api/components/User/Component.php b/api/components/User/Component.php index 618ff78..d829c54 100644 --- a/api/components/User/Component.php +++ b/api/components/User/Component.php @@ -88,10 +88,6 @@ class Component extends YiiUserComponent { $minecraftSession->revoked_at = time(); Assert::true($minecraftSession->save()); } - - foreach ($account->minecraftAccessKeys as $minecraftAccessKey) { - $minecraftAccessKey->delete(); - } } } diff --git a/api/modules/authserver/models/RefreshTokenForm.php b/api/modules/authserver/models/RefreshTokenForm.php index 281f0bb..2172ba4 100644 --- a/api/modules/authserver/models/RefreshTokenForm.php +++ b/api/modules/authserver/models/RefreshTokenForm.php @@ -10,7 +10,6 @@ use api\modules\authserver\validators\AccessTokenValidator; use api\modules\authserver\validators\RequiredValidator; use api\rbac\Permissions as P; use common\models\Account; -use common\models\MinecraftAccessKey; use common\models\OauthClient; use common\models\OauthSession; use Webmozart\Assert\Assert; @@ -48,26 +47,13 @@ class RefreshTokenForm extends ApiForm { */ public function refresh(): AuthenticateData { $this->validate(); - $account = null; - if (mb_strlen($this->accessToken) === 36) { - /** @var MinecraftAccessKey $token */ - $token = MinecraftAccessKey::findOne([ - 'access_token' => $this->accessToken, - 'client_token' => $this->clientToken, - ]); - if ($token !== null) { - $account = $token->account; - } - } else { - $token = Yii::$app->tokens->parse($this->accessToken); - $tokenReader = new TokenReader($token); - if ($tokenReader->getMinecraftClientToken() !== $this->clientToken) { - throw new ForbiddenOperationException('Invalid token.'); - } - - $account = Account::findOne(['id' => $tokenReader->getAccountId()]); + $token = Yii::$app->tokens->parse($this->accessToken); + $tokenReader = new TokenReader($token); + if ($tokenReader->getMinecraftClientToken() !== $this->clientToken) { + throw new ForbiddenOperationException('Invalid token.'); } + $account = Account::findOne(['id' => $tokenReader->getAccountId()]); if ($account === null) { throw new ForbiddenOperationException('Invalid token.'); } diff --git a/api/modules/authserver/validators/AccessTokenValidator.php b/api/modules/authserver/validators/AccessTokenValidator.php index 355bba6..1c31413 100644 --- a/api/modules/authserver/validators/AccessTokenValidator.php +++ b/api/modules/authserver/validators/AccessTokenValidator.php @@ -7,7 +7,6 @@ use api\components\Tokens\TokenReader; use api\modules\authserver\exceptions\ForbiddenOperationException; use Carbon\Carbon; use common\models\Account; -use common\models\MinecraftAccessKey; use Exception; use Yii; use yii\validators\Validator; @@ -22,16 +21,10 @@ class AccessTokenValidator extends Validator { public bool $verifyAccount = true; /** - * @param string $value - * * @return array|null * @throws ForbiddenOperationException */ protected function validateValue($value): ?array { - if (mb_strlen($value) === 36) { - return $this->validateLegacyToken($value); - } - try { $token = Yii::$app->tokens->parse($value); } catch (Exception $e) { @@ -53,30 +46,6 @@ class AccessTokenValidator extends Validator { return null; } - /** - * @param string $value - * - * @return array|null - * @throws ForbiddenOperationException - */ - private function validateLegacyToken(string $value): ?array { - /** @var MinecraftAccessKey|null $result */ - $result = MinecraftAccessKey::findOne(['access_token' => $value]); - if ($result === null) { - throw new ForbiddenOperationException(self::INVALID_TOKEN); - } - - if ($this->verifyExpiration && $result->isExpired()) { - throw new ForbiddenOperationException(self::TOKEN_EXPIRED); - } - - if ($this->verifyAccount && !$this->validateAccount($result->account_id)) { - throw new ForbiddenOperationException(self::INVALID_TOKEN); - } - - return null; - } - private function validateAccount(int $accountId): bool { /** @var Account|null $account */ $account = Account::find()->excludeDeleted()->andWhere(['id' => $accountId])->one(); diff --git a/api/modules/session/models/JoinForm.php b/api/modules/session/models/JoinForm.php index c8472a7..06299d7 100644 --- a/api/modules/session/models/JoinForm.php +++ b/api/modules/session/models/JoinForm.php @@ -9,9 +9,9 @@ use api\modules\session\models\protocols\JoinInterface; use api\modules\session\Module as Session; use api\modules\session\validators\RequiredValidator; use api\rbac\Permissions as P; +use Closure; use common\helpers\StringHelper; use common\models\Account; -use common\models\MinecraftAccessKey; use Ramsey\Uuid\Uuid; use Webmozart\Assert\Assert; use Yii; @@ -47,13 +47,12 @@ class JoinForm extends Model { public function rules(): array { return [ [['accessToken', 'serverId'], RequiredValidator::class], - [['accessToken', 'selectedProfile'], 'validateUuid'], - [['accessToken'], 'validateAccessToken'], + [['accessToken', 'selectedProfile'], Closure::fromCallable([$this, 'validateUuid'])], + [['accessToken'], Closure::fromCallable([$this, 'validateAccessToken'])], ]; } /** - * @return bool * @throws IllegalArgumentException * @throws ForbiddenOperationException */ @@ -66,7 +65,7 @@ class JoinForm extends Model { return false; } - $account = $this->getAccount(); + $account = $this->account; $sessionModel = new SessionModel($account->username, $serverId); Assert::true($sessionModel->save()); @@ -96,7 +95,7 @@ class JoinForm extends Model { * * @throws IllegalArgumentException */ - public function validateUuid(string $attribute): void { + private function validateUuid(string $attribute): void { if ($this->hasErrors($attribute)) { return; } @@ -109,46 +108,36 @@ class JoinForm extends Model { /** * @throws \api\modules\session\exceptions\ForbiddenOperationException */ - public function validateAccessToken(): void { + private function validateAccessToken(): void { $accessToken = $this->accessToken; - /** @var MinecraftAccessKey|null $accessModel */ - $accessModel = MinecraftAccessKey::findOne(['access_token' => $accessToken]); - if ($accessModel !== null) { - Yii::$app->statsd->inc('sessionserver.authentication.legacy_minecraft_protocol'); - /** @var MinecraftAccessKey|\api\components\OAuth2\Entities\AccessTokenEntity $accessModel */ - if ($accessModel->isExpired()) { - Session::error("User with access_token = '{$accessToken}' failed join by expired access_token."); - Yii::$app->statsd->inc('sessionserver.authentication.legacy_minecraft_protocol_token_expired'); - - throw new ForbiddenOperationException('Expired access_token.'); + try { + $identity = Yii::$app->user->loginByAccessToken($accessToken); + } catch (UnauthorizedHttpException $e) { + if ($e->getMessage() === 'Token expired') { + throw new ForbiddenOperationException('Expired access_token.', 0, $e); } - $account = $accessModel->account; - } else { - try { - $identity = Yii::$app->user->loginByAccessToken($accessToken); - } catch (UnauthorizedHttpException $e) { - $identity = null; - } - - if ($identity === null) { - Session::error("User with access_token = '{$accessToken}' failed join by wrong access_token."); - Yii::$app->statsd->inc('sessionserver.join.fail_wrong_token'); - - throw new ForbiddenOperationException('Invalid access_token.'); - } - - Yii::$app->statsd->inc('sessionserver.authentication.oauth2'); - if (!Yii::$app->user->can(P::MINECRAFT_SERVER_SESSION)) { - Session::error("User with access_token = '{$accessToken}' doesn't have enough scopes to make join."); - Yii::$app->statsd->inc('sessionserver.authentication.oauth2_not_enough_scopes'); - - throw new ForbiddenOperationException('The token does not have required scope.'); - } - - $account = $identity->getAccount(); + $identity = null; } + if ($identity === null) { + Session::error("User with access_token = '{$accessToken}' failed join by wrong access_token."); + Yii::$app->statsd->inc('sessionserver.join.fail_wrong_token'); + + throw new ForbiddenOperationException('Invalid access_token.'); + } + + Yii::$app->statsd->inc('sessionserver.authentication.oauth2'); + if (!Yii::$app->user->can(P::MINECRAFT_SERVER_SESSION)) { + Session::error("User with access_token = '{$accessToken}' doesn't have enough scopes to make join."); + Yii::$app->statsd->inc('sessionserver.authentication.oauth2_not_enough_scopes'); + + throw new ForbiddenOperationException('The token does not have required scope.'); + } + + /** @var Account $account */ + $account = $identity->getAccount(); + $selectedProfile = $this->selectedProfile; $isUuid = StringHelper::isUuid($selectedProfile); if ($isUuid && $account->uuid !== $this->normalizeUUID($selectedProfile)) { @@ -172,10 +161,6 @@ class JoinForm extends Model { $this->account = $account; } - protected function getAccount(): Account { - return $this->account; - } - private function normalizeUUID(string $uuid): string { return Uuid::fromString($uuid)->toString(); } diff --git a/api/tests/functional/authlibInjector/JoinCest.php b/api/tests/functional/authlibInjector/JoinCest.php index e43ec59..c6341d1 100644 --- a/api/tests/functional/authlibInjector/JoinCest.php +++ b/api/tests/functional/authlibInjector/JoinCest.php @@ -68,7 +68,7 @@ class JoinCest { public function joinWithExpiredToken(FunctionalTester $I) { $I->wantTo('join to some server with expired accessToken'); $I->sendPOST('/api/authlib-injector/sessionserver/session/minecraft/join', [ - 'accessToken' => '6042634a-a1e2-4aed-866c-c661fe4e63e2', + 'accessToken' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE1MTgzMzQ3NDMsImV4cCI6MTUxODMzNDc5MCwiY2xpZW50X2lkIjoiZWx5Iiwic2NvcGUiOiJtaW5lY3JhZnRfc2VydmVyX3Nlc3Npb24iLCJzdWIiOiJlbHl8MSJ9.0mBXezB2p0eGuusZDklthR8xQLGo-v1qoP0GPdEPpYvckJMoHmlSqiW-2WwLlxGK0_J4KmYlp5vM4ynE14armw', 'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022', 'serverId' => uuid(), ]); @@ -125,7 +125,7 @@ class JoinCest { public function joinByAccountMarkedForDeletion(FunctionalTester $I) { $I->sendPOST('/api/authlib-injector/sessionserver/session/minecraft/join', [ - 'accessToken' => '239ba889-7020-4383-8d99-cd8c8aab4a2f', + 'accessToken' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE1MTgzMzQ3NDMsImNsaWVudF9pZCI6ImVseSIsInNjb3BlIjoibWluZWNyYWZ0X3NlcnZlcl9zZXNzaW9uIiwic3ViIjoiZWx5fDE1In0.2qla7RzReBi2WtfgP3x8T6ZA0wn9HOrQo57xaZc2wMKPo1Zc49_o6w-5Ku1tbvzmESZfAxNQpfY4EwclEWjHYA', 'selectedProfile' => '6383de63-8f85-4ed5-92b7-5401a1fa68cd', 'serverId' => uuid(), ]); diff --git a/api/tests/functional/authserver/RefreshCest.php b/api/tests/functional/authserver/RefreshCest.php index a9a7ded..3e134f0 100644 --- a/api/tests/functional/authserver/RefreshCest.php +++ b/api/tests/functional/authserver/RefreshCest.php @@ -24,20 +24,6 @@ class RefreshCest { $this->assertSuccessResponse($I, $case[0]); } - /** - * @example [true] - * @example [false] - */ - public function refreshLegacyAccessToken(AuthserverSteps $I, Example $case) { - $I->wantTo('refresh legacy accessToken'); - $I->sendPOST('/api/authserver/authentication/refresh', [ - 'accessToken' => 'e7bb6648-2183-4981-9b86-eba5e7f87b42', - 'clientToken' => '6f380440-0c05-47bd-b7c6-d011f1b5308f', - 'requestUser' => $case[0], - ]); - $this->assertSuccessResponse($I, $case[0]); - } - public function refreshWithInvalidClientToken(AuthserverSteps $I) { $I->wantTo('refresh accessToken with not matched client token'); [$accessToken] = $I->amAuthenticated(); @@ -51,27 +37,11 @@ class RefreshCest { ]); } - public function refreshLegacyAccessTokenWithInvalidClientToken(AuthserverSteps $I) { - $I->wantTo('refresh legacy accessToken with not matched client token'); - $I->sendPOST('/api/authserver/authentication/refresh', [ - 'accessToken' => 'e7bb6648-2183-4981-9b86-eba5e7f87b42', - 'clientToken' => Uuid::uuid4()->toString(), - ]); - $I->canSeeResponseContainsJson([ - 'error' => 'ForbiddenOperationException', - 'errorMessage' => 'Invalid token.', - ]); - } - - /** - * @example {"accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE1NzU1NjE1MjgsImV4cCI6MTU3NTU2MTUyOCwiZWx5LXNjb3BlcyI6Im1pbmVjcmFmdF9zZXJ2ZXJfc2Vzc2lvbiIsImVseS1jbGllbnQtdG9rZW4iOiIydnByWnRVdk40VTVtSnZzc0ozaXNpekdVWFhQYnFsV1FsQjVVRWVfUV81bkxKYzlsbUJ3VU1hQWJ1MjBtZC1FNzNtengxNWFsZmRJSU1OMTV5YUpBalZOM29vQW9IRDctOWdOcmciLCJzdWIiOiJlbHl8MSJ9.vwjXzy0VtjJlP6B4RxqoE69yRSBsluZ29VELe4vDi8GCy487eC5cIf9hz9oxp5YcdE7uEJZeqX2yi3nk_0nCaA", "clientToken": "4f368b58-9097-4e56-80b1-f421ae4b53cf"} - * @example {"accessToken": "6042634a-a1e2-4aed-866c-c661fe4e63e2", "clientToken": "47fb164a-2332-42c1-8bad-549e67bb210c"} - */ - public function refreshExpiredToken(AuthserverSteps $I, Example $example) { + public function refreshExpiredToken(AuthserverSteps $I) { $I->wantTo('refresh legacy accessToken'); $I->sendPOST('/api/authserver/authentication/refresh', [ - 'accessToken' => $example['accessToken'], - 'clientToken' => $example['clientToken'], + 'accessToken' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE1NzU1NjE1MjgsImV4cCI6MTU3NTU2MTUyOCwiZWx5LXNjb3BlcyI6Im1pbmVjcmFmdF9zZXJ2ZXJfc2Vzc2lvbiIsImVseS1jbGllbnQtdG9rZW4iOiIydnByWnRVdk40VTVtSnZzc0ozaXNpekdVWFhQYnFsV1FsQjVVRWVfUV81bkxKYzlsbUJ3VU1hQWJ1MjBtZC1FNzNtengxNWFsZmRJSU1OMTV5YUpBalZOM29vQW9IRDctOWdOcmciLCJzdWIiOiJlbHl8MSJ9.vwjXzy0VtjJlP6B4RxqoE69yRSBsluZ29VELe4vDi8GCy487eC5cIf9hz9oxp5YcdE7uEJZeqX2yi3nk_0nCaA', + 'clientToken' => '4f368b58-9097-4e56-80b1-f421ae4b53cf', ]); $this->assertSuccessResponse($I, false); } diff --git a/api/tests/functional/authserver/ValidateCest.php b/api/tests/functional/authserver/ValidateCest.php index 93e5ff8..5835b6b 100644 --- a/api/tests/functional/authserver/ValidateCest.php +++ b/api/tests/functional/authserver/ValidateCest.php @@ -18,15 +18,6 @@ class ValidateCest { $I->canSeeResponseEquals(''); } - public function validateLegacyToken(AuthserverSteps $I) { - $I->wantTo('validate my legacy accessToken'); - $I->sendPOST('/api/authserver/authentication/validate', [ - 'accessToken' => 'e7bb6648-2183-4981-9b86-eba5e7f87b42', - ]); - $I->seeResponseCodeIs(200); - $I->canSeeResponseEquals(''); - } - public function wrongArguments(AuthserverSteps $I) { $I->wantTo('get error on wrong amount of arguments'); $I->sendPOST('/api/authserver/authentication/validate', [ @@ -66,23 +57,10 @@ class ValidateCest { ]); } - public function expiredLegacyAccessToken(AuthserverSteps $I) { - $I->wantTo('get error on expired legacy accessToken'); - $I->sendPOST('/api/authserver/authentication/validate', [ - 'accessToken' => '6042634a-a1e2-4aed-866c-c661fe4e63e2', // Already expired token from the fixtures - ]); - $I->canSeeResponseCodeIs(401); - $I->canSeeResponseIsJson(); - $I->canSeeResponseContainsJson([ - 'error' => 'ForbiddenOperationException', - 'errorMessage' => 'Token expired.', - ]); - } - public function credentialsFromBannedAccount(AuthserverSteps $I) { $I->wantTo('get error on expired legacy accessToken'); $I->sendPOST('/api/authserver/authentication/validate', [ - 'accessToken' => '239ba889-7020-4383-8d99-cd8c8aab4a2f', + 'accessToken' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE1MTgzMzQ3NDMsImNsaWVudF9pZCI6ImVseSIsInNjb3BlIjoibWluZWNyYWZ0X3NlcnZlcl9zZXNzaW9uIiwic3ViIjoiZWx5fDE1In0.2qla7RzReBi2WtfgP3x8T6ZA0wn9HOrQo57xaZc2wMKPo1Zc49_o6w-5Ku1tbvzmESZfAxNQpfY4EwclEWjHYA', ]); $I->canSeeResponseCodeIs(401); $I->canSeeResponseContainsJson([ diff --git a/api/tests/functional/sessionserver/JoinCest.php b/api/tests/functional/sessionserver/JoinCest.php index fd7fddb..d6b1576 100644 --- a/api/tests/functional/sessionserver/JoinCest.php +++ b/api/tests/functional/sessionserver/JoinCest.php @@ -79,10 +79,10 @@ class JoinCest { ]); } - public function joinWithExpiredToken(FunctionalTester $I) { + public function joinWithExpiredToken(OauthSteps $I) { $I->wantTo('join to some server with expired accessToken'); $this->route->join([ - 'accessToken' => '6042634a-a1e2-4aed-866c-c661fe4e63e2', + 'accessToken' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE1MTgzMzQ3NDMsImV4cCI6MTUxODMzNDc5MCwiY2xpZW50X2lkIjoiZWx5Iiwic2NvcGUiOiJtaW5lY3JhZnRfc2VydmVyX3Nlc3Npb24iLCJzdWIiOiJlbHl8MSJ9.0mBXezB2p0eGuusZDklthR8xQLGo-v1qoP0GPdEPpYvckJMoHmlSqiW-2WwLlxGK0_J4KmYlp5vM4ynE14armw', 'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022', 'serverId' => uuid(), ]); @@ -137,9 +137,9 @@ class JoinCest { ]); } - public function joinByAccountMarkedForDeletion(FunctionalTester $I) { + public function joinByAccountMarkedForDeletion(AuthserverSteps $I) { $this->route->join([ - 'accessToken' => '239ba889-7020-4383-8d99-cd8c8aab4a2f', + 'accessToken' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpYXQiOjE1MTgzMzQ3NDMsImNsaWVudF9pZCI6ImVseSIsInNjb3BlIjoibWluZWNyYWZ0X3NlcnZlcl9zZXNzaW9uIiwic3ViIjoiZWx5fDE1In0.2qla7RzReBi2WtfgP3x8T6ZA0wn9HOrQo57xaZc2wMKPo1Zc49_o6w-5Ku1tbvzmESZfAxNQpfY4EwclEWjHYA', 'selectedProfile' => '6383de63-8f85-4ed5-92b7-5401a1fa68cd', 'serverId' => uuid(), ]); diff --git a/api/tests/unit/components/User/ComponentTest.php b/api/tests/unit/components/User/ComponentTest.php index 260c8ce..b83b4d1 100644 --- a/api/tests/unit/components/User/ComponentTest.php +++ b/api/tests/unit/components/User/ComponentTest.php @@ -12,7 +12,6 @@ use common\models\AccountSession; use common\models\OauthClient; use common\tests\fixtures\AccountFixture; use common\tests\fixtures\AccountSessionFixture; -use common\tests\fixtures\MinecraftAccessKeyFixture; use common\tests\fixtures\OauthClientFixture; use common\tests\fixtures\OauthSessionFixture; use Lcobucci\JWT\Claim\Basic; @@ -34,7 +33,6 @@ class ComponentTest extends TestCase { return [ 'accounts' => AccountFixture::class, 'sessions' => AccountSessionFixture::class, - 'minecraftSessions' => MinecraftAccessKeyFixture::class, 'oauthClients' => OauthClientFixture::class, 'oauthSessions' => OauthSessionFixture::class, ]; @@ -82,12 +80,10 @@ class ComponentTest extends TestCase { // Dry run: no sessions should be removed $component->terminateSessions($account, Component::KEEP_MINECRAFT_SESSIONS | Component::KEEP_SITE_SESSIONS); - $this->assertNotEmpty($account->getMinecraftAccessKeys()->all()); $this->assertNotEmpty($account->getSessions()->all()); // All Minecraft sessions should be removed. Web sessions should be kept $component->terminateSessions($account, Component::KEEP_SITE_SESSIONS); - $this->assertEmpty($account->getMinecraftAccessKeys()->all()); $this->assertNotEmpty($account->getSessions()->all()); $this->assertEqualsWithDelta(time(), $account->getOauthSessions()->andWhere(['client_id' => OauthClient::UNAUTHORIZED_MINECRAFT_GAME_LAUNCHER])->one()->revoked_at, 5); @@ -100,7 +96,6 @@ class ComponentTest extends TestCase { // With no arguments each and every session should be removed $component->terminateSessions($account); $this->assertEmpty($account->getSessions()->all()); - $this->assertEmpty($account->getMinecraftAccessKeys()->all()); } } diff --git a/common/models/Account.php b/common/models/Account.php index 74493c3..1ef4979 100644 --- a/common/models/Account.php +++ b/common/models/Account.php @@ -46,7 +46,6 @@ use const common\LATEST_RULES_VERSION; * @property-read OauthClient[] $oauthClients * @property-read UsernameHistory[] $usernameHistory * @property-read AccountSession[] $sessions - * @property-read MinecraftAccessKey[] $minecraftAccessKeys * * Behaviors: * @mixin TimestampBehavior @@ -121,10 +120,6 @@ class Account extends ActiveRecord { return $this->hasMany(AccountSession::class, ['account_id' => 'id']); } - public function getMinecraftAccessKeys(): ActiveQuery { - return $this->hasMany(MinecraftAccessKey::class, ['account_id' => 'id']); - } - public function hasMojangUsernameCollision(): bool { return MojangUsername::find() ->andWhere(['username' => $this->username]) diff --git a/common/models/MinecraftAccessKey.php b/common/models/MinecraftAccessKey.php deleted file mode 100644 index 8eb64db..0000000 --- a/common/models/MinecraftAccessKey.php +++ /dev/null @@ -1,63 +0,0 @@ - TimestampBehavior::class, - ], - [ - 'class' => PrimaryKeyValueBehavior::class, - 'value' => function() { - return Uuid::uuid4()->toString(); - }, - ], - ]; - } - - public function getAccount(): AccountQuery { - /** @noinspection PhpIncompatibleReturnTypeInspection */ - return $this->hasOne(Account::class, ['id' => 'account_id']); - } - - public function isExpired(): bool { - return time() > $this->updated_at + self::LIFETIME; - } - -} diff --git a/common/tasks/ClearAccountSessions.php b/common/tasks/ClearAccountSessions.php index 0dbe7c5..36e5bfe 100644 --- a/common/tasks/ClearAccountSessions.php +++ b/common/tasks/ClearAccountSessions.php @@ -47,11 +47,6 @@ final class ClearAccountSessions implements RetryableJobInterface { $authSession->delete(); } - /** @var \common\models\MinecraftAccessKey $key */ - foreach ($account->getMinecraftAccessKeys()->each(100, Yii::$app->unbufferedDb) as $key) { - $key->delete(); - } - /** @var \common\models\OauthSession $oauthSession */ foreach ($account->getOauthSessions()->each(100, Yii::$app->unbufferedDb) as $oauthSession) { $oauthSession->delete(); diff --git a/common/tests/_support/FixtureHelper.php b/common/tests/_support/FixtureHelper.php index 4c7f6a3..cb9e268 100644 --- a/common/tests/_support/FixtureHelper.php +++ b/common/tests/_support/FixtureHelper.php @@ -56,7 +56,6 @@ class FixtureHelper extends Module { 'legacyOauthAccessTokens' => fixtures\LegacyOauthAccessTokenFixture::class, 'legacyOauthAccessTokensScopes' => fixtures\LegacyOauthAccessTokenScopeFixture::class, 'legacyOauthRefreshTokens' => fixtures\LegacyOauthRefreshTokenFixture::class, - 'minecraftAccessKeys' => fixtures\MinecraftAccessKeyFixture::class, ]; } diff --git a/common/tests/fixtures/MinecraftAccessKeyFixture.php b/common/tests/fixtures/MinecraftAccessKeyFixture.php deleted file mode 100644 index 983c194..0000000 --- a/common/tests/fixtures/MinecraftAccessKeyFixture.php +++ /dev/null @@ -1,17 +0,0 @@ - [ - 'access_token' => 'e7bb6648-2183-4981-9b86-eba5e7f87b42', - 'client_token' => '6f380440-0c05-47bd-b7c6-d011f1b5308f', - 'account_id' => 1, - 'created_at' => time() - 10, - 'updated_at' => time() - 10, - ], - 'expired-token' => [ - 'access_token' => '6042634a-a1e2-4aed-866c-c661fe4e63e2', - 'client_token' => '47fb164a-2332-42c1-8bad-549e67bb210c', - 'account_id' => 1, - 'created_at' => 1472423530, - 'updated_at' => 1472423530, - ], - 'banned-token' => [ - 'access_token' => '918ecb41-616c-40ee-a7d2-0b0ef0d0d732', - 'client_token' => '6042634a-a1e2-4aed-866c-c661fe4e63e2', - 'account_id' => 10, - 'created_at' => time() - 10, - 'updated_at' => time() - 10, - ], - 'deleted-token' => [ - 'access_token' => '239ba889-7020-4383-8d99-cd8c8aab4a2f', - 'client_token' => '47443658-4ff8-45e7-b33e-dc8915ab6421', - 'account_id' => 15, - 'created_at' => time() - 10, - 'updated_at' => time() - 10, - ], -]; diff --git a/common/tests/unit/tasks/ClearAccountSessionsTest.php b/common/tests/unit/tasks/ClearAccountSessionsTest.php index 3a8fc6f..dcaef62 100644 --- a/common/tests/unit/tasks/ClearAccountSessionsTest.php +++ b/common/tests/unit/tasks/ClearAccountSessionsTest.php @@ -17,7 +17,6 @@ class ClearAccountSessionsTest extends TestCase { return [ 'accounts' => fixtures\AccountFixture::class, 'oauthSessions' => fixtures\OauthSessionFixture::class, - 'minecraftAccessKeys' => fixtures\MinecraftAccessKeyFixture::class, 'authSessions' => fixtures\AccountSessionFixture::class, ]; } @@ -28,7 +27,6 @@ class ClearAccountSessionsTest extends TestCase { $task = new ClearAccountSessions($bannedAccount->id); $task->execute($this->createMock(Queue::class)); $this->assertEmpty($bannedAccount->sessions); - $this->assertEmpty($bannedAccount->minecraftAccessKeys); $this->assertEmpty($bannedAccount->oauthSessions); } diff --git a/common/tests/unit/tasks/DeleteAccountTest.php b/common/tests/unit/tasks/DeleteAccountTest.php index ae6d609..b4dd928 100644 --- a/common/tests/unit/tasks/DeleteAccountTest.php +++ b/common/tests/unit/tasks/DeleteAccountTest.php @@ -19,7 +19,6 @@ class DeleteAccountTest extends TestCase { 'accounts' => fixtures\AccountFixture::class, 'authSessions' => fixtures\AccountSessionFixture::class, 'emailActivations' => fixtures\EmailActivationFixture::class, - 'minecraftAccessKeys' => fixtures\MinecraftAccessKeyFixture::class, 'usernamesHistory' => fixtures\UsernameHistoryFixture::class, 'oauthClients' => fixtures\OauthClientFixture::class, 'oauthSessions' => fixtures\OauthSessionFixture::class, @@ -37,7 +36,6 @@ class DeleteAccountTest extends TestCase { $task->execute($this->createMock(Queue::class)); $this->assertEmpty($account->emailActivations); $this->assertEmpty($account->sessions); - $this->assertEmpty($account->minecraftAccessKeys); $this->assertEmpty($account->oauthSessions); $this->assertEmpty($account->usernameHistory); $this->assertEmpty($account->oauthClients); @@ -57,7 +55,6 @@ class DeleteAccountTest extends TestCase { $task->execute($this->createMock(Queue::class)); $this->assertNotEmpty($account->emailActivations); $this->assertNotEmpty($account->sessions); - $this->assertNotEmpty($account->minecraftAccessKeys); $this->assertNotEmpty($account->oauthSessions); $this->assertNotEmpty($account->usernameHistory); $this->assertNotEmpty($account->oauthClients); @@ -80,7 +77,6 @@ class DeleteAccountTest extends TestCase { $task->execute($this->createMock(Queue::class)); $this->assertNotEmpty($account->emailActivations); $this->assertNotEmpty($account->sessions); - $this->assertNotEmpty($account->minecraftAccessKeys); $this->assertNotEmpty($account->oauthSessions); $this->assertNotEmpty($account->usernameHistory); $this->assertNotEmpty($account->oauthClients); diff --git a/console/controllers/CleanupController.php b/console/controllers/CleanupController.php index a64e1d2..054ba2f 100644 --- a/console/controllers/CleanupController.php +++ b/console/controllers/CleanupController.php @@ -1,10 +1,8 @@ andWhere(['<', 'updated_at', Carbon::now()->subMonths(3)->getTimestamp()]); - - foreach ($expiredMinecraftSessionsQuery->each(100, Yii::$app->unbufferedDb) as $minecraftSession) { - /** @var MinecraftAccessKey $minecraftSession */ - $minecraftSession->delete(); - } - - return ExitCode::OK; - } - /** * Sessions that have not been refreshed for 90 days and those * that have not been refreshed since they were issued more than 2 weeks ago diff --git a/console/migrations/m240614_024554_drop_minecraft_access_keys_table.php b/console/migrations/m240614_024554_drop_minecraft_access_keys_table.php new file mode 100644 index 0000000..e83a01f --- /dev/null +++ b/console/migrations/m240614_024554_drop_minecraft_access_keys_table.php @@ -0,0 +1,24 @@ +dropTable('minecraft_access_keys'); + } + + public function safeDown() { + $this->createTable('minecraft_access_keys', [ + 'access_token' => $this->string(36)->notNull(), + 'client_token' => $this->string()->notNull(), + 'account_id' => $this->db->getTableSchema('accounts')->getColumn('id')->dbType . ' NOT NULL', + 'created_at' => $this->integer()->unsigned()->notNull(), + 'updated_at' => $this->integer()->unsigned()->notNull(), + $this->primary('access_token'), + ]); + $this->addForeignKey('FK_minecraft_access_token_to_account', 'minecraft_access_keys', 'account_id', 'accounts', 'id', 'CASCADE', 'CASCADE'); + } + +} diff --git a/console/tests/unit/controllers/CleanupControllerTest.php b/console/tests/unit/controllers/CleanupControllerTest.php index 6d6d3d1..b4172ae 100644 --- a/console/tests/unit/controllers/CleanupControllerTest.php +++ b/console/tests/unit/controllers/CleanupControllerTest.php @@ -5,7 +5,6 @@ namespace console\tests\unit\controllers; use common\models\AccountSession; use common\models\EmailActivation; -use common\models\MinecraftAccessKey; use common\models\OauthClient; use common\tasks\ClearOauthSessions; use common\tests\fixtures; @@ -18,7 +17,6 @@ class CleanupControllerTest extends TestCase { public function _fixtures(): array { return [ 'emailActivations' => fixtures\EmailActivationFixture::class, - 'minecraftSessions' => fixtures\MinecraftAccessKeyFixture::class, 'accountsSessions' => fixtures\AccountSessionFixture::class, 'oauthClients' => fixtures\OauthClientFixture::class, 'oauthSessions' => fixtures\OauthSessionFixture::class, @@ -35,16 +33,6 @@ class CleanupControllerTest extends TestCase { $this->tester->cantSeeRecord(EmailActivation::class, ['key' => $expiredConfirmation->key]); } - public function testActionMinecraftSessions() { - /** @var MinecraftAccessKey $expiredSession */ - $expiredSession = $this->tester->grabFixture('minecraftSessions', 'expired-token'); - - $controller = new CleanupController('cleanup', Yii::$app); - $this->assertSame(0, $controller->actionMinecraftSessions()); - - $this->tester->cantSeeRecord(MinecraftAccessKey::class, ['access_token' => $expiredSession->access_token]); - } - public function testActionWebSessions() { /** @var AccountSession $expiredSession */ $expiredSession = $this->tester->grabFixture('accountsSessions', 'very-expired-session'); diff --git a/docker/cron/cleanup b/docker/cron/cleanup index 247db1f..abb1a69 100644 --- a/docker/cron/cleanup +++ b/docker/cron/cleanup @@ -1,5 +1,4 @@ # https://crontab.guru/every-day 0 0 * * * php /var/www/html/yii cleanup/email-keys >/dev/null 2>&1 -0 1 * * * php /var/www/html/yii cleanup/minecraft-sessions >/dev/null 2>&1 0 2 * * * php /var/www/html/yii cleanup/web-sessions >/dev/null 2>&1 0 3 * * * php /var/www/html/yii cleanup/oauth-clients >/dev/null 2>&1