Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pterodactyl
GitHub Repository: pterodactyl/panel
Path: blob/1.0-develop/app/Http/Middleware/Api/Client/Server/ResourceBelongsToServer.php
10280 views
1
<?php
2
3
namespace Pterodactyl\Http\Middleware\Api\Client\Server;
4
5
use Illuminate\Http\Request;
6
use Pterodactyl\Models\Task;
7
use Pterodactyl\Models\User;
8
use Pterodactyl\Models\Backup;
9
use Pterodactyl\Models\Server;
10
use Pterodactyl\Models\Subuser;
11
use Pterodactyl\Models\Database;
12
use Pterodactyl\Models\Schedule;
13
use Pterodactyl\Models\Allocation;
14
use Illuminate\Database\Eloquent\Model;
15
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
16
17
class ResourceBelongsToServer
18
{
19
/**
20
* Looks at the request parameters to determine if the given resource belongs
21
* to the requested server. If not, a 404 error will be returned to the caller.
22
*
23
* This is critical to ensuring that all subsequent logic is using exactly the
24
* server that is expected, and that we're not accessing a resource completely
25
* unrelated to the server provided in the request.
26
*/
27
public function handle(Request $request, \Closure $next): mixed
28
{
29
$params = $request->route()->parameters();
30
if (! isset($params['server']) || !$params['server'] instanceof Server) {
31
throw new \InvalidArgumentException('This middleware cannot be used in a context that is missing a server in the parameters.');
32
}
33
34
/** @var Server $server */
35
$server = $request->route()->parameter('server');
36
$exception = new NotFoundHttpException('The requested resource was not found for this server.');
37
foreach ($params as $key => $model) {
38
// Specifically skip the server, we're just trying to see if all of the
39
// other resources are assigned to this server. Also skip anything that
40
// is not currently a Model instance since those will just end up being
41
// a 404 down the road.
42
if ($key === 'server' || !$model instanceof Model) {
43
continue;
44
}
45
46
switch (get_class($model)) {
47
// All of these models use "server_id" as the field key for the server
48
// they are assigned to, so the logic is identical for them all.
49
case Allocation::class:
50
case Backup::class:
51
case Database::class:
52
case Schedule::class:
53
case Subuser::class:
54
if ($model->server_id !== $server->id) {
55
throw $exception;
56
}
57
break;
58
// Regular users are a special case here as we need to make sure they're
59
// currently assigned as a subuser on the server.
60
case User::class:
61
$subuser = $server->subusers()->where('user_id', $model->id)->first();
62
if (is_null($subuser)) {
63
throw $exception;
64
}
65
// This is a special case to avoid an additional query being triggered
66
// in the underlying logic.
67
$request->attributes->set('subuser', $subuser);
68
break;
69
// Tasks are special since they're (currently) the only item in the API
70
// that requires something in addition to the server in order to be accessed.
71
case Task::class:
72
$schedule = $request->route()->parameter('schedule');
73
if (!$schedule instanceof Schedule || $model->schedule_id !== $schedule->id || $schedule->server_id !== $server->id) {
74
throw $exception;
75
}
76
break;
77
default:
78
// Don't return a 404 here since we want to make sure no one relies
79
// on this middleware in a context in which it will not work. Fail safe.
80
throw new \InvalidArgumentException('There is no handler configured for a resource of this type: ' . get_class($model));
81
}
82
}
83
84
return $next($request);
85
}
86
}
87
88