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