diff --git a/api/config/routes.php b/api/config/routes.php index 2a0f5a0..6dec26d 100644 --- a/api/config/routes.php +++ b/api/config/routes.php @@ -12,4 +12,5 @@ return [ '/minecraft/session/legacy/join' => 'session/session/join-legacy', '/minecraft/session/hasJoined' => 'session/session/has-joined', '/minecraft/session/legacy/hasJoined' => 'session/session/has-joined-legacy', + '/minecraft/session/profile/' => 'session/session/profile', ]; diff --git a/api/modules/session/controllers/SessionController.php b/api/modules/session/controllers/SessionController.php index 8e0835b..56475c4 100644 --- a/api/modules/session/controllers/SessionController.php +++ b/api/modules/session/controllers/SessionController.php @@ -3,6 +3,7 @@ namespace api\modules\session\controllers; use api\controllers\ApiController; use api\modules\session\exceptions\ForbiddenOperationException; +use api\modules\session\exceptions\IllegalArgumentException; use api\modules\session\exceptions\SessionServerException; use api\modules\session\filters\RateLimiter; use api\modules\session\models\HasJoinedForm; @@ -10,7 +11,9 @@ use api\modules\session\models\JoinForm; use api\modules\session\models\protocols\LegacyJoin; use api\modules\session\models\protocols\ModernHasJoined; use api\modules\session\models\protocols\ModernJoin; +use common\models\Account; use common\models\Textures; +use Ramsey\Uuid\Uuid; use Yii; use yii\web\Response; @@ -99,4 +102,19 @@ class SessionController extends ApiController { return 'YES'; } + public function actionProfile($uuid) { + try { + $uuid = Uuid::fromString($uuid)->toString(); + } catch(\InvalidArgumentException $e) { + throw new IllegalArgumentException('Invalid uuid format.'); + } + + $account = Account::findOne(['uuid' => $uuid]); + if ($account === null) { + throw new ForbiddenOperationException('Invalid uuid.'); + } + + return (new Textures($account))->getMinecraftResponse(); + } + } diff --git a/api/modules/session/exceptions/IllegalArgumentException.php b/api/modules/session/exceptions/IllegalArgumentException.php index 2250a22..ac904db 100644 --- a/api/modules/session/exceptions/IllegalArgumentException.php +++ b/api/modules/session/exceptions/IllegalArgumentException.php @@ -3,8 +3,8 @@ namespace api\modules\session\exceptions; class IllegalArgumentException extends SessionServerException { - public function __construct($status = null, $message = null, $code = 0, \Exception $previous = null) { - parent::__construct(400, 'credentials can not be null.', $code, $previous); + public function __construct($message = 'credentials can not be null.', $code = 0, \Exception $previous = null) { + parent::__construct(400, $message, $code, $previous); } } diff --git a/tests/codeception/api/_pages/SessionServerRoute.php b/tests/codeception/api/_pages/SessionServerRoute.php index 7e102ff..b3ac951 100644 --- a/tests/codeception/api/_pages/SessionServerRoute.php +++ b/tests/codeception/api/_pages/SessionServerRoute.php @@ -28,4 +28,9 @@ class SessionServerRoute extends BasePage { $this->actor->sendGET($this->getUrl(), $params); } + public function profile($profileUuid) { + $this->route = '/minecraft/session/profile/' . $profileUuid; + $this->actor->sendGET($this->getUrl()); + } + } diff --git a/tests/codeception/api/functional/_steps/SessionServerSteps.php b/tests/codeception/api/functional/_steps/SessionServerSteps.php index 6bcb3fe..b5b4d6a 100644 --- a/tests/codeception/api/functional/_steps/SessionServerSteps.php +++ b/tests/codeception/api/functional/_steps/SessionServerSteps.php @@ -34,5 +34,33 @@ class SessionServerSteps extends \tests\codeception\api\FunctionalTester { return [$username, $serverId]; } + + public function canSeeValidTexturesResponse($expectedUsername, $expectedUuid) { + $this->seeResponseIsJson(); + $this->canSeeResponseContainsJson([ + 'name' => $expectedUsername, + 'id' => $expectedUuid, + 'ely' => true, + 'properties' => [ + [ + 'name' => 'textures', + 'signature' => 'Cg==', + ], + ], + ]); + $this->canSeeResponseJsonMatchesJsonPath('$.properties[0].value'); + $value = json_decode($this->grabResponse(), true)['properties'][0]['value']; + $decoded = json_decode(base64_decode($value), true); + $this->assertArrayHasKey('timestamp', $decoded); + $this->assertArrayHasKey('textures', $decoded); + $this->assertEquals($expectedUuid, $decoded['profileId']); + $this->assertEquals($expectedUsername, $decoded['profileName']); + $this->assertTrue($decoded['ely']); + $textures = $decoded['textures']; + $this->assertArrayHasKey('SKIN', $textures); + $skinTextures = $textures['SKIN']; + $this->assertArrayHasKey('url', $skinTextures); + $this->assertArrayHasKey('hash', $skinTextures); + } } diff --git a/tests/codeception/api/functional/sessionserver/HasJoinedCest.php b/tests/codeception/api/functional/sessionserver/HasJoinedCest.php index 682099a..8b90d1e 100644 --- a/tests/codeception/api/functional/sessionserver/HasJoinedCest.php +++ b/tests/codeception/api/functional/sessionserver/HasJoinedCest.php @@ -26,31 +26,7 @@ class HasJoinedCest { 'serverId' => $serverId, ]); $I->seeResponseCodeIs(200); - $I->seeResponseIsJson(); - $I->canSeeResponseContainsJson([ - 'name' => $username, - 'id' => 'df936908b2e1544d96f82977ec213022', - 'ely' => true, - 'properties' => [ - [ - 'name' => 'textures', - 'signature' => 'Cg==', - ], - ], - ]); - $I->canSeeResponseJsonMatchesJsonPath('$.properties[0].value'); - $value = json_decode($I->grabResponse(), true)['properties'][0]['value']; - $decoded = json_decode(base64_decode($value), true); - $I->assertArrayHasKey('timestamp', $decoded); - $I->assertArrayHasKey('textures', $decoded); - $I->assertEquals('df936908b2e1544d96f82977ec213022', $decoded['profileId']); - $I->assertEquals('Admin', $decoded['profileName']); - $I->assertTrue($decoded['ely']); - $textures = $decoded['textures']; - $I->assertArrayHasKey('SKIN', $textures); - $skinTextures = $textures['SKIN']; - $I->assertArrayHasKey('url', $skinTextures); - $I->assertArrayHasKey('hash', $skinTextures); + $I->canSeeValidTexturesResponse($username, 'df936908b2e1544d96f82977ec213022'); } public function wrongArguments(FunctionalTester $I) { diff --git a/tests/codeception/api/functional/sessionserver/ProfileCest.php b/tests/codeception/api/functional/sessionserver/ProfileCest.php new file mode 100644 index 0000000..29e83c1 --- /dev/null +++ b/tests/codeception/api/functional/sessionserver/ProfileCest.php @@ -0,0 +1,61 @@ +route = new SessionServerRoute($I); + } + + public function getProfile(SessionServerSteps $I) { + $I->wantTo('get info about player textures by uuid'); + $this->route->profile('df936908-b2e1-544d-96f8-2977ec213022'); + $I->canSeeValidTexturesResponse('Admin', 'df936908b2e1544d96f82977ec213022'); + } + + public function getProfileByUuidWithoutDashes(SessionServerSteps $I) { + $I->wantTo('get info about player textures by uuid without dashes'); + $this->route->profile('df936908b2e1544d96f82977ec213022'); + $I->canSeeValidTexturesResponse('Admin', 'df936908b2e1544d96f82977ec213022'); + } + + public function directCallWithoutUuidPart(FunctionalTester $I) { + $I->wantTo('call profile route without passing uuid'); + $this->route->profile(''); + $I->canSeeResponseCodeIs(404); + } + + public function callWithInvalidUuid(FunctionalTester $I) { + $I->wantTo('call profile route with invalid uuid string'); + $this->route->profile('bla-bla-bla'); + $I->canSeeResponseCodeIs(400); + $I->canSeeResponseIsJson(); + $I->canSeeResponseContainsJson([ + 'error' => 'IllegalArgumentException', + 'errorMessage' => 'Invalid uuid format.', + ]); + } + + public function getProfileWithNonexistentUuid(FunctionalTester $I) { + $I->wantTo('get info about nonexistent uuid'); + $this->route->profile(Uuid::uuid()); + $I->canSeeResponseCodeIs(401); + $I->canSeeResponseIsJson(); + $I->seeResponseIsJson(); + $I->canSeeResponseContainsJson([ + 'error' => 'ForbiddenOperationException', + 'errorMessage' => 'Invalid uuid.', + ]); + } + +}