Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pterodactyl
GitHub Repository: pterodactyl/panel
Path: blob/1.0-develop/tests/Integration/Api/Client/ClientControllerTest.php
14044 views
1
<?php
2
3
namespace Pterodactyl\Tests\Integration\Api\Client;
4
5
use Ramsey\Uuid\Uuid;
6
use Pterodactyl\Models\User;
7
use Pterodactyl\Models\Server;
8
use Pterodactyl\Models\Subuser;
9
use Pterodactyl\Models\Allocation;
10
use Pterodactyl\Models\Permission;
11
12
class ClientControllerTest extends ClientApiIntegrationTestCase
13
{
14
/**
15
* Test that only the servers a logged-in user is assigned to are returned by the
16
* API endpoint. Obviously there are cases such as being an administrator or being
17
* a subuser, but for this test we just want to test a basic scenario and pretend
18
* subusers do not exist at all.
19
*/
20
public function testOnlyLoggedInUsersServersAreReturned()
21
{
22
/** @var \Pterodactyl\Models\User[] $users */
23
$users = User::factory()->times(3)->create();
24
25
/** @var \Pterodactyl\Models\Server[] $servers */
26
$servers = [
27
$this->createServerModel(['user_id' => $users[0]->id]),
28
$this->createServerModel(['user_id' => $users[1]->id]),
29
$this->createServerModel(['user_id' => $users[2]->id]),
30
];
31
32
$response = $this->actingAs($users[0])->getJson('/api/client');
33
34
$response->assertOk();
35
$response->assertJsonPath('object', 'list');
36
$response->assertJsonPath('data.0.object', Server::RESOURCE_NAME);
37
$response->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort);
38
$response->assertJsonPath('data.0.attributes.server_owner', true);
39
$response->assertJsonPath('meta.pagination.total', 1);
40
$response->assertJsonPath('meta.pagination.per_page', 50);
41
}
42
43
/**
44
* Test that using ?filter[*]=name|uuid returns any server matching that name or UUID
45
* with the search filters.
46
*/
47
public function testServersAreFilteredUsingNameAndUuidInformation()
48
{
49
/** @var \Pterodactyl\Models\User[] $users */
50
$users = User::factory()->times(2)->create();
51
$users[0]->update(['root_admin' => true]);
52
53
/** @var \Pterodactyl\Models\Server[] $servers */
54
$servers = [
55
$this->createServerModel(['user_id' => $users[0]->id, 'name' => 'Julia']),
56
$this->createServerModel(['user_id' => $users[1]->id, 'uuidShort' => '12121212', 'name' => 'Janice']),
57
$this->createServerModel(['user_id' => $users[1]->id, 'uuid' => Uuid::uuid4()->toString(), 'external_id' => 'ext123', 'name' => 'Julia']),
58
$this->createServerModel(['user_id' => $users[1]->id, 'uuid' => Uuid::uuid4()->toString(), 'name' => 'Jennifer']),
59
];
60
61
$this->actingAs($users[1])->getJson('/api/client?filter[*]=Julia')
62
->assertOk()
63
->assertJsonCount(1, 'data')
64
->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);
65
66
$this->actingAs($users[1])->getJson('/api/client?filter[*]=ext123')
67
->assertOk()
68
->assertJsonCount(1, 'data')
69
->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);
70
71
$this->actingAs($users[1])->getJson('/api/client?filter[*]=ext123')
72
->assertOk()
73
->assertJsonCount(1, 'data')
74
->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);
75
76
$this->actingAs($users[1])->getJson('/api/client?filter[*]=12121212')
77
->assertOk()
78
->assertJsonCount(1, 'data')
79
->assertJsonPath('data.0.attributes.identifier', $servers[1]->uuidShort);
80
81
$this->actingAs($users[1])->getJson("/api/client?filter[*]={$servers[2]->uuidShort}")
82
->assertOk()
83
->assertJsonCount(1, 'data')
84
->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);
85
86
$this->actingAs($users[1])->getJson('/api/client?filter[*]=88788878-abcd')
87
->assertOk()
88
->assertJsonCount(0, 'data');
89
90
$this->actingAs($users[0])->getJson('/api/client?filter[*]=Julia&type=admin-all')
91
->assertOk()
92
->assertJsonCount(2, 'data')
93
->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort)
94
->assertJsonPath('data.1.attributes.identifier', $servers[2]->uuidShort);
95
}
96
97
/**
98
* Test that using ?filter[*]=:25565 or ?filter[*]=192.168.1.1:25565 returns only those servers
99
* with the same allocation for the given user.
100
*/
101
public function testServersAreFilteredUsingAllocationInformation()
102
{
103
/** @var User $user */
104
/** @var Server $server */
105
[$user, $server] = $this->generateTestAccount();
106
$server2 = $this->createServerModel(['user_id' => $user->id, 'node_id' => $server->node_id]);
107
108
$allocation = Allocation::factory()->create(['node_id' => $server->node_id, 'server_id' => $server->id, 'ip' => '192.168.1.1', 'port' => 25565]);
109
$allocation2 = Allocation::factory()->create(['node_id' => $server->node_id, 'server_id' => $server2->id, 'ip' => '192.168.1.1', 'port' => 25570]);
110
111
$server->update(['allocation_id' => $allocation->id]);
112
$server2->update(['allocation_id' => $allocation2->id]);
113
114
$server->refresh();
115
$server2->refresh();
116
117
$this->actingAs($user)->getJson('/api/client?filter[*]=192.168.1.1')
118
->assertOk()
119
->assertJsonCount(2, 'data')
120
->assertJsonPath('data.0.attributes.identifier', $server->uuidShort)
121
->assertJsonPath('data.1.attributes.identifier', $server2->uuidShort);
122
123
$this->actingAs($user)->getJson('/api/client?filter[*]=192.168.1.1:25565')
124
->assertOk()
125
->assertJsonCount(1, 'data')
126
->assertJsonPath('data.0.attributes.identifier', $server->uuidShort);
127
128
$this->actingAs($user)->getJson('/api/client?filter[*]=:25570')
129
->assertOk()
130
->assertJsonCount(1, 'data')
131
->assertJsonPath('data.0.attributes.identifier', $server2->uuidShort);
132
133
$this->actingAs($user)->getJson('/api/client?filter[*]=:255')
134
->assertOk()
135
->assertJsonCount(2, 'data')
136
->assertJsonPath('data.0.attributes.identifier', $server->uuidShort)
137
->assertJsonPath('data.1.attributes.identifier', $server2->uuidShort);
138
}
139
140
/**
141
* Test that servers where the user is a subuser are returned by default in the API call.
142
*/
143
public function testServersUserIsASubuserOfAreReturned()
144
{
145
/** @var \Pterodactyl\Models\User[] $users */
146
$users = User::factory()->times(3)->create();
147
$servers = [
148
$this->createServerModel(['user_id' => $users[0]->id]),
149
$this->createServerModel(['user_id' => $users[1]->id]),
150
$this->createServerModel(['user_id' => $users[2]->id]),
151
];
152
153
// Set user 0 as a subuser of server 1. Thus, we should get two servers
154
// back in the response when making the API call as user 0.
155
Subuser::query()->create([
156
'user_id' => $users[0]->id,
157
'server_id' => $servers[1]->id,
158
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
159
]);
160
161
$response = $this->actingAs($users[0])->getJson('/api/client');
162
163
$response->assertOk();
164
$response->assertJsonCount(2, 'data');
165
$response->assertJsonPath('data.0.attributes.server_owner', true);
166
$response->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort);
167
$response->assertJsonPath('data.1.attributes.server_owner', false);
168
$response->assertJsonPath('data.1.attributes.identifier', $servers[1]->uuidShort);
169
}
170
171
/**
172
* Returns only servers that the user owns, not servers they are a subuser of.
173
*/
174
public function testFilterOnlyOwnerServers()
175
{
176
/** @var \Pterodactyl\Models\User[] $users */
177
$users = User::factory()->times(3)->create();
178
$servers = [
179
$this->createServerModel(['user_id' => $users[0]->id]),
180
$this->createServerModel(['user_id' => $users[1]->id]),
181
$this->createServerModel(['user_id' => $users[2]->id]),
182
];
183
184
// Set user 0 as a subuser of server 1. Thus, we should get two servers
185
// back in the response when making the API call as user 0.
186
Subuser::query()->create([
187
'user_id' => $users[0]->id,
188
'server_id' => $servers[1]->id,
189
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
190
]);
191
192
$response = $this->actingAs($users[0])->getJson('/api/client?type=owner');
193
194
$response->assertOk();
195
$response->assertJsonCount(1, 'data');
196
$response->assertJsonPath('data.0.attributes.server_owner', true);
197
$response->assertJsonPath('data.0.attributes.identifier', $servers[0]->uuidShort);
198
}
199
200
/**
201
* Tests that the permissions from the Panel are returned correctly.
202
*/
203
public function testPermissionsAreReturned()
204
{
205
/** @var User $user */
206
$user = User::factory()->create();
207
208
$this->actingAs($user)
209
->getJson('/api/client/permissions')
210
->assertOk()
211
->assertJson([
212
'object' => 'system_permissions',
213
'attributes' => [
214
'permissions' => Permission::permissions()->toArray(),
215
],
216
]);
217
}
218
219
/**
220
* Test that only servers a user can access because they are an administrator are returned. This
221
* will always exclude any servers they can see because they're the owner or a subuser of the server.
222
*/
223
public function testOnlyAdminLevelServersAreReturned()
224
{
225
/** @var \Pterodactyl\Models\User[] $users */
226
$users = User::factory()->times(4)->create();
227
$users[0]->update(['root_admin' => true]);
228
229
$servers = [
230
$this->createServerModel(['user_id' => $users[0]->id]),
231
$this->createServerModel(['user_id' => $users[1]->id]),
232
$this->createServerModel(['user_id' => $users[2]->id]),
233
$this->createServerModel(['user_id' => $users[3]->id]),
234
];
235
236
Subuser::query()->create([
237
'user_id' => $users[0]->id,
238
'server_id' => $servers[1]->id,
239
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
240
]);
241
242
// Only servers 2 & 3 (0 indexed) should be returned by the API at this point. The user making
243
// the request is the owner of server 0, and a subuser of server 1, so they should be excluded.
244
$response = $this->actingAs($users[0])->getJson('/api/client?type=admin');
245
246
$response->assertOk();
247
$response->assertJsonCount(2, 'data');
248
249
$response->assertJsonPath('data.0.attributes.server_owner', false);
250
$response->assertJsonPath('data.0.attributes.identifier', $servers[2]->uuidShort);
251
$response->assertJsonPath('data.1.attributes.server_owner', false);
252
$response->assertJsonPath('data.1.attributes.identifier', $servers[3]->uuidShort);
253
}
254
255
/**
256
* Test that all servers a user can access as an admin are returned if using ?filter=admin-all.
257
*/
258
public function testAllServersAreReturnedToAdmin()
259
{
260
/** @var \Pterodactyl\Models\User[] $users */
261
$users = User::factory()->times(4)->create();
262
$users[0]->update(['root_admin' => true]);
263
264
$servers = [
265
$this->createServerModel(['user_id' => $users[0]->id]),
266
$this->createServerModel(['user_id' => $users[1]->id]),
267
$this->createServerModel(['user_id' => $users[2]->id]),
268
$this->createServerModel(['user_id' => $users[3]->id]),
269
];
270
271
Subuser::query()->create([
272
'user_id' => $users[0]->id,
273
'server_id' => $servers[1]->id,
274
'permissions' => [Permission::ACTION_WEBSOCKET_CONNECT],
275
]);
276
277
// All servers should be returned.
278
$response = $this->actingAs($users[0])->getJson('/api/client?type=admin-all');
279
280
$response->assertOk();
281
$response->assertJsonCount(4, 'data');
282
}
283
284
/**
285
* Test that no servers get returned if the user requests all admin level servers by using
286
* ?type=admin or ?type=admin-all in the request.
287
*/
288
#[\PHPUnit\Framework\Attributes\DataProvider('filterTypeDataProvider')]
289
public function testNoServersAreReturnedIfAdminFilterIsPassedByRegularUser(string $type)
290
{
291
/** @var \Pterodactyl\Models\User[] $users */
292
$users = User::factory()->times(3)->create();
293
294
$this->createServerModel(['user_id' => $users[0]->id]);
295
$this->createServerModel(['user_id' => $users[1]->id]);
296
$this->createServerModel(['user_id' => $users[2]->id]);
297
298
$response = $this->actingAs($users[0])->getJson('/api/client?type=' . $type);
299
300
$response->assertOk();
301
$response->assertJsonCount(0, 'data');
302
}
303
304
/**
305
* Test that a subuser without the allocation.read permission is only able to see the primary
306
* allocation for the server.
307
*/
308
public function testOnlyPrimaryAllocationIsReturnedToSubuser()
309
{
310
/** @var Server $server */
311
[$user, $server] = $this->generateTestAccount([Permission::ACTION_WEBSOCKET_CONNECT]);
312
$server->allocation->notes = 'Test notes';
313
$server->allocation->save();
314
315
Allocation::factory()->times(2)->create([
316
'node_id' => $server->node_id,
317
'server_id' => $server->id,
318
]);
319
320
$server->refresh();
321
$response = $this->actingAs($user)->getJson('/api/client');
322
323
$response->assertOk();
324
$response->assertJsonCount(1, 'data');
325
$response->assertJsonPath('data.0.attributes.server_owner', false);
326
$response->assertJsonPath('data.0.attributes.uuid', $server->uuid);
327
$response->assertJsonCount(1, 'data.0.attributes.relationships.allocations.data');
328
$response->assertJsonPath('data.0.attributes.relationships.allocations.data.0.attributes.id', $server->allocation->id);
329
$response->assertJsonPath('data.0.attributes.relationships.allocations.data.0.attributes.notes', null);
330
}
331
332
public static function filterTypeDataProvider(): array
333
{
334
return [['admin'], ['admin-all']];
335
}
336
}
337
338