Path: blob/1.0-develop/tests/Integration/Api/Client/ClientControllerTest.php
14044 views
<?php12namespace Pterodactyl\Tests\Integration\Api\Client;34use Ramsey\Uuid\Uuid;5use Pterodactyl\Models\User;6use Pterodactyl\Models\Server;7use Pterodactyl\Models\Subuser;8use Pterodactyl\Models\Allocation;9use Pterodactyl\Models\Permission;1011class ClientControllerTest extends ClientApiIntegrationTestCase12{13/**14* Test that only the servers a logged-in user is assigned to are returned by the15* API endpoint. Obviously there are cases such as being an administrator or being16* a subuser, but for this test we just want to test a basic scenario and pretend17* subusers do not exist at all.18*/19public function testOnlyLoggedInUsersServersAreReturned()20{21/** @var \Pterodactyl\Models\User[] $users */22$users = User::factory()->times(3)->create();2324/** @var \Pterodactyl\Models\Server[] $servers */25$servers = [26$this->createServerModel(['user_id' => $users[0]->id]),27$this->createServerModel(['user_id' => $users[1]->id]),28$this->createServerModel(['user_id' => $users[2]->id]),29];3031$response = $this->actingAs($users[0])->getJson('/api/client');3233$response->assertOk();34$response->assertJsonPath('object', 'list');35$response->assertJsonPath('data.0.object', Server::RESOURCE_NAME);36$response->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort);37$response->assertJsonPath('data.0.attributes.server_owner', true);38$response->assertJsonPath('meta.pagination.total', 1);39$response->assertJsonPath('meta.pagination.per_page', 50);40}4142/**43* Test that using ?filter[*]=name|uuid returns any server matching that name or UUID44* with the search filters.45*/46public function testServersAreFilteredUsingNameAndUuidInformation()47{48/** @var \Pterodactyl\Models\User[] $users */49$users = User::factory()->times(2)->create();50$users[0]->update(['root_admin' => true]);5152/** @var \Pterodactyl\Models\Server[] $servers */53$servers = [54$this->createServerModel(['user_id' => $users[0]->id, 'name' => 'Julia']),55$this->createServerModel(['user_id' => $users[1]->id, 'uuidShort' => '12121212', 'name' => 'Janice']),56$this->createServerModel(['user_id' => $users[1]->id, 'uuid' => Uuid::uuid4()->toString(), 'external_id' => 'ext123', 'name' => 'Julia']),57$this->createServerModel(['user_id' => $users[1]->id, 'uuid' => Uuid::uuid4()->toString(), 'name' => 'Jennifer']),58];5960$this->actingAs($users[1])->getJson('/api/client?filter[*]=Julia')61->assertOk()62->assertJsonCount(1, 'data')63->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);6465$this->actingAs($users[1])->getJson('/api/client?filter[*]=ext123')66->assertOk()67->assertJsonCount(1, 'data')68->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);6970$this->actingAs($users[1])->getJson('/api/client?filter[*]=ext123')71->assertOk()72->assertJsonCount(1, 'data')73->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);7475$this->actingAs($users[1])->getJson('/api/client?filter[*]=12121212')76->assertOk()77->assertJsonCount(1, 'data')78->assertJsonPath('data.0.attributes.identifier', $servers[1]->uuidShort);7980$this->actingAs($users[1])->getJson("/api/client?filter[*]={$servers[2]->uuidShort}")81->assertOk()82->assertJsonCount(1, 'data')83->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);8485$this->actingAs($users[1])->getJson('/api/client?filter[*]=88788878-abcd')86->assertOk()87->assertJsonCount(0, 'data');8889$this->actingAs($users[0])->getJson('/api/client?filter[*]=Julia&type=admin-all')90->assertOk()91->assertJsonCount(2, 'data')92->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort)93->assertJsonPath('data.1.attributes.identifier', $servers[2]->uuidShort);94}9596/**97* Test that using ?filter[*]=:25565 or ?filter[*]=192.168.1.1:25565 returns only those servers98* with the same allocation for the given user.99*/100public function testServersAreFilteredUsingAllocationInformation()101{102/** @var User $user */103/** @var Server $server */104[$user, $server] = $this->generateTestAccount();105$server2 = $this->createServerModel(['user_id' => $user->id, 'node_id' => $server->node_id]);106107$allocation = Allocation::factory()->create(['node_id' => $server->node_id, 'server_id' => $server->id, 'ip' => '192.168.1.1', 'port' => 25565]);108$allocation2 = Allocation::factory()->create(['node_id' => $server->node_id, 'server_id' => $server2->id, 'ip' => '192.168.1.1', 'port' => 25570]);109110$server->update(['allocation_id' => $allocation->id]);111$server2->update(['allocation_id' => $allocation2->id]);112113$server->refresh();114$server2->refresh();115116$this->actingAs($user)->getJson('/api/client?filter[*]=192.168.1.1')117->assertOk()118->assertJsonCount(2, 'data')119->assertJsonPath('data.0.attributes.identifier', $server->uuidShort)120->assertJsonPath('data.1.attributes.identifier', $server2->uuidShort);121122$this->actingAs($user)->getJson('/api/client?filter[*]=192.168.1.1:25565')123->assertOk()124->assertJsonCount(1, 'data')125->assertJsonPath('data.0.attributes.identifier', $server->uuidShort);126127$this->actingAs($user)->getJson('/api/client?filter[*]=:25570')128->assertOk()129->assertJsonCount(1, 'data')130->assertJsonPath('data.0.attributes.identifier', $server2->uuidShort);131132$this->actingAs($user)->getJson('/api/client?filter[*]=:255')133->assertOk()134->assertJsonCount(2, 'data')135->assertJsonPath('data.0.attributes.identifier', $server->uuidShort)136->assertJsonPath('data.1.attributes.identifier', $server2->uuidShort);137}138139/**140* Test that servers where the user is a subuser are returned by default in the API call.141*/142public function testServersUserIsASubuserOfAreReturned()143{144/** @var \Pterodactyl\Models\User[] $users */145$users = User::factory()->times(3)->create();146$servers = [147$this->createServerModel(['user_id' => $users[0]->id]),148$this->createServerModel(['user_id' => $users[1]->id]),149$this->createServerModel(['user_id' => $users[2]->id]),150];151152// Set user 0 as a subuser of server 1. Thus, we should get two servers153// back in the response when making the API call as user 0.154Subuser::query()->create([155'user_id' => $users[0]->id,156'server_id' => $servers[1]->id,157'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],158]);159160$response = $this->actingAs($users[0])->getJson('/api/client');161162$response->assertOk();163$response->assertJsonCount(2, 'data');164$response->assertJsonPath('data.0.attributes.server_owner', true);165$response->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort);166$response->assertJsonPath('data.1.attributes.server_owner', false);167$response->assertJsonPath('data.1.attributes.identifier', $servers[1]->uuidShort);168}169170/**171* Returns only servers that the user owns, not servers they are a subuser of.172*/173public function testFilterOnlyOwnerServers()174{175/** @var \Pterodactyl\Models\User[] $users */176$users = User::factory()->times(3)->create();177$servers = [178$this->createServerModel(['user_id' => $users[0]->id]),179$this->createServerModel(['user_id' => $users[1]->id]),180$this->createServerModel(['user_id' => $users[2]->id]),181];182183// Set user 0 as a subuser of server 1. Thus, we should get two servers184// back in the response when making the API call as user 0.185Subuser::query()->create([186'user_id' => $users[0]->id,187'server_id' => $servers[1]->id,188'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],189]);190191$response = $this->actingAs($users[0])->getJson('/api/client?type=owner');192193$response->assertOk();194$response->assertJsonCount(1, 'data');195$response->assertJsonPath('data.0.attributes.server_owner', true);196$response->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort);197}198199/**200* Tests that the permissions from the Panel are returned correctly.201*/202public function testPermissionsAreReturned()203{204/** @var User $user */205$user = User::factory()->create();206207$this->actingAs($user)208->getJson('/api/client/permissions')209->assertOk()210->assertJson([211'object' => 'system_permissions',212'attributes' => [213'permissions' => Permission::permissions()->toArray(),214],215]);216}217218/**219* Test that only servers a user can access because they are an administrator are returned. This220* will always exclude any servers they can see because they're the owner or a subuser of the server.221*/222public function testOnlyAdminLevelServersAreReturned()223{224/** @var \Pterodactyl\Models\User[] $users */225$users = User::factory()->times(4)->create();226$users[0]->update(['root_admin' => true]);227228$servers = [229$this->createServerModel(['user_id' => $users[0]->id]),230$this->createServerModel(['user_id' => $users[1]->id]),231$this->createServerModel(['user_id' => $users[2]->id]),232$this->createServerModel(['user_id' => $users[3]->id]),233];234235Subuser::query()->create([236'user_id' => $users[0]->id,237'server_id' => $servers[1]->id,238'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],239]);240241// Only servers 2 & 3 (0 indexed) should be returned by the API at this point. The user making242// the request is the owner of server 0, and a subuser of server 1, so they should be excluded.243$response = $this->actingAs($users[0])->getJson('/api/client?type=admin');244245$response->assertOk();246$response->assertJsonCount(2, 'data');247248$response->assertJsonPath('data.0.attributes.server_owner', false);249$response->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);250$response->assertJsonPath('data.1.attributes.server_owner', false);251$response->assertJsonPath('data.1.attributes.identifier', $servers[3]->uuidShort);252}253254/**255* Test that all servers a user can access as an admin are returned if using ?filter=admin-all.256*/257public function testAllServersAreReturnedToAdmin()258{259/** @var \Pterodactyl\Models\User[] $users */260$users = User::factory()->times(4)->create();261$users[0]->update(['root_admin' => true]);262263$servers = [264$this->createServerModel(['user_id' => $users[0]->id]),265$this->createServerModel(['user_id' => $users[1]->id]),266$this->createServerModel(['user_id' => $users[2]->id]),267$this->createServerModel(['user_id' => $users[3]->id]),268];269270Subuser::query()->create([271'user_id' => $users[0]->id,272'server_id' => $servers[1]->id,273'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],274]);275276// All servers should be returned.277$response = $this->actingAs($users[0])->getJson('/api/client?type=admin-all');278279$response->assertOk();280$response->assertJsonCount(4, 'data');281}282283/**284* Test that no servers get returned if the user requests all admin level servers by using285* ?type=admin or ?type=admin-all in the request.286*/287#[\PHPUnit\Framework\Attributes\DataProvider('filterTypeDataProvider')]288public function testNoServersAreReturnedIfAdminFilterIsPassedByRegularUser(string $type)289{290/** @var \Pterodactyl\Models\User[] $users */291$users = User::factory()->times(3)->create();292293$this->createServerModel(['user_id' => $users[0]->id]);294$this->createServerModel(['user_id' => $users[1]->id]);295$this->createServerModel(['user_id' => $users[2]->id]);296297$response = $this->actingAs($users[0])->getJson('/api/client?type=' . $type);298299$response->assertOk();300$response->assertJsonCount(0, 'data');301}302303/**304* Test that a subuser without the allocation.read permission is only able to see the primary305* allocation for the server.306*/307public function testOnlyPrimaryAllocationIsReturnedToSubuser()308{309/** @var Server $server */310[$user, $server] = $this->generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]);311$server->allocation->notes = 'Test notes';312$server->allocation->save();313314Allocation::factory()->times(2)->create([315'node_id' => $server->node_id,316'server_id' => $server->id,317]);318319$server->refresh();320$response = $this->actingAs($user)->getJson('/api/client');321322$response->assertOk();323$response->assertJsonCount(1, 'data');324$response->assertJsonPath('data.0.attributes.server_owner', false);325$response->assertJsonPath('data.0.attributes.uuid', $server->uuid);326$response->assertJsonCount(1, 'data.0.attributes.relationships.allocations.data');327$response->assertJsonPath('data.0.attributes.relationships.allocations.data.0.attributes.id', $server->allocation->id);328$response->assertJsonPath('data.0.attributes.relationships.allocations.data.0.attributes.notes', null);329}330331public static function filterTypeDataProvider(): array332{333return [['admin'], ['admin-all']];334}335}336337338