mirror of
				https://github.com/elyby/accounts.git
				synced 2025-05-31 14:11:46 +05:30 
			
		
		
		
	Update Mojang API response code and messages, implement UUID->Username endpoint (#47)
* Update Mojang API response code and messages, implement UUID->Username endpoint * php-cs-fixer Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * review: address the minor issues Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * try to implement legacy response support (all tests are failing (routing is broken)) Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * well that was 10x easier Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * fix: php-cs-fixer Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> * Fix PHPStan errors and update tests for authlib-injector entrypoint. Final polishing before merge --------- Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com> Co-authored-by: ErickSkrauch <erickskrauch@yandex.ru>
This commit is contained in:
		@@ -49,6 +49,7 @@ return [
 | 
				
			|||||||
    'GET /mojang/services/minecraft/profile' => 'mojang/services/profile',
 | 
					    'GET /mojang/services/minecraft/profile' => 'mojang/services/profile',
 | 
				
			||||||
    'POST /mojang/services/minecraft/profile/lookup/bulk/byname' => 'mojang/api/uuids-by-usernames',
 | 
					    'POST /mojang/services/minecraft/profile/lookup/bulk/byname' => 'mojang/api/uuids-by-usernames',
 | 
				
			||||||
    'GET /mojang/services/minecraft/profile/lookup/name/<username>' => 'mojang/api/uuid-by-username',
 | 
					    'GET /mojang/services/minecraft/profile/lookup/name/<username>' => 'mojang/api/uuid-by-username',
 | 
				
			||||||
 | 
					    'GET /mojang/services/minecraft/profile/lookup/<uuid>' => 'mojang/api/username-by-uuid',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // authlib-injector
 | 
					    // authlib-injector
 | 
				
			||||||
    '/authlib-injector/authserver/<action>' => 'authserver/authentication/<action>',
 | 
					    '/authlib-injector/authserver/<action>' => 'authserver/authentication/<action>',
 | 
				
			||||||
@@ -58,4 +59,5 @@ return [
 | 
				
			|||||||
    '/authlib-injector/api/profiles/minecraft' => 'mojang/api/uuids-by-usernames',
 | 
					    '/authlib-injector/api/profiles/minecraft' => 'mojang/api/uuids-by-usernames',
 | 
				
			||||||
    '/authlib-injector/minecraftservices/minecraft/profile/lookup/bulk/byname' => 'mojang/api/uuids-by-usernames',
 | 
					    '/authlib-injector/minecraftservices/minecraft/profile/lookup/bulk/byname' => 'mojang/api/uuids-by-usernames',
 | 
				
			||||||
    '/authlib-injector/minecraftservices/minecraft/profile/lookup/name/<username>' => 'mojang/api/uuid-by-username',
 | 
					    '/authlib-injector/minecraftservices/minecraft/profile/lookup/name/<username>' => 'mojang/api/uuid-by-username',
 | 
				
			||||||
 | 
					    '/authlib-injector/minecraftservices/minecraft/profile/lookup/<uuid>' => 'mojang/api/username-by-uuid',
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ use yii\helpers\ArrayHelper;
 | 
				
			|||||||
use yii\helpers\UnsetArrayValue;
 | 
					use yii\helpers\UnsetArrayValue;
 | 
				
			||||||
use yii\web\Response;
 | 
					use yii\web\Response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ApiController extends Controller {
 | 
					final class ApiController extends Controller {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function behaviors(): array {
 | 
					    public function behaviors(): array {
 | 
				
			||||||
        return ArrayHelper::merge(parent::behaviors(), [
 | 
					        return ArrayHelper::merge(parent::behaviors(), [
 | 
				
			||||||
@@ -27,7 +27,7 @@ class ApiController extends Controller {
 | 
				
			|||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function actionUuidByUsername(string $username, int $at = null) {
 | 
					    public function actionUuidByUsername(string $username, int $at = null): ?array {
 | 
				
			||||||
        if ($at !== null) {
 | 
					        if ($at !== null) {
 | 
				
			||||||
            /** @var UsernameHistory|null $record */
 | 
					            /** @var UsernameHistory|null $record */
 | 
				
			||||||
            $record = UsernameHistory::find()
 | 
					            $record = UsernameHistory::find()
 | 
				
			||||||
@@ -52,7 +52,7 @@ class ApiController extends Controller {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($account === null || $account->status === Account::STATUS_DELETED) {
 | 
					        if ($account === null || $account->status === Account::STATUS_DELETED) {
 | 
				
			||||||
            return $this->noContentResponse();
 | 
					            return $this->isModernEndpoint() ? $this->contentNotFound("Couldn't find any profile with name {$username}") : $this->noContent();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return [
 | 
					        return [
 | 
				
			||||||
@@ -61,7 +61,7 @@ class ApiController extends Controller {
 | 
				
			|||||||
        ];
 | 
					        ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function actionUsernamesByUuid(string $uuid) {
 | 
					    public function actionUsernamesByUuid(string $uuid): ?array {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            $uuid = Uuid::fromString($uuid)->toString();
 | 
					            $uuid = Uuid::fromString($uuid)->toString();
 | 
				
			||||||
        } catch (\InvalidArgumentException) {
 | 
					        } catch (\InvalidArgumentException) {
 | 
				
			||||||
@@ -70,7 +70,7 @@ class ApiController extends Controller {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $account = Account::find()->excludeDeleted()->andWhere(['uuid' => $uuid])->one();
 | 
					        $account = Account::find()->excludeDeleted()->andWhere(['uuid' => $uuid])->one();
 | 
				
			||||||
        if ($account === null) {
 | 
					        if ($account === null) {
 | 
				
			||||||
            return $this->noContentResponse();
 | 
					            return $this->noContent();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /** @var UsernameHistory[] $usernameHistory */
 | 
					        /** @var UsernameHistory[] $usernameHistory */
 | 
				
			||||||
@@ -93,20 +93,39 @@ class ApiController extends Controller {
 | 
				
			|||||||
        return $data;
 | 
					        return $data;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function actionUuidsByUsernames() {
 | 
					    public function actionUsernameByUuid(string $uuid): array {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            $uuid = Uuid::fromString($uuid)->toString();
 | 
				
			||||||
 | 
					        } catch (\InvalidArgumentException) {
 | 
				
			||||||
 | 
					            return $this->constraintViolation("Invalid UUID string: {$uuid}");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /** @var Account|null $account */
 | 
				
			||||||
 | 
					        $account = Account::findOne(['uuid' => $uuid]);
 | 
				
			||||||
 | 
					        if ($account === null || $account->status === Account::STATUS_DELETED) {
 | 
				
			||||||
 | 
					            return $this->contentNotFound();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'id' => str_replace('-', '', $account->uuid),
 | 
				
			||||||
 | 
					            'name' => $account->username,
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function actionUuidsByUsernames(): array {
 | 
				
			||||||
        $usernames = Yii::$app->request->post();
 | 
					        $usernames = Yii::$app->request->post();
 | 
				
			||||||
        if (empty($usernames)) {
 | 
					        if (empty($usernames)) {
 | 
				
			||||||
            return $this->illegalArgumentResponse('Passed array of profile names is an invalid JSON string.');
 | 
					            return $this->isModernEndpoint() ? $this->constraintViolation('size must be between 1 and 100') : $this->illegalArgumentResponse('Passed array of profile names is an invalid JSON string.');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $usernames = array_unique($usernames);
 | 
					        $usernames = array_unique($usernames);
 | 
				
			||||||
        if (count($usernames) > 100) {
 | 
					        if (count($usernames) > 100) {
 | 
				
			||||||
            return $this->illegalArgumentResponse('Not more that 100 profile name per call is allowed.');
 | 
					            return $this->isModernEndpoint() ? $this->constraintViolation('size must be between 1 and 100') : $this->illegalArgumentResponse('Not more that 100 profile name per call is allowed.');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        foreach ($usernames as $username) {
 | 
					        foreach ($usernames as $username) {
 | 
				
			||||||
            if (empty($username) || is_array($username)) {
 | 
					            if (empty($username) || is_array($username)) {
 | 
				
			||||||
                return $this->illegalArgumentResponse('profileName can not be null, empty or array key.');
 | 
					                return $this->isModernEndpoint() ? $this->constraintViolation('Invalid profile name') : $this->illegalArgumentResponse('profileName can not be null, empty or array key.');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -129,25 +148,62 @@ class ApiController extends Controller {
 | 
				
			|||||||
        return $responseData;
 | 
					        return $responseData;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private function noContentResponse() {
 | 
					    private function isModernEndpoint(): bool {
 | 
				
			||||||
        $response = Yii::$app->getResponse();
 | 
					        $url = Yii::$app->getRequest()->url;
 | 
				
			||||||
        $response->setStatusCode(204);
 | 
					 | 
				
			||||||
        $response->format = Response::FORMAT_RAW;
 | 
					 | 
				
			||||||
        $response->content = '';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $response;
 | 
					        return str_contains($url, 'mojang/services')
 | 
				
			||||||
 | 
					            || str_contains($url, 'minecraftservices');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private function illegalArgumentResponse(string $errorMessage) {
 | 
					    private function noContent(): null {
 | 
				
			||||||
        $response = Yii::$app->getResponse();
 | 
					        $this->response->setStatusCode(204);
 | 
				
			||||||
        $response->setStatusCode(400);
 | 
					        $this->response->format = Response::FORMAT_RAW;
 | 
				
			||||||
        $response->format = Response::FORMAT_JSON;
 | 
					
 | 
				
			||||||
        $response->data = [
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @phpstan-return array<mixed>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function contentNotFound(?string $errorMessage = null): array {
 | 
				
			||||||
 | 
					        $this->response->setStatusCode(404);
 | 
				
			||||||
 | 
					        if ($errorMessage === null) {
 | 
				
			||||||
 | 
					            return [
 | 
				
			||||||
 | 
					                'path' => $this->request->url,
 | 
				
			||||||
 | 
					                'error' => 'NOT_FOUND',
 | 
				
			||||||
 | 
					                'errorMessage' => 'Not Found',
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'path' => $this->request->url,
 | 
				
			||||||
 | 
					            'errorMessage' => $errorMessage,
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @phpstan-return array<mixed>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function constraintViolation(string $errorMessage): array {
 | 
				
			||||||
 | 
					        $this->response->setStatusCode(400);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            'path' => $this->request->url,
 | 
				
			||||||
 | 
					            'error' => 'CONSTRAINT_VIOLATION',
 | 
				
			||||||
 | 
					            'errorMessage' => $errorMessage,
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @phpstan-return array<mixed>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function illegalArgumentResponse(string $errorMessage): array {
 | 
				
			||||||
 | 
					        $this->response->setStatusCode(400);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
            'error' => 'IllegalArgumentException',
 | 
					            'error' => 'IllegalArgumentException',
 | 
				
			||||||
            'errorMessage' => $errorMessage,
 | 
					            'errorMessage' => $errorMessage,
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $response;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,15 @@ use Codeception\Example;
 | 
				
			|||||||
final class MinecraftProfilesCest {
 | 
					final class MinecraftProfilesCest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return iterable<array{string}>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static function bulkProfilesEndpoints(): iterable {
 | 
				
			||||||
 | 
					        yield ['/api/authlib-injector/api/profiles/minecraft'];
 | 
				
			||||||
 | 
					        yield ['/api/authlib-injector/minecraftservices/minecraft/profile/lookup/bulk/byname'];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidByOneUsername(FunctionalTester $I, Example $case): void {
 | 
					    public function getUuidByOneUsername(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -23,6 +32,7 @@ final class MinecraftProfilesCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidsByUsernames(FunctionalTester $I, Example $case): void {
 | 
					    public function getUuidsByUsernames(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -31,6 +41,7 @@ final class MinecraftProfilesCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidsByUsernamesWithPostString(FunctionalTester $I, Example $case): void {
 | 
					    public function getUuidsByUsernamesWithPostString(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -42,6 +53,7 @@ final class MinecraftProfilesCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidsByPartialNonexistentUsernames(FunctionalTester $I, Example $case): void {
 | 
					    public function getUuidsByPartialNonexistentUsernames(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -58,6 +70,7 @@ final class MinecraftProfilesCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function passAllNonexistentUsernames(FunctionalTester $I, Example $case): void {
 | 
					    public function passAllNonexistentUsernames(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -68,6 +81,7 @@ final class MinecraftProfilesCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function passTooManyUsernames(FunctionalTester $I, Example $case): void {
 | 
					    public function passTooManyUsernames(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -79,41 +93,64 @@ final class MinecraftProfilesCest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $I->sendPOST($case[0], $usernames);
 | 
					        $I->sendPOST($case[0], $usernames);
 | 
				
			||||||
        $I->canSeeResponseCodeIs(400);
 | 
					        $I->canSeeResponseCodeIs(400);
 | 
				
			||||||
        $I->canSeeResponseContainsJson([
 | 
					        if (self::isModernEndpoint($case[0])) {
 | 
				
			||||||
            'error' => 'IllegalArgumentException',
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
            'errorMessage' => 'Not more that 100 profile name per call is allowed.',
 | 
					                'path' => $case[0],
 | 
				
			||||||
        ]);
 | 
					                'error' => 'CONSTRAINT_VIOLATION',
 | 
				
			||||||
 | 
					                'errorMessage' => 'size must be between 1 and 100',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'error' => 'IllegalArgumentException',
 | 
				
			||||||
 | 
					                'errorMessage' => 'Not more that 100 profile name per call is allowed.',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function passEmptyUsername(FunctionalTester $I, Example $case): void {
 | 
					    public function passEmptyUsername(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
        $I->sendPOST($case[0], ['Admin', '']);
 | 
					        $I->sendPOST($case[0], ['Admin', '']);
 | 
				
			||||||
        $I->canSeeResponseCodeIs(400);
 | 
					        $I->canSeeResponseCodeIs(400);
 | 
				
			||||||
        $I->canSeeResponseContainsJson([
 | 
					        if (self::isModernEndpoint($case[0])) {
 | 
				
			||||||
            'error' => 'IllegalArgumentException',
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
            'errorMessage' => 'profileName can not be null, empty or array key.',
 | 
					                'path' => $case[0],
 | 
				
			||||||
        ]);
 | 
					                'error' => 'CONSTRAINT_VIOLATION',
 | 
				
			||||||
 | 
					                'errorMessage' => 'Invalid profile name',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'error' => 'IllegalArgumentException',
 | 
				
			||||||
 | 
					                'errorMessage' => 'profileName can not be null, empty or array key.',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function passEmptyField(FunctionalTester $I, Example $case): void {
 | 
					    public function passEmptyField(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
        $I->sendPOST($case[0], []);
 | 
					        $I->sendPOST($case[0], []);
 | 
				
			||||||
        $I->canSeeResponseCodeIs(400);
 | 
					        $I->canSeeResponseCodeIs(400);
 | 
				
			||||||
        $I->canSeeResponseContainsJson([
 | 
					        if (self::isModernEndpoint($case[0])) {
 | 
				
			||||||
            'error' => 'IllegalArgumentException',
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
            'errorMessage' => 'Passed array of profile names is an invalid JSON string.',
 | 
					                'path' => $case[0],
 | 
				
			||||||
        ]);
 | 
					                'error' => 'CONSTRAINT_VIOLATION',
 | 
				
			||||||
 | 
					                'errorMessage' => 'size must be between 1 and 100',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'error' => 'IllegalArgumentException',
 | 
				
			||||||
 | 
					                'errorMessage' => 'Passed array of profile names is an invalid JSON string.',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function bulkProfilesEndpoints(): array {
 | 
					    private static function isModernEndpoint(string $url): bool {
 | 
				
			||||||
        return [
 | 
					        return str_contains($url, 'minecraftservices');
 | 
				
			||||||
            ['/api/authlib-injector/api/profiles/minecraft'],
 | 
					 | 
				
			||||||
            ['/api/authlib-injector/minecraftservices/minecraft/profile/lookup/bulk/byname'],
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private function validateFewValidUsernames(FunctionalTester $I): void {
 | 
					    private function validateFewValidUsernames(FunctionalTester $I): void {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,6 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace api\tests\functional\mojang;
 | 
					namespace api\tests\functional\mojang;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use api\tests\FunctionalTester;
 | 
					use api\tests\FunctionalTester;
 | 
				
			||||||
@@ -15,7 +17,7 @@ final class UsernameToUuidCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @param Example<array{string}> $url
 | 
					     * @param \Codeception\Example<array{string}> $url
 | 
				
			||||||
     * @dataProvider endpoints
 | 
					     * @dataProvider endpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidByUsername(FunctionalTester $I, Example $url): void {
 | 
					    public function getUuidByUsername(FunctionalTester $I, Example $url): void {
 | 
				
			||||||
@@ -30,7 +32,7 @@ final class UsernameToUuidCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @param Example<array{string}> $url
 | 
					     * @param \Codeception\Example<array{string}> $url
 | 
				
			||||||
     * @dataProvider endpoints
 | 
					     * @dataProvider endpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidByUsernameAtMoment(FunctionalTester $I, Example $url): void {
 | 
					    public function getUuidByUsernameAtMoment(FunctionalTester $I, Example $url): void {
 | 
				
			||||||
@@ -45,57 +47,104 @@ final class UsernameToUuidCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @param Example<array{string}> $url
 | 
					     * @param \Codeception\Example<array{string}> $url
 | 
				
			||||||
     * @dataProvider endpoints
 | 
					     * @dataProvider endpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidByUsernameAtWrongMoment(FunctionalTester $I, Example $url): void {
 | 
					    public function getUuidByUsernameAtWrongMoment(FunctionalTester $I, Example $url): void {
 | 
				
			||||||
        $I->wantTo('get 204 if passed once used, but changed username at moment, when it was changed');
 | 
					        $I->wantTo('get 204 if passed once used, but changed username at moment, when it was changed');
 | 
				
			||||||
        $I->sendGET("{$url[0]}/klik201", ['at' => 1474404144]);
 | 
					        $I->sendGET("{$url[0]}/klik201", ['at' => 1474404144]);
 | 
				
			||||||
        $I->canSeeResponseCodeIs(204);
 | 
					        if (self::isModernEndpoint($url[0])) {
 | 
				
			||||||
        $I->canSeeResponseEquals('');
 | 
					            $I->canSeeResponseCodeIs(404);
 | 
				
			||||||
 | 
					            $I->canSeeResponseIsJson();
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'path' => "{$url[0]}/klik201?at=1474404144",
 | 
				
			||||||
 | 
					                'errorMessage' => "Couldn't find any profile with name klik201",
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseCodeIs(204);
 | 
				
			||||||
 | 
					            $I->canSeeResponseEquals('');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @param Example<array{string}> $url
 | 
					     * @param \Codeception\Example<array{string}> $url
 | 
				
			||||||
     * @dataProvider endpoints
 | 
					     * @dataProvider endpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidByUsernameWithoutMoment(FunctionalTester $I, Example $url): void {
 | 
					    public function getUuidByUsernameWithoutMoment(FunctionalTester $I, Example $url): void {
 | 
				
			||||||
        $I->wantTo('get 204 if username not busy and not passed valid time mark, when it was busy');
 | 
					        $I->wantTo('get 204 if username not busy and not passed valid time mark, when it was busy');
 | 
				
			||||||
        $I->sendGET("{$url[0]}/klik201");
 | 
					        $I->sendGET("{$url[0]}/klik201");
 | 
				
			||||||
        $I->canSeeResponseCodeIs(204);
 | 
					        if (self::isModernEndpoint($url[0])) {
 | 
				
			||||||
        $I->canSeeResponseEquals('');
 | 
					            $I->canSeeResponseCodeIs(404);
 | 
				
			||||||
 | 
					            $I->canSeeResponseIsJson();
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'path' => "{$url[0]}/klik201",
 | 
				
			||||||
 | 
					                'errorMessage' => "Couldn't find any profile with name klik201",
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseCodeIs(204);
 | 
				
			||||||
 | 
					            $I->canSeeResponseEquals('');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @param Example<array{string}> $url
 | 
					     * @param \Codeception\Example<array{string}> $url
 | 
				
			||||||
     * @dataProvider endpoints
 | 
					     * @dataProvider endpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidByWrongUsername(FunctionalTester $I, Example $url): void {
 | 
					    public function getUuidByWrongUsername(FunctionalTester $I, Example $url): void {
 | 
				
			||||||
        $I->wantTo('get user uuid by some wrong username');
 | 
					        $I->wantTo('get user uuid by some wrong username');
 | 
				
			||||||
        $I->sendGET("{$url[0]}/not-exists-user");
 | 
					        $I->sendGET("{$url[0]}/not-exists-user");
 | 
				
			||||||
        $I->canSeeResponseCodeIs(204);
 | 
					        if (self::isModernEndpoint($url[0])) {
 | 
				
			||||||
        $I->canSeeResponseEquals('');
 | 
					            $I->canSeeResponseCodeIs(404);
 | 
				
			||||||
 | 
					            $I->canSeeResponseIsJson();
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'path' => "{$url[0]}/not-exists-user",
 | 
				
			||||||
 | 
					                'errorMessage' => "Couldn't find any profile with name not-exists-user",
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseCodeIs(204);
 | 
				
			||||||
 | 
					            $I->canSeeResponseEquals('');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @param Example<array{string}> $url
 | 
					     * @param \Codeception\Example<array{string}> $url
 | 
				
			||||||
     * @dataProvider endpoints
 | 
					     * @dataProvider endpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidForDeletedAccount(FunctionalTester $I, Example $url): void {
 | 
					    public function getUuidForDeletedAccount(FunctionalTester $I, Example $url): void {
 | 
				
			||||||
        $I->wantTo('get uuid for account that marked for deleting');
 | 
					        $I->wantTo('get uuid for account that marked for deleting');
 | 
				
			||||||
        $I->sendGET("{$url[0]}/DeletedAccount");
 | 
					        $I->sendGET("{$url[0]}/DeletedAccount");
 | 
				
			||||||
        $I->canSeeResponseCodeIs(204);
 | 
					        if (self::isModernEndpoint($url[0])) {
 | 
				
			||||||
        $I->canSeeResponseEquals('');
 | 
					            $I->canSeeResponseCodeIs(404);
 | 
				
			||||||
 | 
					            $I->canSeeResponseIsJson();
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'path' => "{$url[0]}/DeletedAccount",
 | 
				
			||||||
 | 
					                'errorMessage' => "Couldn't find any profile with name DeletedAccount",
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseCodeIs(204);
 | 
				
			||||||
 | 
					            $I->canSeeResponseEquals('');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    public function legacyNonPassedUsername(FunctionalTester $I): void {
 | 
				
			||||||
     * @param Example<array{string}> $url
 | 
					        $I->wantTo('get 404 if no username is passed on old endpoint');
 | 
				
			||||||
     * @dataProvider endpoints
 | 
					        $I->sendGET('/api/mojang/profiles');
 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function nonPassedUsername(FunctionalTester $I, Example $url): void {
 | 
					 | 
				
			||||||
        $I->wantTo('get 404 on not passed username');
 | 
					 | 
				
			||||||
        $I->sendGET($url[0]);
 | 
					 | 
				
			||||||
        $I->canSeeResponseCodeIs(404);
 | 
					        $I->canSeeResponseCodeIs(404);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getUuidForIncompletePath(FunctionalTester $I): void {
 | 
				
			||||||
 | 
					        $I->sendGET('/api/mojang/services/minecraft/profile/lookup/name');
 | 
				
			||||||
 | 
					        $I->canSeeResponseCodeIs(400);
 | 
				
			||||||
 | 
					        $I->canSeeResponseIsJson();
 | 
				
			||||||
 | 
					        $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					            'path' => '/api/mojang/services/minecraft/profile/lookup/name',
 | 
				
			||||||
 | 
					            'error' => 'CONSTRAINT_VIOLATION',
 | 
				
			||||||
 | 
					            'errorMessage' => 'Invalid UUID string: name',
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static function isModernEndpoint(string $url): bool {
 | 
				
			||||||
 | 
					        return str_contains($url, 'mojang/services');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,23 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
namespace api\tests\functional\authserver;
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace api\tests\functional\mojang;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use api\tests\FunctionalTester;
 | 
					use api\tests\FunctionalTester;
 | 
				
			||||||
use Codeception\Example;
 | 
					use Codeception\Example;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UsernamesToUuidsCest {
 | 
					final class UsernamesToUuidsCest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @return iterable<array{string}>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function bulkProfilesEndpoints(): iterable {
 | 
				
			||||||
 | 
					        yield ['/api/mojang/profiles'];
 | 
				
			||||||
 | 
					        yield ['/api/mojang/services/minecraft/profile/lookup/bulk/byname'];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidByOneUsername(FunctionalTester $I, Example $case): void {
 | 
					    public function getUuidByOneUsername(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -23,6 +34,7 @@ class UsernamesToUuidsCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidsByUsernames(FunctionalTester $I, Example $case): void {
 | 
					    public function getUuidsByUsernames(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -32,6 +44,7 @@ class UsernamesToUuidsCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidsByUsernamesWithPostString(FunctionalTester $I, Example $case): void {
 | 
					    public function getUuidsByUsernamesWithPostString(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -42,6 +55,7 @@ class UsernamesToUuidsCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUuidsByPartialNonexistentUsernames(FunctionalTester $I, Example $case): void {
 | 
					    public function getUuidsByPartialNonexistentUsernames(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -60,6 +74,7 @@ class UsernamesToUuidsCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function passAllNonexistentUsernames(FunctionalTester $I, Example $case): void {
 | 
					    public function passAllNonexistentUsernames(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -71,6 +86,7 @@ class UsernamesToUuidsCest {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function passTooManyUsernames(FunctionalTester $I, Example $case): void {
 | 
					    public function passTooManyUsernames(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -84,13 +100,22 @@ class UsernamesToUuidsCest {
 | 
				
			|||||||
        $I->sendPost($case[0], $usernames);
 | 
					        $I->sendPost($case[0], $usernames);
 | 
				
			||||||
        $I->canSeeResponseCodeIs(400);
 | 
					        $I->canSeeResponseCodeIs(400);
 | 
				
			||||||
        $I->canSeeResponseIsJson();
 | 
					        $I->canSeeResponseIsJson();
 | 
				
			||||||
        $I->canSeeResponseContainsJson([
 | 
					        if (self::isModernEndpoint($case[0])) {
 | 
				
			||||||
            'error' => 'IllegalArgumentException',
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
            'errorMessage' => 'Not more that 100 profile name per call is allowed.',
 | 
					                'path' => $case[0],
 | 
				
			||||||
        ]);
 | 
					                'error' => 'CONSTRAINT_VIOLATION',
 | 
				
			||||||
 | 
					                'errorMessage' => 'size must be between 1 and 100',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'error' => 'IllegalArgumentException',
 | 
				
			||||||
 | 
					                'errorMessage' => 'Not more that 100 profile name per call is allowed.',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function passEmptyUsername(FunctionalTester $I, Example $case): void {
 | 
					    public function passEmptyUsername(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -98,13 +123,22 @@ class UsernamesToUuidsCest {
 | 
				
			|||||||
        $I->sendPost($case[0], ['Admin', '']);
 | 
					        $I->sendPost($case[0], ['Admin', '']);
 | 
				
			||||||
        $I->canSeeResponseCodeIs(400);
 | 
					        $I->canSeeResponseCodeIs(400);
 | 
				
			||||||
        $I->canSeeResponseIsJson();
 | 
					        $I->canSeeResponseIsJson();
 | 
				
			||||||
        $I->canSeeResponseContainsJson([
 | 
					        if (self::isModernEndpoint($case[0])) {
 | 
				
			||||||
            'error' => 'IllegalArgumentException',
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
            'errorMessage' => 'profileName can not be null, empty or array key.',
 | 
					                'path' => $case[0],
 | 
				
			||||||
        ]);
 | 
					                'error' => 'CONSTRAINT_VIOLATION',
 | 
				
			||||||
 | 
					                'errorMessage' => 'Invalid profile name',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'error' => 'IllegalArgumentException',
 | 
				
			||||||
 | 
					                'errorMessage' => 'profileName can not be null, empty or array key.',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param \Codeception\Example<array{string}> $case
 | 
				
			||||||
     * @dataProvider bulkProfilesEndpoints
 | 
					     * @dataProvider bulkProfilesEndpoints
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function passEmptyField(FunctionalTester $I, Example $case): void {
 | 
					    public function passEmptyField(FunctionalTester $I, Example $case): void {
 | 
				
			||||||
@@ -112,17 +146,22 @@ class UsernamesToUuidsCest {
 | 
				
			|||||||
        $I->sendPost($case[0], []);
 | 
					        $I->sendPost($case[0], []);
 | 
				
			||||||
        $I->canSeeResponseCodeIs(400);
 | 
					        $I->canSeeResponseCodeIs(400);
 | 
				
			||||||
        $I->canSeeResponseIsJson();
 | 
					        $I->canSeeResponseIsJson();
 | 
				
			||||||
        $I->canSeeResponseContainsJson([
 | 
					        if (self::isModernEndpoint($case[0])) {
 | 
				
			||||||
            'error' => 'IllegalArgumentException',
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
            'errorMessage' => 'Passed array of profile names is an invalid JSON string.',
 | 
					                'path' => $case[0],
 | 
				
			||||||
        ]);
 | 
					                'error' => 'CONSTRAINT_VIOLATION',
 | 
				
			||||||
 | 
					                'errorMessage' => 'size must be between 1 and 100',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					                'error' => 'IllegalArgumentException',
 | 
				
			||||||
 | 
					                'errorMessage' => 'Passed array of profile names is an invalid JSON string.',
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function bulkProfilesEndpoints(): array {
 | 
					    private static function isModernEndpoint(string $url): bool {
 | 
				
			||||||
        return [
 | 
					        return str_contains($url, 'mojang/services');
 | 
				
			||||||
            ['/api/mojang/profiles'],
 | 
					 | 
				
			||||||
            ['/api/mojang/services/minecraft/profile/lookup/bulk/byname'],
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private function validateFewValidUsernames(FunctionalTester $I): void {
 | 
					    private function validateFewValidUsernames(FunctionalTester $I): void {
 | 
				
			||||||
							
								
								
									
										58
									
								
								api/tests/functional/mojang/UuidToUsernameCest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								api/tests/functional/mojang/UuidToUsernameCest.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					declare(strict_types=1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace api\tests\functional\mojang;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use api\tests\FunctionalTester;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final class UuidToUsernameCest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getUsernameByUuid(FunctionalTester $I): void {
 | 
				
			||||||
 | 
					        $I->sendGET('/api/mojang/services/minecraft/profile/lookup/df936908b2e1544d96f82977ec213022');
 | 
				
			||||||
 | 
					        $I->canSeeResponseCodeIs(200);
 | 
				
			||||||
 | 
					        $I->canSeeResponseIsJson();
 | 
				
			||||||
 | 
					        $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					            'id' => 'df936908b2e1544d96f82977ec213022',
 | 
				
			||||||
 | 
					            'name' => 'Admin',
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getUsernameByInvalidUuid(FunctionalTester $I): void {
 | 
				
			||||||
 | 
					        $I->sendGET('/api/mojang/services/minecraft/profile/lookup/123ABC');
 | 
				
			||||||
 | 
					        $I->canSeeResponseCodeIs(400);
 | 
				
			||||||
 | 
					        $I->canSeeResponseIsJson();
 | 
				
			||||||
 | 
					        $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					            'path' => '/api/mojang/services/minecraft/profile/lookup/123ABC',
 | 
				
			||||||
 | 
					            'error' => 'CONSTRAINT_VIOLATION',
 | 
				
			||||||
 | 
					            'errorMessage' => 'Invalid UUID string: 123ABC',
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getUsernameByWrongUuid(FunctionalTester $I): void {
 | 
				
			||||||
 | 
					        $I->sendGET('/api/mojang/services/minecraft/profile/lookup/644b25a8-1b0e-46a8-ad2a-97b53ecbb0a2');
 | 
				
			||||||
 | 
					        $I->canSeeResponseCodeIs(404);
 | 
				
			||||||
 | 
					        $I->canSeeResponseIsJson();
 | 
				
			||||||
 | 
					        $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					            'path' => '/api/mojang/services/minecraft/profile/lookup/644b25a8-1b0e-46a8-ad2a-97b53ecbb0a2',
 | 
				
			||||||
 | 
					            'error' => 'NOT_FOUND',
 | 
				
			||||||
 | 
					            'errorMessage' => 'Not Found',
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function getUuidForDeletedAccount(FunctionalTester $I): void {
 | 
				
			||||||
 | 
					        $I->sendGET('/api/mojang/services/minecraft/profile/lookup/6383de63-8f85-4ed5-92b7-5401a1fa68cd');
 | 
				
			||||||
 | 
					        $I->canSeeResponseCodeIs(404);
 | 
				
			||||||
 | 
					        $I->canSeeResponseIsJson();
 | 
				
			||||||
 | 
					        $I->canSeeResponseContainsJson([
 | 
				
			||||||
 | 
					            'path' => '/api/mojang/services/minecraft/profile/lookup/6383de63-8f85-4ed5-92b7-5401a1fa68cd',
 | 
				
			||||||
 | 
					            'error' => 'NOT_FOUND',
 | 
				
			||||||
 | 
					            'errorMessage' => 'Not Found',
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function nonPassedUuid(FunctionalTester $I): void {
 | 
				
			||||||
 | 
					        $I->sendGET('/api/mojang/services/minecraft/profile/lookup/');
 | 
				
			||||||
 | 
					        $I->canSeeResponseCodeIs(404);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -405,36 +405,6 @@ parameters:
 | 
				
			|||||||
			count: 1
 | 
								count: 1
 | 
				
			||||||
			path: api/modules/internal/controllers/AccountsController.php
 | 
								path: api/modules/internal/controllers/AccountsController.php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Call to an undefined method yii\\\\console\\\\Response\\|yii\\\\web\\\\Response\\:\\:setStatusCode\\(\\)\\.$#"
 | 
					 | 
				
			||||||
			count: 2
 | 
					 | 
				
			||||||
			path: api/modules/mojang/controllers/ApiController.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\modules\\\\mojang\\\\controllers\\\\ApiController\\:\\:actionUsernamesByUuid\\(\\) has no return type specified\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/modules/mojang/controllers/ApiController.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\modules\\\\mojang\\\\controllers\\\\ApiController\\:\\:actionUuidByUsername\\(\\) has no return type specified\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/modules/mojang/controllers/ApiController.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\modules\\\\mojang\\\\controllers\\\\ApiController\\:\\:actionUuidsByUsernames\\(\\) has no return type specified\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/modules/mojang/controllers/ApiController.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\modules\\\\mojang\\\\controllers\\\\ApiController\\:\\:illegalArgumentResponse\\(\\) has no return type specified\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/modules/mojang/controllers/ApiController.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\modules\\\\mojang\\\\controllers\\\\ApiController\\:\\:noContentResponse\\(\\) has no return type specified\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/modules/mojang/controllers/ApiController.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
							-
 | 
				
			||||||
			message: "#^Method api\\\\modules\\\\oauth\\\\controllers\\\\AuthorizationController\\:\\:verbs\\(\\) return type has no value type specified in iterable type array\\.$#"
 | 
								message: "#^Method api\\\\modules\\\\oauth\\\\controllers\\\\AuthorizationController\\:\\:verbs\\(\\) return type has no value type specified in iterable type array\\.$#"
 | 
				
			||||||
			count: 1
 | 
								count: 1
 | 
				
			||||||
@@ -750,51 +720,6 @@ parameters:
 | 
				
			|||||||
			count: 1
 | 
								count: 1
 | 
				
			||||||
			path: api/tests/functional/authlibInjector/JoinCest.php
 | 
								path: api/tests/functional/authlibInjector/JoinCest.php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\MinecraftProfilesCest\\:\\:bulkProfilesEndpoints\\(\\) return type has no value type specified in iterable type array\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authlibInjector/MinecraftProfilesCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\MinecraftProfilesCest\\:\\:getUuidByOneUsername\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authlibInjector/MinecraftProfilesCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\MinecraftProfilesCest\\:\\:getUuidsByPartialNonexistentUsernames\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authlibInjector/MinecraftProfilesCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\MinecraftProfilesCest\\:\\:getUuidsByUsernames\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authlibInjector/MinecraftProfilesCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\MinecraftProfilesCest\\:\\:getUuidsByUsernamesWithPostString\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authlibInjector/MinecraftProfilesCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\MinecraftProfilesCest\\:\\:passAllNonexistentUsernames\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authlibInjector/MinecraftProfilesCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\MinecraftProfilesCest\\:\\:passEmptyField\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authlibInjector/MinecraftProfilesCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\MinecraftProfilesCest\\:\\:passEmptyUsername\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authlibInjector/MinecraftProfilesCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\MinecraftProfilesCest\\:\\:passTooManyUsernames\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authlibInjector/MinecraftProfilesCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
							-
 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\ProfileCest\\:\\:getProfile\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
								message: "#^Method api\\\\tests\\\\functional\\\\authlibInjector\\\\ProfileCest\\:\\:getProfile\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
				
			||||||
			count: 1
 | 
								count: 1
 | 
				
			||||||
@@ -815,51 +740,6 @@ parameters:
 | 
				
			|||||||
			count: 1
 | 
								count: 1
 | 
				
			||||||
			path: api/tests/functional/authserver/RefreshCest.php
 | 
								path: api/tests/functional/authserver/RefreshCest.php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authserver\\\\UsernamesToUuidsCest\\:\\:bulkProfilesEndpoints\\(\\) return type has no value type specified in iterable type array\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authserver/UsernamesToUuidsCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authserver\\\\UsernamesToUuidsCest\\:\\:getUuidByOneUsername\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authserver/UsernamesToUuidsCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authserver\\\\UsernamesToUuidsCest\\:\\:getUuidsByPartialNonexistentUsernames\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authserver/UsernamesToUuidsCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authserver\\\\UsernamesToUuidsCest\\:\\:getUuidsByUsernames\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authserver/UsernamesToUuidsCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authserver\\\\UsernamesToUuidsCest\\:\\:getUuidsByUsernamesWithPostString\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authserver/UsernamesToUuidsCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authserver\\\\UsernamesToUuidsCest\\:\\:passAllNonexistentUsernames\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authserver/UsernamesToUuidsCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authserver\\\\UsernamesToUuidsCest\\:\\:passEmptyField\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authserver/UsernamesToUuidsCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authserver\\\\UsernamesToUuidsCest\\:\\:passEmptyUsername\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authserver/UsernamesToUuidsCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
					 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\authserver\\\\UsernamesToUuidsCest\\:\\:passTooManyUsernames\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
					 | 
				
			||||||
			count: 1
 | 
					 | 
				
			||||||
			path: api/tests/functional/authserver/UsernamesToUuidsCest.php
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		-
 | 
							-
 | 
				
			||||||
			message: "#^Method api\\\\tests\\\\functional\\\\sessionserver\\\\ProfileCest\\:\\:getProfile\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
								message: "#^Method api\\\\tests\\\\functional\\\\sessionserver\\\\ProfileCest\\:\\:getProfile\\(\\) has parameter \\$case with no value type specified in iterable type Codeception\\\\Example\\.$#"
 | 
				
			||||||
			count: 1
 | 
								count: 1
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user