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
This commit is contained in:
@@ -49,6 +49,7 @@ return [
|
||||
'GET /mojang/services/minecraft/profile' => 'mojang/services/profile',
|
||||
'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/<uuid>' => 'mojang/api/username-by-uuid',
|
||||
|
||||
// authlib-injector
|
||||
'/authlib-injector/authserver/<action>' => 'authserver/authentication/<action>',
|
||||
@@ -58,4 +59,5 @@ return [
|
||||
'/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/name/<username>' => 'mojang/api/uuid-by-username',
|
||||
'/authlib-injector/minecraftservices/minecraft/profile/lookup/<uuid>' => 'mojang/api/username-by-uuid',
|
||||
];
|
||||
|
@@ -27,7 +27,7 @@ class ApiController extends Controller {
|
||||
]);
|
||||
}
|
||||
|
||||
public function actionUuidByUsername(string $username, int $at = null) {
|
||||
public function actionUuidByUsername(string $username, int $at = null): Response|array {
|
||||
if ($at !== null) {
|
||||
/** @var UsernameHistory|null $record */
|
||||
$record = UsernameHistory::find()
|
||||
@@ -52,7 +52,7 @@ class ApiController extends Controller {
|
||||
}
|
||||
|
||||
if ($account === null || $account->status === Account::STATUS_DELETED) {
|
||||
return $this->noContentResponse();
|
||||
return $this->contentNotFound("Couldn't find any profile with name {$username}");
|
||||
}
|
||||
|
||||
return [
|
||||
@@ -61,16 +61,49 @@ class ApiController extends Controller {
|
||||
];
|
||||
}
|
||||
|
||||
public function actionUsernamesByUuid(string $uuid) {
|
||||
public function actionUsernameByUuid(string $uuid): Response|array {
|
||||
try {
|
||||
$uuid = Uuid::fromString($uuid)->toString();
|
||||
} catch (\InvalidArgumentException) {
|
||||
return $this->illegalArgumentResponse('Invalid uuid format.');
|
||||
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 actionUsernamesByUuid(string $uuid): Response|array {
|
||||
try {
|
||||
$uuid = Uuid::fromString($uuid)->toString();
|
||||
} catch (\InvalidArgumentException) {
|
||||
$response = Yii::$app->getResponse();
|
||||
$response->setStatusCode(400);
|
||||
$response->format = Response::FORMAT_JSON;
|
||||
$response->data = [
|
||||
'error' => 'IllegalArgumentException',
|
||||
'errorMessage' => 'Invalid uuid format.',
|
||||
];
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$account = Account::find()->excludeDeleted()->andWhere(['uuid' => $uuid])->one();
|
||||
if ($account === null) {
|
||||
return $this->noContentResponse();
|
||||
$response = Yii::$app->getResponse();
|
||||
$response->setStatusCode(204);
|
||||
$response->format = Response::FORMAT_RAW;
|
||||
$response->content = '';
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/** @var UsernameHistory[] $usernameHistory */
|
||||
@@ -93,20 +126,20 @@ class ApiController extends Controller {
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function actionUuidsByUsernames() {
|
||||
public function actionUuidsByUsernames(): Response|array {
|
||||
$usernames = Yii::$app->request->post();
|
||||
if (empty($usernames)) {
|
||||
return $this->illegalArgumentResponse('Passed array of profile names is an invalid JSON string.');
|
||||
return $this->constraintViolation('size must be between 1 and 100');
|
||||
}
|
||||
|
||||
$usernames = array_unique($usernames);
|
||||
if (count($usernames) > 100) {
|
||||
return $this->illegalArgumentResponse('Not more that 100 profile name per call is allowed.');
|
||||
return $this->constraintViolation('size must be between 1 and 100');
|
||||
}
|
||||
|
||||
foreach ($usernames as $username) {
|
||||
if (empty($username) || is_array($username)) {
|
||||
return $this->illegalArgumentResponse('profileName can not be null, empty or array key.');
|
||||
return $this->constraintViolation('Invalid profile name');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,21 +162,33 @@ class ApiController extends Controller {
|
||||
return $responseData;
|
||||
}
|
||||
|
||||
private function noContentResponse() {
|
||||
private function contentNotFound(string|null $errorMessage = null): Response {
|
||||
$response = Yii::$app->getResponse();
|
||||
$response->setStatusCode(204);
|
||||
$response->format = Response::FORMAT_RAW;
|
||||
$response->content = '';
|
||||
$response->setStatusCode(404);
|
||||
$response->format = Response::FORMAT_JSON;
|
||||
if ($errorMessage === null) {
|
||||
$response->data = [
|
||||
'path' => Yii::$app->getRequest()->url,
|
||||
'error' => 'NOT_FOUND',
|
||||
'errorMessage' => 'Not Found',
|
||||
];
|
||||
} else {
|
||||
$response->data = [
|
||||
'path' => Yii::$app->getRequest()->url,
|
||||
'errorMessage' => $errorMessage,
|
||||
];
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function illegalArgumentResponse(string $errorMessage) {
|
||||
private function constraintViolation(string $errorMessage): Response {
|
||||
$response = Yii::$app->getResponse();
|
||||
$response->setStatusCode(400);
|
||||
$response->format = Response::FORMAT_JSON;
|
||||
$response->data = [
|
||||
'error' => 'IllegalArgumentException',
|
||||
'path' => Yii::$app->getRequest()->url,
|
||||
'error' => 'CONSTRAINT_VIOLATION',
|
||||
'errorMessage' => $errorMessage,
|
||||
];
|
||||
|
||||
|
@@ -4,18 +4,16 @@ namespace api\tests\functional\mojang;
|
||||
use api\tests\FunctionalTester;
|
||||
use Codeception\Example;
|
||||
|
||||
final class UsernameToUuidCest {
|
||||
class UsernameToUuidCest {
|
||||
|
||||
/**
|
||||
* @return iterable<array{string}>
|
||||
*/
|
||||
public static function endpoints(): iterable {
|
||||
yield ['/api/mojang/profiles'];
|
||||
yield ['/api/mojang/services/minecraft/profile/lookup/name'];
|
||||
public static function endpoints(): array {
|
||||
return [
|
||||
['/api/mojang/profiles'],
|
||||
['/api/mojang/services/minecraft/profile/lookup/name'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Example<array{string}> $url
|
||||
* @dataProvider endpoints
|
||||
*/
|
||||
public function getUuidByUsername(FunctionalTester $I, Example $url): void {
|
||||
@@ -30,7 +28,6 @@ final class UsernameToUuidCest {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Example<array{string}> $url
|
||||
* @dataProvider endpoints
|
||||
*/
|
||||
public function getUuidByUsernameAtMoment(FunctionalTester $I, Example $url): void {
|
||||
@@ -45,57 +42,77 @@ final class UsernameToUuidCest {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Example<array{string}> $url
|
||||
* @dataProvider endpoints
|
||||
*/
|
||||
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->sendGET("{$url[0]}/klik201", ['at' => 1474404144]);
|
||||
$I->canSeeResponseCodeIs(204);
|
||||
$I->canSeeResponseEquals('');
|
||||
$I->canSeeResponseCodeIs(404);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'path' => "{$url[0]}/klik201?at=1474404144",
|
||||
'errorMessage' => "Couldn't find any profile with name klik201",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Example<array{string}> $url
|
||||
* @dataProvider endpoints
|
||||
*/
|
||||
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->sendGET("{$url[0]}/klik201");
|
||||
$I->canSeeResponseCodeIs(204);
|
||||
$I->canSeeResponseEquals('');
|
||||
$I->canSeeResponseCodeIs(404);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'path' => "{$url[0]}/klik201",
|
||||
'errorMessage' => "Couldn't find any profile with name klik201",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Example<array{string}> $url
|
||||
* @dataProvider endpoints
|
||||
*/
|
||||
public function getUuidByWrongUsername(FunctionalTester $I, Example $url): void {
|
||||
$I->wantTo('get user uuid by some wrong username');
|
||||
$I->sendGET("{$url[0]}/not-exists-user");
|
||||
$I->canSeeResponseCodeIs(204);
|
||||
$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",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Example<array{string}> $url
|
||||
* @dataProvider endpoints
|
||||
*/
|
||||
public function getUuidForDeletedAccount(FunctionalTester $I, Example $url): void {
|
||||
$I->wantTo('get uuid for account that marked for deleting');
|
||||
$I->sendGET("{$url[0]}/DeletedAccount");
|
||||
$I->canSeeResponseCodeIs(204);
|
||||
$I->canSeeResponseEquals('');
|
||||
$I->canSeeResponseCodeIs(404);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'path' => "{$url[0]}/DeletedAccount",
|
||||
'errorMessage' => "Couldn't find any profile with name DeletedAccount",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Example<array{string}> $url
|
||||
* @dataProvider endpoints
|
||||
*/
|
||||
public function nonPassedUsername(FunctionalTester $I, Example $url): void {
|
||||
$I->wantTo('get 404 on not passed username');
|
||||
$I->sendGET($url[0]);
|
||||
public function legacyNonPassedUsername(FunctionalTester $I): void {
|
||||
$I->wantTo('get 404 if no username is passed on old endpoint');
|
||||
$I->sendGET('/api/mojang/profiles');
|
||||
$I->canSeeResponseCodeIs(404);
|
||||
}
|
||||
|
||||
public function nonPassedUsername(FunctionalTester $I): void {
|
||||
$I->wantTo('get UUID error if no username is passed on new endpoint');
|
||||
$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",
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
namespace api\tests\functional\authserver;
|
||||
namespace api\tests\functional\mojang;
|
||||
|
||||
use api\tests\FunctionalTester;
|
||||
use Codeception\Example;
|
||||
@@ -85,8 +85,9 @@ class UsernamesToUuidsCest {
|
||||
$I->canSeeResponseCodeIs(400);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'IllegalArgumentException',
|
||||
'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',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -99,8 +100,9 @@ class UsernamesToUuidsCest {
|
||||
$I->canSeeResponseCodeIs(400);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'IllegalArgumentException',
|
||||
'errorMessage' => 'profileName can not be null, empty or array key.',
|
||||
'path' => $case[0],
|
||||
'error' => 'CONSTRAINT_VIOLATION',
|
||||
'errorMessage' => 'Invalid profile name',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -113,8 +115,9 @@ class UsernamesToUuidsCest {
|
||||
$I->canSeeResponseCodeIs(400);
|
||||
$I->canSeeResponseIsJson();
|
||||
$I->canSeeResponseContainsJson([
|
||||
'error' => 'IllegalArgumentException',
|
||||
'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',
|
||||
]);
|
||||
}
|
||||
|
61
api/tests/functional/mojang/UuidToUsernameCest.php
Normal file
61
api/tests/functional/mojang/UuidToUsernameCest.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace api\tests\functional\mojang;
|
||||
|
||||
use api\tests\FunctionalTester;
|
||||
|
||||
class UuidToUsernameCest {
|
||||
|
||||
public function getUsernameByUuid(FunctionalTester $I): void {
|
||||
$I->wantTo('get username by uuid');
|
||||
$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->wantTo('get username by invalid uuid');
|
||||
$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->wantTo('get username by wrong uuid');
|
||||
$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->wantTo('get username for account that marked for deleting');
|
||||
$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->wantTo('get 404 on not passed uuid');
|
||||
$I->sendGET("/api/mojang/services/minecraft/profile/lookup/");
|
||||
$I->canSeeResponseCodeIs(404);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user