Merge branch 'dane/sanctum' into v2

This commit is contained in:
Dane Everitt 2021-08-07 16:19:19 -07:00
commit 874e7afce3
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
253 changed files with 1480 additions and 3543 deletions

5
.gitignore vendored
View File

@ -46,7 +46,7 @@ yarn-error.log
# PHP # PHP
/vendor /vendor
.php_cs.cache .php-cs-fixer.cache
.phpunit.result.cache .phpunit.result.cache
_ide_helper.php _ide_helper.php
_ide_helper_models.php _ide_helper_models.php
@ -80,3 +80,6 @@ _ide_helper_models.php
!.env.example !.env.example
.env* .env*
*.log *.log
_ide_helper_models.php
_ide_helper.php
.phpstorm.meta.php

View File

@ -21,7 +21,7 @@ return (new Config())
'no_unreachable_default_argument_value' => true, 'no_unreachable_default_argument_value' => true,
'no_useless_return' => true, 'no_useless_return' => true,
'ordered_imports' => [ 'ordered_imports' => [
'sortAlgorithm' => 'length', 'sort_algorithm' => 'length',
], ],
'phpdoc_align' => [ 'phpdoc_align' => [
'align' => 'left', 'align' => 'left',

View File

@ -1,13 +0,0 @@
<?php
namespace Pterodactyl\Contracts\Http;
interface ClientPermissionsRequest
{
/**
* Returns the permissions string indicating which permission should be used to
* validate that the authenticated user has permission to perform this action aganist
* the given resource (server).
*/
public function permission(): string;
}

View File

@ -1,29 +0,0 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\User;
use Illuminate\Support\Collection;
interface ApiKeyRepositoryInterface extends RepositoryInterface
{
/**
* Get all of the account API keys that exist for a specific user.
*/
public function getAccountKeys(User $user): Collection;
/**
* Get all of the application API keys that exist for a specific user.
*/
public function getApplicationKeys(User $user): Collection;
/**
* Delete an account API key from the panel for a specific user.
*/
public function deleteAccountKey(User $user, string $identifier): int;
/**
* Delete an application API key from the panel for a specific user.
*/
public function deleteApplicationKey(User $user, string $identifier): int;
}

View File

@ -7,6 +7,7 @@ use Throwable;
use PDOException; use PDOException;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Http\Response;
use Swift_TransportException; use Swift_TransportException;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
@ -59,6 +60,16 @@ class Handler extends ExceptionHandler
'password_confirmation', 'password_confirmation',
]; ];
/**
* Maps specific internal exceptions to a valid HTTP status code.
*
* @var array
*/
protected static $statusCodeMap = [
AuthenticationException::class => Response::HTTP_UNAUTHORIZED,
ValidationException::class => Response::HTTP_UNPROCESSABLE_ENTITY,
];
/** /**
* Registers the exception handling callbacks for the application. This * Registers the exception handling callbacks for the application. This
* will capture specific exception types that we do not want to include * will capture specific exception types that we do not want to include
@ -191,7 +202,7 @@ class Handler extends ExceptionHandler
'code' => class_basename($exception), 'code' => class_basename($exception),
'status' => method_exists($exception, 'getStatusCode') 'status' => method_exists($exception, 'getStatusCode')
? strval($exception->getStatusCode()) ? strval($exception->getStatusCode())
: ($exception instanceof ValidationException ? '422' : '500'), : strval(self::$statusCodeMap[get_class($exception)] ?? 500),
'detail' => $exception instanceof HttpExceptionInterface 'detail' => $exception instanceof HttpExceptionInterface
? $exception->getMessage() ? $exception->getMessage()
: 'An unexpected error was encountered while processing this request, please try again.', : 'An unexpected error was encountered while processing this request, please try again.',
@ -212,6 +223,7 @@ class Handler extends ExceptionHandler
'file' => str_replace(Application::getInstance()->basePath(), '', $exception->getFile()), 'file' => str_replace(Application::getInstance()->basePath(), '', $exception->getFile()),
], ],
'meta' => [ 'meta' => [
'class' => get_class($exception),
'trace' => explode("\n", $exception->getTraceAsString()), 'trace' => explode("\n", $exception->getTraceAsString()),
], ],
]); ]);

View File

@ -1,9 +0,0 @@
<?php
namespace Pterodactyl\Exceptions\Transformer;
use Pterodactyl\Exceptions\PterodactylException;
class InvalidTransformerLevelException extends PterodactylException
{
}

View File

@ -0,0 +1,23 @@
<?php
namespace Pterodactyl\Extensions\Laravel\Sanctum;
use Pterodactyl\Models\PersonalAccessToken;
use Laravel\Sanctum\NewAccessToken as SanctumAccessToken;
/**
* @property \Pterodactyl\Models\PersonalAccessToken $accessToken
*/
class NewAccessToken extends SanctumAccessToken
{
/**
* NewAccessToken constructor.
*
* @noinspection PhpMissingParentConstructorInspection
*/
public function __construct(PersonalAccessToken $accessToken, string $plainTextToken)
{
$this->accessToken = $accessToken;
$this->plainTextToken = $plainTextToken;
}
}

View File

@ -2,8 +2,8 @@
namespace Pterodactyl\Extensions\Spatie\Fractalistic; namespace Pterodactyl\Extensions\Spatie\Fractalistic;
use League\Fractal\TransformerAbstract;
use Spatie\Fractal\Fractal as SpatieFractal; use Spatie\Fractal\Fractal as SpatieFractal;
use Pterodactyl\Transformers\Api\Transformer;
use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use League\Fractal\Pagination\IlluminatePaginatorAdapter; use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use Pterodactyl\Extensions\League\Fractal\Serializers\PterodactylSerializer; use Pterodactyl\Extensions\League\Fractal\Serializers\PterodactylSerializer;
@ -33,12 +33,9 @@ class Fractal extends SpatieFractal
// If the resource name is not set attempt to pull it off the transformer // If the resource name is not set attempt to pull it off the transformer
// itself and set it automatically. // itself and set it automatically.
if ( $class = is_string($this->transformer) ? new $this->transformer() : $this->transformer;
is_null($this->resourceName) if (is_null($this->resourceName) && $class instanceof Transformer) {
&& $this->transformer instanceof TransformerAbstract $this->resourceName = $class->getResourceName();
&& method_exists($this->transformer, 'getResourceName')
) {
$this->resourceName = $this->transformer->getResourceName();
} }
return parent::createData(); return parent::createData();

View File

@ -9,8 +9,6 @@ class BaseController extends Controller
{ {
/** /**
* Return the admin index view. * Return the admin index view.
*
* @return \Illuminate\View\View
*/ */
public function index(): View public function index(): View
{ {

View File

@ -3,17 +3,16 @@
namespace Pterodactyl\Http\Controllers\Api\Application; namespace Pterodactyl\Http\Controllers\Api\Application;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Webmozart\Assert\Assert;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Container\Container; use Illuminate\Container\Container;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Extensions\Spatie\Fractalistic\Fractal; use Pterodactyl\Extensions\Spatie\Fractalistic\Fractal;
use Pterodactyl\Transformers\Api\Application\BaseTransformer;
abstract class ApplicationApiController extends Controller abstract class ApplicationApiController extends Controller
{ {
protected Request $request; protected Request $request;
protected Fractal $fractal; protected Fractal $fractal;
/** /**
@ -45,25 +44,6 @@ abstract class ApplicationApiController extends Controller
$this->request = $request; $this->request = $request;
} }
/**
* Return an instance of an application transformer.
*
* @return \Pterodactyl\Transformers\Api\Application\BaseTransformer
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function getTransformer(string $abstract)
{
/** @var \Pterodactyl\Transformers\Api\Application\BaseTransformer $transformer */
$transformer = Container::getInstance()->make($abstract);
$transformer->setRootAdmin($this->request->user()->root_admin);
$transformer->setKey($this->request->attributes->get('api_key'));
Assert::isInstanceOf($transformer, BaseTransformer::class);
return $transformer;
}
/** /**
* Return a HTTP/201 response for the API. * Return a HTTP/201 response for the API.
*/ */

View File

@ -51,7 +51,7 @@ class DatabaseController extends ApplicationApiController
->paginate($perPage); ->paginate($perPage);
return $this->fractal->collection($databases) return $this->fractal->collection($databases)
->transformWith($this->getTransformer(DatabaseHostTransformer::class)) ->transformWith(DatabaseHostTransformer::class)
->toArray(); ->toArray();
} }
@ -63,7 +63,7 @@ class DatabaseController extends ApplicationApiController
public function view(GetDatabaseRequest $request, DatabaseHost $databaseHost): array public function view(GetDatabaseRequest $request, DatabaseHost $databaseHost): array
{ {
return $this->fractal->item($databaseHost) return $this->fractal->item($databaseHost)
->transformWith($this->getTransformer(DatabaseHostTransformer::class)) ->transformWith(DatabaseHostTransformer::class)
->toArray(); ->toArray();
} }
@ -77,7 +77,7 @@ class DatabaseController extends ApplicationApiController
$databaseHost = $this->creationService->handle($request->validated()); $databaseHost = $this->creationService->handle($request->validated());
return $this->fractal->item($databaseHost) return $this->fractal->item($databaseHost)
->transformWith($this->getTransformer(DatabaseHostTransformer::class)) ->transformWith(DatabaseHostTransformer::class)
->respond(JsonResponse::HTTP_CREATED); ->respond(JsonResponse::HTTP_CREATED);
} }
@ -91,7 +91,7 @@ class DatabaseController extends ApplicationApiController
$databaseHost = $this->updateService->handle($databaseHost->id, $request->validated()); $databaseHost = $this->updateService->handle($databaseHost->id, $request->validated());
return $this->fractal->item($databaseHost) return $this->fractal->item($databaseHost)
->transformWith($this->getTransformer(DatabaseHostTransformer::class)) ->transformWith(DatabaseHostTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -52,7 +52,7 @@ class EggController extends ApplicationApiController
} }
return $this->fractal->collection($eggs) return $this->fractal->collection($eggs)
->transformWith($this->getTransformer(EggTransformer::class)) ->transformWith(EggTransformer::class)
->toArray(); ->toArray();
} }
@ -64,7 +64,7 @@ class EggController extends ApplicationApiController
public function view(GetEggRequest $request, Egg $egg): array public function view(GetEggRequest $request, Egg $egg): array
{ {
return $this->fractal->item($egg) return $this->fractal->item($egg)
->transformWith($this->getTransformer(EggTransformer::class)) ->transformWith(EggTransformer::class)
->toArray(); ->toArray();
} }
@ -78,7 +78,7 @@ class EggController extends ApplicationApiController
$egg = Egg::query()->create($request->validated()); $egg = Egg::query()->create($request->validated());
return $this->fractal->item($egg) return $this->fractal->item($egg)
->transformWith($this->getTransformer(EggTransformer::class)) ->transformWith(EggTransformer::class)
->respond(JsonResponse::HTTP_CREATED); ->respond(JsonResponse::HTTP_CREATED);
} }
@ -92,7 +92,7 @@ class EggController extends ApplicationApiController
$egg->update($request->validated()); $egg->update($request->validated());
return $this->fractal->item($egg) return $this->fractal->item($egg)
->transformWith($this->getTransformer(EggTransformer::class)) ->transformWith(EggTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -57,7 +57,7 @@ class LocationController extends ApplicationApiController
->paginate($perPage); ->paginate($perPage);
return $this->fractal->collection($locations) return $this->fractal->collection($locations)
->transformWith($this->getTransformer(LocationTransformer::class)) ->transformWith(LocationTransformer::class)
->toArray(); ->toArray();
} }
@ -69,7 +69,7 @@ class LocationController extends ApplicationApiController
public function view(GetLocationRequest $request, Location $location): array public function view(GetLocationRequest $request, Location $location): array
{ {
return $this->fractal->item($location) return $this->fractal->item($location)
->transformWith($this->getTransformer(LocationTransformer::class)) ->transformWith(LocationTransformer::class)
->toArray(); ->toArray();
} }
@ -85,7 +85,7 @@ class LocationController extends ApplicationApiController
$location = $this->creationService->handle($request->validated()); $location = $this->creationService->handle($request->validated());
return $this->fractal->item($location) return $this->fractal->item($location)
->transformWith($this->getTransformer(LocationTransformer::class)) ->transformWith(LocationTransformer::class)
->addMeta([ ->addMeta([
'resource' => route('api.application.locations.view', [ 'resource' => route('api.application.locations.view', [
'location' => $location->id, 'location' => $location->id,
@ -106,7 +106,7 @@ class LocationController extends ApplicationApiController
$location = $this->updateService->handle($location, $request->validated()); $location = $this->updateService->handle($location, $request->validated());
return $this->fractal->item($location) return $this->fractal->item($location)
->transformWith($this->getTransformer(LocationTransformer::class)) ->transformWith(LocationTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -2,8 +2,8 @@
namespace Pterodactyl\Http\Controllers\Api\Application\Mounts; namespace Pterodactyl\Http\Controllers\Api\Application\Mounts;
use Pterodactyl\Models\Mount;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Pterodactyl\Models\Mount;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Spatie\QueryBuilder\QueryBuilder; use Spatie\QueryBuilder\QueryBuilder;
use Pterodactyl\Transformers\Api\Application\MountTransformer; use Pterodactyl\Transformers\Api\Application\MountTransformer;
@ -45,7 +45,7 @@ class MountController extends ApplicationApiController
->paginate($perPage); ->paginate($perPage);
return $this->fractal->collection($mounts) return $this->fractal->collection($mounts)
->transformWith($this->getTransformer(MountTransformer::class)) ->transformWith(MountTransformer::class)
->toArray(); ->toArray();
} }
@ -57,7 +57,7 @@ class MountController extends ApplicationApiController
public function view(GetMountRequest $request, Mount $mount): array public function view(GetMountRequest $request, Mount $mount): array
{ {
return $this->fractal->item($mount) return $this->fractal->item($mount)
->transformWith($this->getTransformer(MountTransformer::class)) ->transformWith(MountTransformer::class)
->toArray(); ->toArray();
} }
@ -71,7 +71,7 @@ class MountController extends ApplicationApiController
$mount = Mount::query()->create($request->validated()); $mount = Mount::query()->create($request->validated());
return $this->fractal->item($mount) return $this->fractal->item($mount)
->transformWith($this->getTransformer(MountTransformer::class)) ->transformWith(MountTransformer::class)
->respond(JsonResponse::HTTP_CREATED); ->respond(JsonResponse::HTTP_CREATED);
} }
@ -85,7 +85,7 @@ class MountController extends ApplicationApiController
$mount->update($request->validated()); $mount->update($request->validated());
return $this->fractal->item($mount) return $this->fractal->item($mount)
->transformWith($this->getTransformer(MountTransformer::class)) ->transformWith(MountTransformer::class)
->toArray(); ->toArray();
} }
@ -116,7 +116,7 @@ class MountController extends ApplicationApiController
} }
return $this->fractal->item($mount) return $this->fractal->item($mount)
->transformWith($this->getTransformer(MountTransformer::class)) ->transformWith(MountTransformer::class)
->toArray(); ->toArray();
} }
@ -135,7 +135,7 @@ class MountController extends ApplicationApiController
} }
return $this->fractal->item($mount) return $this->fractal->item($mount)
->transformWith($this->getTransformer(MountTransformer::class)) ->transformWith(MountTransformer::class)
->toArray(); ->toArray();
} }
@ -154,7 +154,7 @@ class MountController extends ApplicationApiController
} }
return $this->fractal->item($mount) return $this->fractal->item($mount)
->transformWith($this->getTransformer(MountTransformer::class)) ->transformWith(MountTransformer::class)
->toArray(); ->toArray();
} }
@ -173,7 +173,7 @@ class MountController extends ApplicationApiController
} }
return $this->fractal->item($mount) return $this->fractal->item($mount)
->transformWith($this->getTransformer(MountTransformer::class)) ->transformWith(MountTransformer::class)
->toArray(); ->toArray();
} }
} }

View File

@ -63,7 +63,7 @@ class NestController extends ApplicationApiController
} }
return $this->fractal->collection($nests) return $this->fractal->collection($nests)
->transformWith($this->getTransformer(NestTransformer::class)) ->transformWith(NestTransformer::class)
->toArray(); ->toArray();
} }
@ -75,7 +75,7 @@ class NestController extends ApplicationApiController
public function view(GetNestRequest $request, Nest $nest): array public function view(GetNestRequest $request, Nest $nest): array
{ {
return $this->fractal->item($nest) return $this->fractal->item($nest)
->transformWith($this->getTransformer(NestTransformer::class)) ->transformWith(NestTransformer::class)
->toArray(); ->toArray();
} }
@ -90,7 +90,7 @@ class NestController extends ApplicationApiController
$nest = $this->nestCreationService->handle($request->validated()); $nest = $this->nestCreationService->handle($request->validated());
return $this->fractal->item($nest) return $this->fractal->item($nest)
->transformWith($this->getTransformer(NestTransformer::class)) ->transformWith(NestTransformer::class)
->toArray(); ->toArray();
} }
@ -106,7 +106,7 @@ class NestController extends ApplicationApiController
$this->nestUpdateService->handle($nest->id, $request->validated()); $this->nestUpdateService->handle($nest->id, $request->validated());
return $this->fractal->item($nest) return $this->fractal->item($nest)
->transformWith($this->getTransformer(NestTransformer::class)) ->transformWith(NestTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -47,7 +47,7 @@ class AllocationController extends ApplicationApiController
$allocations = $node->allocations()->paginate($perPage); $allocations = $node->allocations()->paginate($perPage);
return $this->fractal->collection($allocations) return $this->fractal->collection($allocations)
->transformWith($this->getTransformer(AllocationTransformer::class)) ->transformWith(AllocationTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -61,7 +61,7 @@ class NodeController extends ApplicationApiController
->paginate($perPage); ->paginate($perPage);
return $this->fractal->collection($nodes) return $this->fractal->collection($nodes)
->transformWith($this->getTransformer(NodeTransformer::class)) ->transformWith(NodeTransformer::class)
->toArray(); ->toArray();
} }
@ -73,7 +73,7 @@ class NodeController extends ApplicationApiController
public function view(GetNodeRequest $request, Node $node): array public function view(GetNodeRequest $request, Node $node): array
{ {
return $this->fractal->item($node) return $this->fractal->item($node)
->transformWith($this->getTransformer(NodeTransformer::class)) ->transformWith(NodeTransformer::class)
->toArray(); ->toArray();
} }
@ -89,7 +89,7 @@ class NodeController extends ApplicationApiController
$node = $this->creationService->handle($request->validated()); $node = $this->creationService->handle($request->validated());
return $this->fractal->item($node) return $this->fractal->item($node)
->transformWith($this->getTransformer(NodeTransformer::class)) ->transformWith(NodeTransformer::class)
->addMeta([ ->addMeta([
'resource' => route('api.application.nodes.view', [ 'resource' => route('api.application.nodes.view', [
'node' => $node->id, 'node' => $node->id,
@ -112,7 +112,7 @@ class NodeController extends ApplicationApiController
); );
return $this->fractal->item($node) return $this->fractal->item($node)
->transformWith($this->getTransformer(NodeTransformer::class)) ->transformWith(NodeTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -38,7 +38,7 @@ class NodeDeploymentController extends ApplicationApiController
->handle($request->query('per_page'), $request->query('page')); ->handle($request->query('per_page'), $request->query('page'));
return $this->fractal->collection($nodes) return $this->fractal->collection($nodes)
->transformWith($this->getTransformer(NodeTransformer::class)) ->transformWith(NodeTransformer::class)
->toArray(); ->toArray();
} }
} }

View File

@ -6,8 +6,8 @@ use Illuminate\Http\Response;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Pterodactyl\Models\AdminRole; use Pterodactyl\Models\AdminRole;
use Spatie\QueryBuilder\QueryBuilder; use Spatie\QueryBuilder\QueryBuilder;
use Pterodactyl\Transformers\Api\Application\AdminRoleTransformer;
use Pterodactyl\Exceptions\Http\QueryValueOutOfRangeHttpException; use Pterodactyl\Exceptions\Http\QueryValueOutOfRangeHttpException;
use Pterodactyl\Transformers\Api\Application\AdminRoleTransformer;
use Pterodactyl\Http\Requests\Api\Application\Roles\GetRoleRequest; use Pterodactyl\Http\Requests\Api\Application\Roles\GetRoleRequest;
use Pterodactyl\Http\Requests\Api\Application\Roles\GetRolesRequest; use Pterodactyl\Http\Requests\Api\Application\Roles\GetRolesRequest;
use Pterodactyl\Http\Requests\Api\Application\Roles\StoreRoleRequest; use Pterodactyl\Http\Requests\Api\Application\Roles\StoreRoleRequest;
@ -43,7 +43,7 @@ class RoleController extends ApplicationApiController
->paginate($perPage); ->paginate($perPage);
return $this->fractal->collection($roles) return $this->fractal->collection($roles)
->transformWith($this->getTransformer(AdminRoleTransformer::class)) ->transformWith(AdminRoleTransformer::class)
->toArray(); ->toArray();
} }
@ -55,7 +55,7 @@ class RoleController extends ApplicationApiController
public function view(GetRoleRequest $request, AdminRole $role): array public function view(GetRoleRequest $request, AdminRole $role): array
{ {
return $this->fractal->item($role) return $this->fractal->item($role)
->transformWith($this->getTransformer(AdminRoleTransformer::class)) ->transformWith(AdminRoleTransformer::class)
->toArray(); ->toArray();
} }
@ -72,7 +72,7 @@ class RoleController extends ApplicationApiController
$role = AdminRole::query()->create($data); $role = AdminRole::query()->create($data);
return $this->fractal->item($role) return $this->fractal->item($role)
->transformWith($this->getTransformer(AdminRoleTransformer::class)) ->transformWith(AdminRoleTransformer::class)
->respond(JsonResponse::HTTP_CREATED); ->respond(JsonResponse::HTTP_CREATED);
} }
@ -86,7 +86,7 @@ class RoleController extends ApplicationApiController
$role->update($request->validated()); $role->update($request->validated());
return $this->fractal->item($role) return $this->fractal->item($role)
->transformWith($this->getTransformer(AdminRoleTransformer::class)) ->transformWith(AdminRoleTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -46,7 +46,7 @@ class DatabaseController extends ApplicationApiController
public function index(GetServerDatabasesRequest $request, Server $server): array public function index(GetServerDatabasesRequest $request, Server $server): array
{ {
return $this->fractal->collection($server->databases) return $this->fractal->collection($server->databases)
->transformWith($this->getTransformer(ServerDatabaseTransformer::class)) ->transformWith(ServerDatabaseTransformer::class)
->toArray(); ->toArray();
} }
@ -58,7 +58,7 @@ class DatabaseController extends ApplicationApiController
public function view(GetServerDatabaseRequest $request, Server $server, Database $database): array public function view(GetServerDatabaseRequest $request, Server $server, Database $database): array
{ {
return $this->fractal->item($database) return $this->fractal->item($database)
->transformWith($this->getTransformer(ServerDatabaseTransformer::class)) ->transformWith(ServerDatabaseTransformer::class)
->toArray(); ->toArray();
} }
@ -86,7 +86,7 @@ class DatabaseController extends ApplicationApiController
])); ]));
return $this->fractal->item($database) return $this->fractal->item($database)
->transformWith($this->getTransformer(ServerDatabaseTransformer::class)) ->transformWith(ServerDatabaseTransformer::class)
->addMeta([ ->addMeta([
'resource' => route('api.application.servers.databases.view', [ 'resource' => route('api.application.servers.databases.view', [
'server' => $server->id, 'server' => $server->id,

View File

@ -2,6 +2,7 @@
namespace Pterodactyl\Http\Controllers\Api\Application\Servers; namespace Pterodactyl\Http\Controllers\Api\Application\Servers;
use Pterodactyl\Models\Server;
use Pterodactyl\Transformers\Api\Application\ServerTransformer; use Pterodactyl\Transformers\Api\Application\ServerTransformer;
use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController; use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;
use Pterodactyl\Http\Requests\Api\Application\Servers\GetExternalServerRequest; use Pterodactyl\Http\Requests\Api\Application\Servers\GetExternalServerRequest;
@ -13,10 +14,12 @@ class ExternalServerController extends ApplicationApiController
* *
* @throws \Illuminate\Contracts\Container\BindingResolutionException * @throws \Illuminate\Contracts\Container\BindingResolutionException
*/ */
public function index(GetExternalServerRequest $request): array public function index(GetExternalServerRequest $request, string $external_id): array
{ {
return $this->fractal->item($request->getServerModel()) $server = Server::query()->where('external_id', $external_id)->firstOrFail();
->transformWith($this->getTransformer(ServerTransformer::class))
return $this->fractal->item($server)
->transformWith(ServerTransformer::class)
->toArray(); ->toArray();
} }
} }

View File

@ -52,7 +52,7 @@ class ServerController extends ApplicationApiController
->paginate($perPage); ->paginate($perPage);
return $this->fractal->collection($servers) return $this->fractal->collection($servers)
->transformWith($this->getTransformer(ServerTransformer::class)) ->transformWith(ServerTransformer::class)
->toArray(); ->toArray();
} }
@ -71,7 +71,7 @@ class ServerController extends ApplicationApiController
$server = $this->creationService->handle($request->validated(), $request->getDeploymentObject()); $server = $this->creationService->handle($request->validated(), $request->getDeploymentObject());
return $this->fractal->item($server) return $this->fractal->item($server)
->transformWith($this->getTransformer(ServerTransformer::class)) ->transformWith(ServerTransformer::class)
->respond(Response::HTTP_CREATED); ->respond(Response::HTTP_CREATED);
} }
@ -83,7 +83,7 @@ class ServerController extends ApplicationApiController
public function view(GetServerRequest $request, Server $server): array public function view(GetServerRequest $request, Server $server): array
{ {
return $this->fractal->item($server) return $this->fractal->item($server)
->transformWith($this->getTransformer(ServerTransformer::class)) ->transformWith(ServerTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -41,7 +41,7 @@ class ServerDetailsController extends ApplicationApiController
); );
return $this->fractal->item($server) return $this->fractal->item($server)
->transformWith($this->getTransformer(ServerTransformer::class)) ->transformWith(ServerTransformer::class)
->toArray(); ->toArray();
} }
@ -55,7 +55,7 @@ class ServerDetailsController extends ApplicationApiController
$server = $this->buildModificationService->handle($server, $request->validated()); $server = $this->buildModificationService->handle($server, $request->validated());
return $this->fractal->item($server) return $this->fractal->item($server)
->transformWith($this->getTransformer(ServerTransformer::class)) ->transformWith(ServerTransformer::class)
->toArray(); ->toArray();
} }
} }

View File

@ -35,7 +35,7 @@ class StartupController extends ApplicationApiController
->handle($server, $request->validated()); ->handle($server, $request->validated());
return $this->fractal->item($server) return $this->fractal->item($server)
->transformWith($this->getTransformer(ServerTransformer::class)) ->transformWith(ServerTransformer::class)
->toArray(); ->toArray();
} }
} }

View File

@ -2,6 +2,7 @@
namespace Pterodactyl\Http\Controllers\Api\Application\Users; namespace Pterodactyl\Http\Controllers\Api\Application\Users;
use Pterodactyl\Models\User;
use Pterodactyl\Transformers\Api\Application\UserTransformer; use Pterodactyl\Transformers\Api\Application\UserTransformer;
use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController; use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;
use Pterodactyl\Http\Requests\Api\Application\Users\GetExternalUserRequest; use Pterodactyl\Http\Requests\Api\Application\Users\GetExternalUserRequest;
@ -13,10 +14,12 @@ class ExternalUserController extends ApplicationApiController
* *
* @throws \Illuminate\Contracts\Container\BindingResolutionException * @throws \Illuminate\Contracts\Container\BindingResolutionException
*/ */
public function index(GetExternalUserRequest $request): array public function index(GetExternalUserRequest $request, string $external_id): array
{ {
return $this->fractal->item($request->getUserModel()) $user = User::query()->where('external_id', $external_id)->firstOrFail();
->transformWith($this->getTransformer(UserTransformer::class))
return $this->fractal->item($user)
->transformWith(UserTransformer::class)
->toArray(); ->toArray();
} }
} }

View File

@ -63,7 +63,7 @@ class UserController extends ApplicationApiController
->paginate($perPage); ->paginate($perPage);
return $this->fractal->collection($users) return $this->fractal->collection($users)
->transformWith($this->getTransformer(UserTransformer::class)) ->transformWith(UserTransformer::class)
->toArray(); ->toArray();
} }
@ -76,7 +76,7 @@ class UserController extends ApplicationApiController
public function view(GetUserRequest $request, User $user): array public function view(GetUserRequest $request, User $user): array
{ {
return $this->fractal->item($user) return $this->fractal->item($user)
->transformWith($this->getTransformer(UserTransformer::class)) ->transformWith(UserTransformer::class)
->toArray(); ->toArray();
} }
@ -98,7 +98,7 @@ class UserController extends ApplicationApiController
$user = $this->updateService->handle($user, $request->validated()); $user = $this->updateService->handle($user, $request->validated());
return $this->fractal->item($user) return $this->fractal->item($user)
->transformWith($this->getTransformer(UserTransformer::class)) ->transformWith(UserTransformer::class)
->toArray(); ->toArray();
} }
@ -114,7 +114,7 @@ class UserController extends ApplicationApiController
$user = $this->creationService->handle($request->validated()); $user = $this->creationService->handle($request->validated());
return $this->fractal->item($user) return $this->fractal->item($user)
->transformWith($this->getTransformer(UserTransformer::class)) ->transformWith(UserTransformer::class)
->addMeta([ ->addMeta([
'resource' => route('api.application.users.view', [ 'resource' => route('api.application.users.view', [
'user' => $user->id, 'user' => $user->id,

View File

@ -34,7 +34,7 @@ class AccountController extends ClientApiController
public function index(Request $request): array public function index(Request $request): array
{ {
return $this->fractal->item($request->user()) return $this->fractal->item($request->user())
->transformWith($this->getTransformer(AccountTransformer::class)) ->transformWith(AccountTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -3,46 +3,22 @@
namespace Pterodactyl\Http\Controllers\Api\Client; namespace Pterodactyl\Http\Controllers\Api\Client;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Pterodactyl\Models\ApiKey;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
use Illuminate\Contracts\Encryption\Encrypter; use Pterodactyl\Http\Requests\Api\Client\AccountApiRequest;
use Pterodactyl\Services\Api\KeyCreationService;
use Pterodactyl\Repositories\Eloquent\ApiKeyRepository;
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
use Pterodactyl\Transformers\Api\Client\ApiKeyTransformer;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Pterodactyl\Http\Requests\Api\Client\Account\StoreApiKeyRequest; use Pterodactyl\Http\Requests\Api\Client\Account\StoreApiKeyRequest;
use Pterodactyl\Transformers\Api\Client\PersonalAccessTokenTransformer;
class ApiKeyController extends ClientApiController class ApiKeyController extends ClientApiController
{ {
private Encrypter $encrypter;
private ApiKeyRepository $repository;
private KeyCreationService $keyCreationService;
/**
* ApiKeyController constructor.
*/
public function __construct(
Encrypter $encrypter,
ApiKeyRepository $repository,
KeyCreationService $keyCreationService
) {
parent::__construct();
$this->encrypter = $encrypter;
$this->repository = $repository;
$this->keyCreationService = $keyCreationService;
}
/** /**
* Returns all of the API keys that exist for the given client. * Returns all of the API keys that exist for the given client.
* *
* @throws \Illuminate\Contracts\Container\BindingResolutionException * @throws \Illuminate\Contracts\Container\BindingResolutionException
*/ */
public function index(ClientApiRequest $request): array public function index(AccountApiRequest $request): array
{ {
return $this->fractal->collection($request->user()->apiKeys) return $this->fractal->collection($request->user()->tokens)
->transformWith($this->getTransformer(ApiKeyTransformer::class)) ->transformWith(PersonalAccessTokenTransformer::class)
->toArray(); ->toArray();
} }
@ -50,25 +26,22 @@ class ApiKeyController extends ClientApiController
* Store a new API key for a user's account. * Store a new API key for a user's account.
* *
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Illuminate\Contracts\Container\BindingResolutionException * @throws \Illuminate\Contracts\Container\BindingResolutionException
*/ */
public function store(StoreApiKeyRequest $request): array public function store(StoreApiKeyRequest $request): array
{ {
if ($request->user()->apiKeys->count() >= 5) { if ($request->user()->tokens->count() >= 10) {
throw new DisplayException('You have reached the account limit for number of API keys.'); throw new DisplayException('You have reached the account limit for number of API keys.');
} }
$key = $this->keyCreationService->setKeyType(ApiKey::TYPE_ACCOUNT)->handle([ // TODO: this should accept an array of different scopes to apply as permissions
'user_id' => $request->user()->id, // for the token. Right now it allows any account level permission.
'memo' => $request->input('description'), $token = $request->user()->createToken($request->input('description'));
'allowed_ips' => $request->input('allowed_ips') ?? [],
]);
return $this->fractal->item($key) return $this->fractal->item($token->accessToken)
->transformWith($this->getTransformer(ApiKeyTransformer::class)) ->transformWith(PersonalAccessTokenTransformer::class)
->addMeta([ ->addMeta([
'secret_token' => $this->encrypter->decrypt($key->token), 'secret_token' => $token->plainTextToken,
]) ])
->toArray(); ->toArray();
} }
@ -76,17 +49,9 @@ class ApiKeyController extends ClientApiController
/** /**
* Deletes a given API key. * Deletes a given API key.
*/ */
public function delete(ClientApiRequest $request, string $identifier): Response public function delete(AccountApiRequest $request, string $id): Response
{ {
$response = $this->repository->deleteWhere([ $request->user()->tokens()->where('token_id', $id)->delete();
'key_type' => ApiKey::TYPE_ACCOUNT,
'user_id' => $request->user()->id,
'identifier' => $identifier,
]);
if (!$response) {
throw new NotFoundHttpException();
}
return $this->returnNoContent(); return $this->returnNoContent();
} }

View File

@ -2,10 +2,7 @@
namespace Pterodactyl\Http\Controllers\Api\Client; namespace Pterodactyl\Http\Controllers\Api\Client;
use Webmozart\Assert\Assert; use Pterodactyl\Transformers\Api\Transformer;
use Illuminate\Container\Container;
use Pterodactyl\Transformers\Daemon\BaseDaemonTransformer;
use Pterodactyl\Transformers\Api\Client\BaseClientTransformer;
use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController; use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;
abstract class ClientApiController extends ApplicationApiController abstract class ClientApiController extends ApplicationApiController
@ -15,7 +12,7 @@ abstract class ClientApiController extends ApplicationApiController
* *
* @return string[] * @return string[]
*/ */
protected function getIncludesForTransformer(BaseClientTransformer $transformer, array $merge = []): array protected function getIncludesForTransformer(Transformer $transformer, array $merge = []): array
{ {
$filtered = array_filter($this->parseIncludes(), function ($datum) use ($transformer) { $filtered = array_filter($this->parseIncludes(), function ($datum) use ($transformer) {
return in_array($datum, $transformer->getAvailableIncludes()); return in_array($datum, $transformer->getAvailableIncludes());
@ -41,28 +38,4 @@ abstract class ClientApiController extends ApplicationApiController
return trim($item); return trim($item);
}, explode(',', $includes)); }, explode(',', $includes));
} }
/**
* Return an instance of an application transformer.
*
* @return \Pterodactyl\Transformers\Api\Client\BaseClientTransformer
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function getTransformer(string $abstract)
{
/** @var \Pterodactyl\Transformers\Api\Client\BaseClientTransformer $transformer */
$transformer = Container::getInstance()->make($abstract);
Assert::isInstanceOfAny($transformer, [
BaseClientTransformer::class,
BaseDaemonTransformer::class,
]);
if ($transformer instanceof BaseClientTransformer) {
$transformer->setKey($this->request->attributes->get('api_key'));
$transformer->setUser($this->request->user());
}
return $transformer;
}
} }

View File

@ -34,11 +34,10 @@ class ClientController extends ClientApiController
public function index(GetServersRequest $request): array public function index(GetServersRequest $request): array
{ {
$user = $request->user(); $user = $request->user();
$transformer = $this->getTransformer(ServerTransformer::class);
// Start the query builder and ensure we eager load any requested relationships from the request. // Start the query builder and ensure we eager load any requested relationships from the request.
$builder = QueryBuilder::for( $builder = QueryBuilder::for(
Server::query()->with($this->getIncludesForTransformer($transformer, ['node'])) Server::query()->with($this->getIncludesForTransformer(new ServerTransformer(), ['node']))
)->allowedFilters([ )->allowedFilters([
'uuid', 'uuid',
'name', 'name',
@ -69,7 +68,7 @@ class ClientController extends ClientApiController
$servers = $builder->paginate(min($request->query('per_page', 50), 100))->appends($request->query()); $servers = $builder->paginate(min($request->query('per_page', 50), 100))->appends($request->query());
return $this->fractal->transformWith($transformer)->collection($servers)->toArray(); return $this->fractal->transformWith(new ServerTransformer())->collection($servers)->toArray();
} }
/** /**

View File

@ -20,13 +20,12 @@ class SSHKeyController extends ClientApiController
public function index(Request $request): \Pterodactyl\Extensions\Spatie\Fractalistic\Fractal public function index(Request $request): \Pterodactyl\Extensions\Spatie\Fractalistic\Fractal
{ {
return $this->fractal->collection(UserSSHKey::query()->where('user_id', '=', $request->user()->id)->get()) return $this->fractal->collection(UserSSHKey::query()->where('user_id', '=', $request->user()->id)->get())
->transformWith($this->getTransformer(UserSSHKeyTransformer::class)); ->transformWith(UserSSHKeyTransformer::class);
} }
/** /**
* ? * ?
* *
* @return JsonResponse
* @throws \Illuminate\Contracts\Container\BindingResolutionException * @throws \Illuminate\Contracts\Container\BindingResolutionException
* @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayException
*/ */
@ -42,7 +41,7 @@ class SSHKeyController extends ClientApiController
$key = UserSSHKey::query()->create($data); $key = UserSSHKey::query()->create($data);
return $this->fractal->item($key) return $this->fractal->item($key)
->transformWith($this->getTransformer(UserSSHKeyTransformer::class)) ->transformWith(UserSSHKeyTransformer::class)
->respond(JsonResponse::HTTP_CREATED); ->respond(JsonResponse::HTTP_CREATED);
} }

View File

@ -12,8 +12,8 @@ use Pterodactyl\Models\Permission;
use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\Access\AuthorizationException;
use Pterodactyl\Services\Backups\DeleteBackupService; use Pterodactyl\Services\Backups\DeleteBackupService;
use Pterodactyl\Services\Backups\DownloadLinkService; use Pterodactyl\Services\Backups\DownloadLinkService;
use Pterodactyl\Services\Backups\InitiateBackupService;
use Pterodactyl\Repositories\Eloquent\BackupRepository; use Pterodactyl\Repositories\Eloquent\BackupRepository;
use Pterodactyl\Services\Backups\InitiateBackupService;
use Pterodactyl\Repositories\Wings\DaemonBackupRepository; use Pterodactyl\Repositories\Wings\DaemonBackupRepository;
use Pterodactyl\Transformers\Api\Client\BackupTransformer; use Pterodactyl\Transformers\Api\Client\BackupTransformer;
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController; use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
@ -63,7 +63,7 @@ class BackupController extends ClientApiController
$limit = min($request->query('per_page') ?? 20, 50); $limit = min($request->query('per_page') ?? 20, 50);
return $this->fractal->collection($server->backups()->paginate($limit)) return $this->fractal->collection($server->backups()->paginate($limit))
->transformWith($this->getTransformer(BackupTransformer::class)) ->transformWith(BackupTransformer::class)
->addMeta([ ->addMeta([
'backup_count' => $this->repository->getNonFailedBackups($server)->count(), 'backup_count' => $this->repository->getNonFailedBackups($server)->count(),
]) ])
@ -100,7 +100,7 @@ class BackupController extends ClientApiController
}); });
return $this->fractal->item($backup) return $this->fractal->item($backup)
->transformWith($this->getTransformer(BackupTransformer::class)) ->transformWith(BackupTransformer::class)
->toArray(); ->toArray();
} }
@ -126,7 +126,7 @@ class BackupController extends ClientApiController
$backup->refresh(); $backup->refresh();
return $this->fractal->item($backup) return $this->fractal->item($backup)
->transformWith($this->getTransformer(BackupTransformer::class)) ->transformWith(BackupTransformer::class)
->toArray(); ->toArray();
} }
@ -142,7 +142,7 @@ class BackupController extends ClientApiController
} }
return $this->fractal->item($backup) return $this->fractal->item($backup)
->transformWith($this->getTransformer(BackupTransformer::class)) ->transformWith(BackupTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -48,7 +48,7 @@ class DatabaseController extends ClientApiController
public function index(GetDatabasesRequest $request, Server $server): array public function index(GetDatabasesRequest $request, Server $server): array
{ {
return $this->fractal->collection($server->databases) return $this->fractal->collection($server->databases)
->transformWith($this->getTransformer(DatabaseTransformer::class)) ->transformWith(DatabaseTransformer::class)
->toArray(); ->toArray();
} }
@ -65,7 +65,7 @@ class DatabaseController extends ClientApiController
return $this->fractal->item($database) return $this->fractal->item($database)
->parseIncludes(['password']) ->parseIncludes(['password'])
->transformWith($this->getTransformer(DatabaseTransformer::class)) ->transformWith(DatabaseTransformer::class)
->toArray(); ->toArray();
} }
@ -82,7 +82,7 @@ class DatabaseController extends ClientApiController
return $this->fractal->item($database) return $this->fractal->item($database)
->parseIncludes(['password']) ->parseIncludes(['password'])
->transformWith($this->getTransformer(DatabaseTransformer::class)) ->transformWith(DatabaseTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -57,7 +57,7 @@ class FileController extends ClientApiController
->getDirectory($request->get('directory') ?? '/'); ->getDirectory($request->get('directory') ?? '/');
return $this->fractal->collection($contents) return $this->fractal->collection($contents)
->transformWith($this->getTransformer(FileObjectTransformer::class)) ->transformWith(FileObjectTransformer::class)
->toArray(); ->toArray();
} }
@ -202,7 +202,7 @@ class FileController extends ClientApiController
}); });
return $this->fractal->item($file) return $this->fractal->item($file)
->transformWith($this->getTransformer(FileObjectTransformer::class)) ->transformWith(FileObjectTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -47,7 +47,7 @@ class NetworkAllocationController extends ClientApiController
public function index(GetNetworkRequest $request, Server $server): array public function index(GetNetworkRequest $request, Server $server): array
{ {
return $this->fractal->collection($server->allocations) return $this->fractal->collection($server->allocations)
->transformWith($this->getTransformer(AllocationTransformer::class)) ->transformWith(AllocationTransformer::class)
->toArray(); ->toArray();
} }
@ -65,7 +65,7 @@ class NetworkAllocationController extends ClientApiController
]); ]);
return $this->fractal->item($allocation) return $this->fractal->item($allocation)
->transformWith($this->getTransformer(AllocationTransformer::class)) ->transformWith(AllocationTransformer::class)
->toArray(); ->toArray();
} }
@ -81,7 +81,7 @@ class NetworkAllocationController extends ClientApiController
$this->serverRepository->update($server->id, ['allocation_id' => $allocation->id]); $this->serverRepository->update($server->id, ['allocation_id' => $allocation->id]);
return $this->fractal->item($allocation) return $this->fractal->item($allocation)
->transformWith($this->getTransformer(AllocationTransformer::class)) ->transformWith(AllocationTransformer::class)
->toArray(); ->toArray();
} }
@ -100,7 +100,7 @@ class NetworkAllocationController extends ClientApiController
$allocation = $this->assignableAllocationService->handle($server); $allocation = $this->assignableAllocationService->handle($server);
return $this->fractal->item($allocation) return $this->fractal->item($allocation)
->transformWith($this->getTransformer(AllocationTransformer::class)) ->transformWith(AllocationTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -42,7 +42,7 @@ class ResourceUtilizationController extends ClientApiController
}); });
return $this->fractal->item($stats) return $this->fractal->item($stats)
->transformWith($this->getTransformer(StatsTransformer::class)) ->transformWith(StatsTransformer::class)
->toArray(); ->toArray();
} }
} }

View File

@ -14,7 +14,6 @@ use Pterodactyl\Repositories\Eloquent\ScheduleRepository;
use Pterodactyl\Services\Schedules\ProcessScheduleService; use Pterodactyl\Services\Schedules\ProcessScheduleService;
use Pterodactyl\Transformers\Api\Client\ScheduleTransformer; use Pterodactyl\Transformers\Api\Client\ScheduleTransformer;
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController; use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\ViewScheduleRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\ViewScheduleRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\StoreScheduleRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\StoreScheduleRequest;
@ -49,7 +48,7 @@ class ScheduleController extends ClientApiController
$schedules->loadMissing('tasks'); $schedules->loadMissing('tasks');
return $this->fractal->collection($schedules) return $this->fractal->collection($schedules)
->transformWith($this->getTransformer(ScheduleTransformer::class)) ->transformWith(ScheduleTransformer::class)
->toArray(); ->toArray();
} }
@ -77,7 +76,7 @@ class ScheduleController extends ClientApiController
]); ]);
return $this->fractal->item($model) return $this->fractal->item($model)
->transformWith($this->getTransformer(ScheduleTransformer::class)) ->transformWith(ScheduleTransformer::class)
->toArray(); ->toArray();
} }
@ -88,14 +87,10 @@ class ScheduleController extends ClientApiController
*/ */
public function view(ViewScheduleRequest $request, Server $server, Schedule $schedule): array public function view(ViewScheduleRequest $request, Server $server, Schedule $schedule): array
{ {
if ($schedule->server_id !== $server->id) {
throw new NotFoundHttpException();
}
$schedule->loadMissing('tasks'); $schedule->loadMissing('tasks');
return $this->fractal->item($schedule) return $this->fractal->item($schedule)
->transformWith($this->getTransformer(ScheduleTransformer::class)) ->transformWith(ScheduleTransformer::class)
->toArray(); ->toArray();
} }
@ -134,7 +129,7 @@ class ScheduleController extends ClientApiController
$this->repository->update($schedule->id, $data); $this->repository->update($schedule->id, $data);
return $this->fractal->item($schedule->refresh()) return $this->fractal->item($schedule->refresh())
->transformWith($this->getTransformer(ScheduleTransformer::class)) ->transformWith(ScheduleTransformer::class)
->toArray(); ->toArray();
} }

View File

@ -6,15 +6,15 @@ use Pterodactyl\Models\Task;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Pterodactyl\Models\Schedule; use Pterodactyl\Models\Schedule;
use Pterodactyl\Models\Permission;
use Pterodactyl\Repositories\Eloquent\TaskRepository; use Pterodactyl\Repositories\Eloquent\TaskRepository;
use Pterodactyl\Exceptions\Http\HttpForbiddenException; use Pterodactyl\Exceptions\Http\HttpForbiddenException;
use Pterodactyl\Transformers\Api\Client\TaskTransformer; use Pterodactyl\Transformers\Api\Client\TaskTransformer;
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController; use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
use Pterodactyl\Exceptions\Service\ServiceLimitExceededException; use Pterodactyl\Exceptions\Service\ServiceLimitExceededException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\StoreTaskRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\StoreTaskRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\DeleteScheduleRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\UpdateScheduleRequest;
class ScheduleTaskController extends ClientApiController class ScheduleTaskController extends ClientApiController
{ {
@ -63,7 +63,7 @@ class ScheduleTaskController extends ClientApiController
]); ]);
return $this->fractal->item($task) return $this->fractal->item($task)
->transformWith($this->getTransformer(TaskTransformer::class)) ->transformWith(TaskTransformer::class)
->toArray(); ->toArray();
} }
@ -93,7 +93,7 @@ class ScheduleTaskController extends ClientApiController
]); ]);
return $this->fractal->item($task->refresh()) return $this->fractal->item($task->refresh())
->transformWith($this->getTransformer(TaskTransformer::class)) ->transformWith(TaskTransformer::class)
->toArray(); ->toArray();
} }
@ -101,18 +101,14 @@ class ScheduleTaskController extends ClientApiController
* Delete a given task for a schedule. If there are subsequent tasks stored in the database * Delete a given task for a schedule. If there are subsequent tasks stored in the database
* for this schedule their sequence IDs are decremented properly. * for this schedule their sequence IDs are decremented properly.
* *
* This uses the UpdateScheduleRequest intentionally -- there is no permission specific
* to deleting a given task on a schedule, so we'll assume if you have permission to edit
* a schedule that you can then remove a task from said schedule.
*
* @throws \Exception * @throws \Exception
*/ */
public function delete(ClientApiRequest $request, Server $server, Schedule $schedule, Task $task): Response public function delete(DeleteScheduleRequest $request, Server $server, Schedule $schedule, Task $task): Response
{ {
if ($task->schedule_id !== $schedule->id || $schedule->server_id !== $server->id) {
throw new NotFoundHttpException();
}
if (!$request->user()->can(Permission::ACTION_SCHEDULE_UPDATE, $server)) {
throw new HttpForbiddenException('You do not have permission to perform this action.');
}
$schedule->tasks()->where('sequence_id', '>', $task->sequence_id)->update([ $schedule->tasks()->where('sequence_id', '>', $task->sequence_id)->update([
'sequence_id' => $schedule->tasks()->getConnection()->raw('(sequence_id - 1)'), 'sequence_id' => $schedule->tasks()->getConnection()->raw('(sequence_id - 1)'),
]); ]);

View File

@ -34,7 +34,7 @@ class ServerController extends ClientApiController
public function index(GetServerRequest $request, Server $server): array public function index(GetServerRequest $request, Server $server): array
{ {
return $this->fractal->item($server) return $this->fractal->item($server)
->transformWith($this->getTransformer(ServerTransformer::class)) ->transformWith(ServerTransformer::class)
->addMeta([ ->addMeta([
'is_server_owner' => $request->user()->id === $server->owner_id, 'is_server_owner' => $request->user()->id === $server->owner_id,
'user_permissions' => $this->permissionsService->handle($server, $request->user()), 'user_permissions' => $this->permissionsService->handle($server, $request->user()),

View File

@ -42,7 +42,7 @@ class StartupController extends ClientApiController
return $this->fractal->collection( return $this->fractal->collection(
$server->variables()->where('user_viewable', true)->get() $server->variables()->where('user_viewable', true)->get()
) )
->transformWith($this->getTransformer(EggVariableTransformer::class)) ->transformWith(EggVariableTransformer::class)
->addMeta([ ->addMeta([
'startup_command' => $startup, 'startup_command' => $startup,
'docker_images' => $server->egg->docker_images, 'docker_images' => $server->egg->docker_images,
@ -86,7 +86,7 @@ class StartupController extends ClientApiController
$startup = $this->startupCommandService->handle($server, false); $startup = $this->startupCommandService->handle($server, false);
return $this->fractal->item($variable) return $this->fractal->item($variable)
->transformWith($this->getTransformer(EggVariableTransformer::class)) ->transformWith(EggVariableTransformer::class)
->addMeta([ ->addMeta([
'startup_command' => $startup, 'startup_command' => $startup,
'raw_startup_command' => $server->startup, 'raw_startup_command' => $server->startup,

View File

@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Pterodactyl\Models\Subuser;
use Pterodactyl\Models\Permission; use Pterodactyl\Models\Permission;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Pterodactyl\Repositories\Eloquent\SubuserRepository; use Pterodactyl\Repositories\Eloquent\SubuserRepository;
@ -47,7 +48,7 @@ class SubuserController extends ClientApiController
public function index(GetSubuserRequest $request, Server $server): array public function index(GetSubuserRequest $request, Server $server): array
{ {
return $this->fractal->collection($server->subusers) return $this->fractal->collection($server->subusers)
->transformWith($this->getTransformer(SubuserTransformer::class)) ->transformWith(SubuserTransformer::class)
->toArray(); ->toArray();
} }
@ -56,12 +57,10 @@ class SubuserController extends ClientApiController
* *
* @throws \Illuminate\Contracts\Container\BindingResolutionException * @throws \Illuminate\Contracts\Container\BindingResolutionException
*/ */
public function view(GetSubuserRequest $request): array public function view(GetSubuserRequest $request, Server $server, Subuser $subuser): array
{ {
$subuser = $request->attributes->get('subuser');
return $this->fractal->item($subuser) return $this->fractal->item($subuser)
->transformWith($this->getTransformer(SubuserTransformer::class)) ->transformWith(SubuserTransformer::class)
->toArray(); ->toArray();
} }
@ -82,7 +81,7 @@ class SubuserController extends ClientApiController
); );
return $this->fractal->item($response) return $this->fractal->item($response)
->transformWith($this->getTransformer(SubuserTransformer::class)) ->transformWith(SubuserTransformer::class)
->toArray(); ->toArray();
} }
@ -93,11 +92,8 @@ class SubuserController extends ClientApiController
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Illuminate\Contracts\Container\BindingResolutionException * @throws \Illuminate\Contracts\Container\BindingResolutionException
*/ */
public function update(UpdateSubuserRequest $request, Server $server): array public function update(UpdateSubuserRequest $request, Server $server, Subuser $subuser): array
{ {
/** @var \Pterodactyl\Models\Subuser $subuser */
$subuser = $request->attributes->get('subuser');
$permissions = $this->getDefaultPermissions($request); $permissions = $this->getDefaultPermissions($request);
$current = $subuser->permissions; $current = $subuser->permissions;
@ -121,18 +117,15 @@ class SubuserController extends ClientApiController
} }
return $this->fractal->item($subuser->refresh()) return $this->fractal->item($subuser->refresh())
->transformWith($this->getTransformer(SubuserTransformer::class)) ->transformWith(SubuserTransformer::class)
->toArray(); ->toArray();
} }
/** /**
* Removes a subusers from a server's assignment. * Removes a subusers from a server's assignment.
*/ */
public function delete(DeleteSubuserRequest $request, Server $server): Response public function delete(DeleteSubuserRequest $request, Server $server, Subuser $subuser): Response
{ {
/** @var \Pterodactyl\Models\Subuser $subuser */
$subuser = $request->attributes->get('subuser');
$this->repository->delete($subuser->id); $this->repository->delete($subuser->id);
try { try {

View File

@ -5,11 +5,10 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Pterodactyl\Models\Permission;
use Pterodactyl\Services\Nodes\NodeJWTService; use Pterodactyl\Services\Nodes\NodeJWTService;
use Pterodactyl\Exceptions\Http\HttpForbiddenException; use Pterodactyl\Exceptions\Http\HttpForbiddenException;
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
use Pterodactyl\Services\Servers\GetUserPermissionsService; use Pterodactyl\Services\Servers\GetUserPermissionsService;
use Pterodactyl\Http\Requests\Api\Client\WebsocketTokenRequest;
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController; use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
class WebsocketController extends ClientApiController class WebsocketController extends ClientApiController
@ -36,14 +35,9 @@ class WebsocketController extends ClientApiController
* allows us to continually renew this token and avoid users maintaining sessions wrongly, * allows us to continually renew this token and avoid users maintaining sessions wrongly,
* as well as ensure that user's only perform actions they're allowed to. * as well as ensure that user's only perform actions they're allowed to.
*/ */
public function __invoke(ClientApiRequest $request, Server $server): JsonResponse public function __invoke(WebsocketTokenRequest $request, Server $server): JsonResponse
{ {
$user = $request->user(); $permissions = $this->permissionsService->handle($server, $request->user());
if ($user->cannot(Permission::ACTION_WEBSOCKET_CONNECT, $server)) {
throw new HttpForbiddenException('You do not have permission to connect to this server\'s websocket.');
}
$permissions = $this->permissionsService->handle($server, $user);
$node = $server->node; $node = $server->node;
if (!is_null($server->transfer)) { if (!is_null($server->transfer)) {
@ -65,7 +59,7 @@ class WebsocketController extends ClientApiController
'server_uuid' => $server->uuid, 'server_uuid' => $server->uuid,
'permissions' => $permissions, 'permissions' => $permissions,
]) ])
->handle($node, $user->id . $server->uuid); ->handle($node, $request->user()->id . $server->uuid);
$socket = str_replace(['https://', 'http://'], ['wss://', 'ws://'], $node->getConnectionAddress()); $socket = str_replace(['https://', 'http://'], ['wss://', 'ws://'], $node->getConnectionAddress());

View File

@ -55,8 +55,6 @@ class TwoFactorController extends ClientApiController
/** /**
* Updates a user's account to have two-factor enabled. * Updates a user's account to have two-factor enabled.
* *
* @return \Illuminate\Http\JsonResponse
*
* @throws \Throwable * @throws \Throwable
* @throws \Illuminate\Validation\ValidationException * @throws \Illuminate\Validation\ValidationException
* @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException * @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException

View File

@ -5,8 +5,8 @@ namespace Pterodactyl\Http\Controllers\Api\Client;
use Exception; use Exception;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use LaravelWebauthn\Facades\Webauthn;
use Pterodactyl\Models\WebauthnKey; use Pterodactyl\Models\WebauthnKey;
use LaravelWebauthn\Facades\Webauthn;
use Webauthn\PublicKeyCredentialCreationOptions; use Webauthn\PublicKeyCredentialCreationOptions;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Transformers\Api\Client\WebauthnKeyTransformer; use Pterodactyl\Transformers\Api\Client\WebauthnKeyTransformer;
@ -24,7 +24,7 @@ class WebauthnController extends ClientApiController
public function index(Request $request): array public function index(Request $request): array
{ {
return $this->fractal->collection(WebauthnKey::query()->where('user_id', '=', $request->user()->id)->get()) return $this->fractal->collection(WebauthnKey::query()->where('user_id', '=', $request->user()->id)->get())
->transformWith($this->getTransformer(WebauthnKeyTransformer::class)) ->transformWith(WebauthnKeyTransformer::class)
->toArray(); ->toArray();
} }
@ -88,7 +88,7 @@ class WebauthnController extends ClientApiController
); );
return $this->fractal->item($webauthnKey) return $this->fractal->item($webauthnKey)
->transformWith($this->getTransformer(WebauthnKeyTransformer::class)) ->transformWith(WebauthnKeyTransformer::class)
->toArray(); ->toArray();
} catch (Exception $e) { } catch (Exception $e) {
return new JsonResponse([ return new JsonResponse([

View File

@ -17,7 +17,6 @@ class LoginCheckpointController extends AbstractLoginController
private Encrypter $encrypter; private Encrypter $encrypter;
private Google2FA $google2FA; private Google2FA $google2FA;
/** /**
* LoginCheckpointController constructor. * LoginCheckpointController constructor.
*/ */
@ -51,6 +50,7 @@ class LoginCheckpointController extends AbstractLoginController
{ {
if ($this->hasTooManyLoginAttempts($request)) { if ($this->hasTooManyLoginAttempts($request)) {
$this->sendLockoutResponse($request); $this->sendLockoutResponse($request);
return; return;
} }
@ -66,6 +66,7 @@ class LoginCheckpointController extends AbstractLoginController
null, null,
'The authentication token provided has expired, please refresh the page and try again.' 'The authentication token provided has expired, please refresh the page and try again.'
); );
return; return;
} }

View File

@ -69,6 +69,7 @@ class LoginController extends AbstractLoginController
if ($this->hasTooManyLoginAttempts($request)) { if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request); $this->fireLockoutEvent($request);
$this->sendLockoutResponse($request); $this->sendLockoutResponse($request);
return; return;
} }
@ -77,6 +78,7 @@ class LoginController extends AbstractLoginController
$user = $this->repository->findFirstWhere([[$useColumn, '=', $username]]); $user = $this->repository->findFirstWhere([[$useColumn, '=', $username]]);
} catch (RecordNotFoundException $exception) { } catch (RecordNotFoundException $exception) {
$this->sendFailedLoginResponse($request); $this->sendFailedLoginResponse($request);
return; return;
} }
@ -86,12 +88,13 @@ class LoginController extends AbstractLoginController
// can proceed to the next step in the login process. // can proceed to the next step in the login process.
if (!password_verify($request->input('password'), $user->password)) { if (!password_verify($request->input('password'), $user->password)) {
$this->sendFailedLoginResponse($request, $user); $this->sendFailedLoginResponse($request, $user);
return; return;
} }
$webauthnKeys = $user->webauthnKeys()->get(); $webauthnKeys = $user->webauthnKeys()->get();
if (sizeof($webauthnKeys) > 0) { if (count($webauthnKeys) > 0) {
$token = Str::random(64); $token = Str::random(64);
$this->cache->put($token, $user->id, CarbonImmutable::now()->addMinutes(5)); $this->cache->put($token, $user->id, CarbonImmutable::now()->addMinutes(5));
@ -99,7 +102,7 @@ class LoginController extends AbstractLoginController
$request->session()->put(self::SESSION_PUBLICKEY_REQUEST, $publicKey); $request->session()->put(self::SESSION_PUBLICKEY_REQUEST, $publicKey);
$request->session()->save(); $request->session()->save();
$methods = [ self::METHOD_WEBAUTHN ]; $methods = [self::METHOD_WEBAUTHN];
if ($user->use_totp) { if ($user->use_totp) {
$methods[] = self::METHOD_TOTP; $methods[] = self::METHOD_TOTP;
} }
@ -112,19 +115,17 @@ class LoginController extends AbstractLoginController
'public_key' => $publicKey, 'public_key' => $publicKey,
], ],
]); ]);
} else if ($user->use_totp) { } elseif ($user->use_totp) {
$token = Str::random(64); $token = Str::random(64);
$this->cache->put($token, $user->id, CarbonImmutable::now()->addMinutes(5)); $this->cache->put($token, $user->id, CarbonImmutable::now()->addMinutes(5));
return new JsonResponse([ return new JsonResponse([
'complete' => false, 'complete' => false,
'methods' => [ self::METHOD_TOTP ], 'methods' => [self::METHOD_TOTP],
'confirmation_token' => $token, 'confirmation_token' => $token,
]); ]);
} }
$this->auth->guard()->login($user, true);
return $this->sendLoginResponse($user, $request); return $this->sendLoginResponse($user, $request);
} }
} }

View File

@ -3,8 +3,8 @@
namespace Pterodactyl\Http\Controllers\Auth; namespace Pterodactyl\Http\Controllers\Auth;
use Exception; use Exception;
use Pterodactyl\Models\User;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Pterodactyl\Models\User;
use Illuminate\Auth\AuthManager; use Illuminate\Auth\AuthManager;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use LaravelWebauthn\Facades\Webauthn; use LaravelWebauthn\Facades\Webauthn;
@ -36,6 +36,7 @@ class WebauthnController extends AbstractLoginController
{ {
if ($this->hasTooManyLoginAttempts($request)) { if ($this->hasTooManyLoginAttempts($request)) {
$this->sendLockoutResponse($request); $this->sendLockoutResponse($request);
return; return;
} }
@ -51,6 +52,7 @@ class WebauthnController extends AbstractLoginController
null, null,
'The authentication token provided has expired, please refresh the page and try again.' 'The authentication token provided has expired, please refresh the page and try again.'
); );
return; return;
} }
$this->auth->guard()->onceUsingId($user->id); $this->auth->guard()->onceUsingId($user->id);

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Http; namespace Pterodactyl\Http;
use Pterodactyl\Models\ApiKey;
use Illuminate\Auth\Middleware\Authorize; use Illuminate\Auth\Middleware\Authorize;
use Illuminate\Auth\Middleware\Authenticate; use Illuminate\Auth\Middleware\Authenticate;
use Pterodactyl\Http\Middleware\TrimStrings; use Pterodactyl\Http\Middleware\TrimStrings;
@ -16,24 +15,23 @@ use Pterodactyl\Http\Middleware\AdminAuthenticate;
use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Routing\Middleware\ThrottleRequests;
use Pterodactyl\Http\Middleware\LanguageMiddleware; use Pterodactyl\Http\Middleware\LanguageMiddleware;
use Illuminate\Foundation\Http\Kernel as HttpKernel; use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Pterodactyl\Http\Middleware\Api\AuthenticateKey;
use Illuminate\Routing\Middleware\SubstituteBindings; use Illuminate\Routing\Middleware\SubstituteBindings;
use Pterodactyl\Http\Middleware\Api\SetSessionDriver;
use Illuminate\Session\Middleware\AuthenticateSession; use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\View\Middleware\ShareErrorsFromSession; use Illuminate\View\Middleware\ShareErrorsFromSession;
use Pterodactyl\Http\Middleware\MaintenanceMiddleware; use Pterodactyl\Http\Middleware\MaintenanceMiddleware;
use Pterodactyl\Http\Middleware\RedirectIfAuthenticated; use Pterodactyl\Http\Middleware\RedirectIfAuthenticated;
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth; use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
use Pterodactyl\Http\Middleware\Api\AuthenticateIPAccess; use Pterodactyl\Http\Middleware\Api\PreventUnboundModels;
use Pterodactyl\Http\Middleware\Api\ApiSubstituteBindings;
use Illuminate\Foundation\Http\Middleware\ValidatePostSize; use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Pterodactyl\Http\Middleware\Api\Daemon\DaemonAuthenticate; use Pterodactyl\Http\Middleware\Api\Daemon\DaemonAuthenticate;
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication; use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull; use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
use Pterodactyl\Http\Middleware\Api\Client\SubstituteClientApiBindings; use Pterodactyl\Http\Middleware\Api\Client\SubstituteClientApiBindings;
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance;
use Pterodactyl\Http\Middleware\Api\Application\AuthenticateApplicationUser; use Pterodactyl\Http\Middleware\Api\Application\AuthenticateApplicationUser;
use Pterodactyl\Http\Middleware\Api\Application\SubstituteApplicationApiBindings;
class Kernel extends HttpKernel class Kernel extends HttpKernel
{ {
@ -43,12 +41,11 @@ class Kernel extends HttpKernel
* @var array * @var array
*/ */
protected $middleware = [ protected $middleware = [
CheckForMaintenanceMode::class, TrustProxies::class,
EncryptCookies::class, PreventRequestsDuringMaintenance::class,
ValidatePostSize::class, ValidatePostSize::class,
TrimStrings::class, TrimStrings::class,
ConvertEmptyStringsToNull::class, ConvertEmptyStringsToNull::class,
TrustProxies::class,
]; ];
/** /**
@ -58,6 +55,7 @@ class Kernel extends HttpKernel
*/ */
protected $middlewareGroups = [ protected $middlewareGroups = [
'web' => [ 'web' => [
EncryptCookies::class,
AddQueuedCookiesToResponse::class, AddQueuedCookiesToResponse::class,
StartSession::class, StartSession::class,
AuthenticateSession::class, AuthenticateSession::class,
@ -69,20 +67,19 @@ class Kernel extends HttpKernel
], ],
'api' => [ 'api' => [
IsValidJson::class, IsValidJson::class,
ApiSubstituteBindings::class, EnsureFrontendRequestsAreStateful::class,
SetSessionDriver::class, 'auth:sanctum',
'api..key:' . ApiKey::TYPE_APPLICATION, SubstituteApplicationApiBindings::class,
PreventUnboundModels::class,
AuthenticateApplicationUser::class, AuthenticateApplicationUser::class,
AuthenticateIPAccess::class, RequireTwoFactorAuthentication::class,
], ],
'client-api' => [ 'client-api' => [
StartSession::class,
SetSessionDriver::class,
AuthenticateSession::class,
IsValidJson::class, IsValidJson::class,
EnsureFrontendRequestsAreStateful::class,
'auth:sanctum',
SubstituteClientApiBindings::class, SubstituteClientApiBindings::class,
'api..key:' . ApiKey::TYPE_ACCOUNT, PreventUnboundModels::class,
AuthenticateIPAccess::class,
// This is perhaps a little backwards with the Client API, but logically you'd be unable // This is perhaps a little backwards with the Client API, but logically you'd be unable
// to create/get an API key without first enabling 2FA on the account, so I suppose in the // to create/get an API key without first enabling 2FA on the account, so I suppose in the
// end it makes sense. // end it makes sense.
@ -112,8 +109,5 @@ class Kernel extends HttpKernel
'bindings' => SubstituteBindings::class, 'bindings' => SubstituteBindings::class,
'recaptcha' => VerifyReCaptcha::class, 'recaptcha' => VerifyReCaptcha::class,
'node.maintenance' => MaintenanceMiddleware::class, 'node.maintenance' => MaintenanceMiddleware::class,
// API Specific Middleware
'api..key' => AuthenticateKey::class,
]; ];
} }

View File

@ -1,87 +0,0 @@
<?php
namespace Pterodactyl\Http\Middleware\Api;
use Closure;
use Pterodactyl\Models\Egg;
use Pterodactyl\Models\Nest;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Database;
use Pterodactyl\Models\Location;
use Pterodactyl\Models\Allocation;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Database\Eloquent\ModelNotFoundException;
class ApiSubstituteBindings extends SubstituteBindings
{
/**
* Mappings to automatically assign route parameters to a model.
*
* @var array
*/
protected static $mappings = [
'allocation' => Allocation::class,
'database' => Database::class,
'egg' => Egg::class,
'location' => Location::class,
'nest' => Nest::class,
'node' => Node::class,
'server' => Server::class,
'user' => User::class,
];
/**
* @var \Illuminate\Routing\Router
*/
protected $router;
/**
* Perform substitution of route parameters without triggering
* a 404 error if a model is not found.
*
* @param \Illuminate\Http\Request $request
*
* @return mixed
*/
public function handle($request, Closure $next)
{
$route = $request->route();
foreach (self::$mappings as $key => $model) {
if (!is_null($this->router->getBindingCallback($key))) {
continue;
}
$this->router->model($key, $model, function () use ($request) {
$request->attributes->set('is_missing_model', true);
});
}
$this->router->substituteBindings($route);
// Attempt to resolve bindings for this route. If one of the models
// cannot be resolved do not immediately return a 404 error. Set a request
// attribute that can be checked in the base API request class to only
// trigger a 404 after validating that the API key making the request is valid
// and even has permission to access the requested resource.
try {
$this->router->substituteImplicitBindings($route);
} catch (ModelNotFoundException $exception) {
$request->attributes->set('is_missing_model', true);
}
return $next($request);
}
/**
* Return the registered mappings.
*
* @return array
*/
public static function getMappings()
{
return self::$mappings;
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace Pterodactyl\Http\Middleware\Api\Application;
use Closure;
use Pterodactyl\Models\Egg;
use Pterodactyl\Models\Nest;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Database;
use Pterodactyl\Models\Location;
use Pterodactyl\Models\Allocation;
use Illuminate\Contracts\Routing\Registrar;
use Illuminate\Database\Eloquent\ModelNotFoundException;
class SubstituteApplicationApiBindings
{
protected Registrar $router;
/**
* Mappings to automatically assign route parameters to a model.
*/
protected static array $mappings = [
'allocation' => Allocation::class,
'database' => Database::class,
'egg' => Egg::class,
'location' => Location::class,
'nest' => Nest::class,
'node' => Node::class,
'server' => Server::class,
'user' => User::class,
];
public function __construct(Registrar $router)
{
$this->router = $router;
}
/**
* Perform substitution of route parameters without triggering
* a 404 error if a model is not found.
*
* @param \Illuminate\Http\Request $request
*
* @return mixed
*/
public function handle($request, Closure $next)
{
foreach (self::$mappings as $key => $class) {
$this->router->bind($key, $class);
}
try {
$this->router->substituteImplicitBindings($route = $request->route());
} catch (ModelNotFoundException $exception) {
if (isset($route) && $route->getMissing()) {
$route->getMissing()($request);
}
throw $exception;
}
return $next($request);
}
}

View File

@ -1,38 +0,0 @@
<?php
namespace Pterodactyl\Http\Middleware\Api;
use Closure;
use IPTools\IP;
use IPTools\Range;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
class AuthenticateIPAccess
{
/**
* Determine if a request IP has permission to access the API.
*
* @return mixed
*
* @throws \Exception
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
*/
public function handle(Request $request, Closure $next)
{
$model = $request->attributes->get('api_key');
if (is_null($model->allowed_ips) || empty($model->allowed_ips)) {
return $next($request);
}
$find = new IP($request->ip());
foreach ($model->allowed_ips as $ip) {
if (Range::parse($ip)->contains($find)) {
return $next($request);
}
}
throw new AccessDeniedHttpException('This IP address (' . $request->ip() . ') does not have permission to access the API using these credentials.');
}
}

View File

@ -1,95 +0,0 @@
<?php
namespace Pterodactyl\Http\Middleware\Api;
use Closure;
use Carbon\CarbonImmutable;
use Illuminate\Http\Request;
use Pterodactyl\Models\User;
use Pterodactyl\Models\ApiKey;
use Illuminate\Auth\AuthManager;
use Illuminate\Contracts\Encryption\Encrypter;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
class AuthenticateKey
{
private AuthManager $auth;
private Encrypter $encrypter;
private ApiKeyRepositoryInterface $repository;
/**
* AuthenticateKey constructor.
*/
public function __construct(ApiKeyRepositoryInterface $repository, AuthManager $auth, Encrypter $encrypter)
{
$this->auth = $auth;
$this->encrypter = $encrypter;
$this->repository = $repository;
}
/**
* Handle an API request by verifying that the provided API key
* is in a valid format and exists in the database.
*
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function handle(Request $request, Closure $next, int $keyType)
{
if (is_null($request->bearerToken()) && is_null($request->user())) {
throw new HttpException(401, null, null, ['WWW-Authenticate' => 'Bearer']);
}
$raw = $request->bearerToken();
// This is a request coming through using cookies, we have an authenticated user not using
// an API key. Make some fake API key models and continue on through the process.
if (empty($raw) && $request->user() instanceof User) {
$model = (new ApiKey())->forceFill([
'user_id' => $request->user()->id,
'key_type' => ApiKey::TYPE_ACCOUNT,
]);
} else {
$model = $this->authenticateApiKey($raw, $keyType);
$this->auth->guard()->loginUsingId($model->user_id);
}
$request->attributes->set('api_key', $model);
return $next($request);
}
/**
* Authenticate an API key.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
protected function authenticateApiKey(string $key, int $keyType): ApiKey
{
$identifier = substr($key, 0, ApiKey::IDENTIFIER_LENGTH);
$token = substr($key, ApiKey::IDENTIFIER_LENGTH);
try {
$model = $this->repository->findFirstWhere([
['identifier', '=', $identifier],
['key_type', '=', $keyType],
]);
} catch (RecordNotFoundException $exception) {
throw new AccessDeniedHttpException();
}
if (!hash_equals($this->encrypter->decrypt($model->token), $token)) {
throw new AccessDeniedHttpException();
}
$this->repository->withoutFreshModel()->update($model->id, ['last_used_at' => CarbonImmutable::now()]);
return $model;
}
}

View File

@ -3,60 +3,102 @@
namespace Pterodactyl\Http\Middleware\Api\Client; namespace Pterodactyl\Http\Middleware\Api\Client;
use Closure; use Closure;
use Pterodactyl\Models\User; use Illuminate\Support\Str;
use Pterodactyl\Models\Backup; use Pterodactyl\Models\Task;
use Pterodactyl\Models\Database; use Illuminate\Routing\Route;
use Pterodactyl\Models\Server;
use Illuminate\Container\Container; use Illuminate\Container\Container;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Contracts\Routing\Registrar;
use Pterodactyl\Contracts\Extensions\HashidsInterface; use Pterodactyl\Contracts\Extensions\HashidsInterface;
use Pterodactyl\Http\Middleware\Api\ApiSubstituteBindings; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
class SubstituteClientApiBindings extends ApiSubstituteBindings class SubstituteClientApiBindings
{ {
protected Registrar $router;
public function __construct(Registrar $router)
{
$this->router = $router;
}
/** /**
* Perform substitution of route parameters without triggering * Perform substitution of route parameters for the Client API.
* a 404 error if a model is not found.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request
* *
* @return mixed * @return mixed
*/ */
public function handle($request, Closure $next) public function handle($request, Closure $next)
{ {
// Override default behavior of the model binding to use a specific table $this->router->bind('server', function ($value) {
// column rather than the default 'id'. return Server::query()->where(Str::length($value) === 8 ? 'uuidShort' : 'uuid', $value)->firstOrFail();
$this->router->bind('server', function ($value) use ($request) {
try {
$column = 'uuidShort';
if (preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $value)) {
$column = 'uuid';
}
return Container::getInstance()->make(ServerRepositoryInterface::class)->findFirstWhere([
[$column, '=', $value],
]);
} catch (RecordNotFoundException $ex) {
$request->attributes->set('is_missing_model', true);
return null;
}
}); });
$this->router->bind('database', function ($value) { $this->router->bind('allocation', function ($value, $route) {
return $this->server($route)->allocations()->findOrFail($value);
});
$this->router->bind('schedule', function ($value, $route) {
return $this->server($route)->schedule()->findOrFail($value);
});
$this->router->bind('task', function ($value, $route) {
return Task::query()
->select('tasks.*')
->join('schedules', function (JoinClause $join) use ($route) {
$join->on('schedules.id', 'tasks.schedule_id')
->where('schedules.server_id', $route->parameter('server')->id);
})
->where('schedules.id', $route->parameter('schedule')->id)
->findOrFail($value);
});
$this->router->bind('database', function ($value, $route) {
$id = Container::getInstance()->make(HashidsInterface::class)->decodeFirst($value); $id = Container::getInstance()->make(HashidsInterface::class)->decodeFirst($value);
return Database::query()->where('id', $id)->firstOrFail(); return $this->server($route)->databases()->findOrFail($id);
}); });
$this->router->bind('backup', function ($value) { $this->router->bind('backup', function ($value, $route) {
return Backup::query()->where('uuid', $value)->firstOrFail(); return $this->server($route)->backups()->where('uuid', $value)->firstOrFail();
}); });
$this->router->bind('user', function ($value) { $this->router->bind('subuser', function ($value, $route) {
return User::query()->where('uuid', $value)->firstOrFail(); return $this->server($route)->subusers()
->select('subusers.*')
->join('users', 'subusers.user_id', '=', 'users.id')
->where('users.uuid', $value)
->firstOrFail();
}); });
return parent::handle($request, $next); try {
/* @var \Illuminate\Routing\Route $route */
$this->router->substituteBindings($route = $request->route());
} catch (ModelNotFoundException $exception) {
if (isset($route) && $route->getMissing()) {
$route->getMissing()($request);
}
throw $exception;
}
return $next($request);
}
/**
* Plucks the server model off the route. If no server model is present a
* ModelNotFound exception will be thrown.
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
private function server(Route $route): Server
{
$server = $route->parameter('server');
if (!$server instanceof Server) {
throw (new ModelNotFoundException())->setModel(Server::class, [$route->parameter('server')]);
}
return $server;
} }
} }

View File

@ -0,0 +1,45 @@
<?php
namespace Pterodactyl\Http\Middleware\Api;
use Closure;
use Exception;
use Illuminate\Support\Reflector;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Routing\UrlRoutable;
class PreventUnboundModels
{
/**
* Prevents a request from making it to a controller action if there is a model
* injection on the controller that has not been explicitly bound by the request.
* This prevents empty models from being valid in scenarios where a new model is
* added but not properly defined in the substitution middleware.
*
* @param \Illuminate\Http\Request $request
*
* @return mixed
*
* @throws \Exception
*/
public function handle($request, Closure $next)
{
$route = $request->route();
$parameters = $route->parameters() ?? [];
/** @var \ReflectionParameter[] $signatures */
$signatures = $route->signatureParameters(UrlRoutable::class);
foreach ($signatures as $signature) {
$class = Reflector::getParameterClassName($signature);
if (is_null($class) || !is_subclass_of($class, Model::class)) {
continue;
}
if (!$parameters[$signature->getName()] instanceof Model) {
throw new Exception(sprintf('No parameter binding has been defined for model [%s] using route parameter key "%s".', $class, $signature->getName()));
}
}
return $next($request);
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace Pterodactyl\Http\Middleware\Api;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
class SetSessionDriver
{
/**
* @var \Illuminate\Contracts\Config\Repository
*/
private $config;
/**
* SetSessionDriver constructor.
*/
public function __construct(ConfigRepository $config)
{
$this->config = $config;
}
/**
* Set the session for API calls to only last for the one request.
*
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$this->config->set('session.driver', 'array');
return $next($request);
}
}

View File

@ -14,6 +14,6 @@ class VerifyCsrfToken extends BaseVerifier
protected $except = [ protected $except = [
'remote/*', 'remote/*',
'daemon/*', 'daemon/*',
'api/*', // 'api/*',
]; ];
} }

View File

@ -0,0 +1,83 @@
<?php
namespace Pterodactyl\Http\Requests\Api;
use Illuminate\Foundation\Http\FormRequest;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* @method \Pterodactyl\Models\User user($guard = null)
*/
abstract class ApiRequest extends FormRequest
{
/**
* Tracks if the request has been validated internally or not to avoid
* making duplicate validation calls.
*/
private bool $hasValidated = false;
/**
* Determine if the current user is authorized to perform the requested
* action against the API.
*/
public function authorize(): bool
{
return false;
}
/**
* Default set of rules to apply to API requests.
*/
public function rules(): array
{
return [];
}
/**
* Validate that the resource exists and can be accessed prior to booting
* the validator and attempting to use the data.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
protected function prepareForValidation()
{
if (!$this->passesAuthorization()) {
$this->failedAuthorization();
}
$this->hasValidated = true;
}
/*
* Determine if the request passes the authorization check as well
* as the exists check.
*
* @return bool
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
protected function passesAuthorization()
{
// If we have already validated we do not need to call this function
// again. This is needed to work around Laravel's normal auth validation
// that occurs after validating the request params since we are doing auth
// validation in the prepareForValidation() function.
if ($this->hasValidated) {
return true;
}
if (!parent::passesAuthorization()) {
return false;
}
// Only let the user know that a resource does not exist if they are
// authenticated to access the endpoint. This avoids exposing that
// an item exists (or does not exist) to the user until they can prove
// that they have permission to know about it.
if ($this->attributes->get('is_missing_model', false)) {
throw new NotFoundHttpException(trans('exceptions.api.resource_not_found'));
}
return true;
}
}

View File

@ -2,31 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Allocations; namespace Pterodactyl\Http\Requests\Api\Application\Allocations;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\Allocation;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class DeleteAllocationRequest extends ApplicationApiRequest class DeleteAllocationRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_ALLOCATIONS;
protected int $permission = AdminAcl::WRITE;
/**
* Determine if the requested allocation exists and belongs to the node that
* is being passed in the URL.
*/
public function resourceExists(): bool
{
$node = $this->route()->parameter('node');
$allocation = $this->route()->parameter('allocation');
if ($node instanceof Node && $node->exists) {
if ($allocation instanceof Allocation && $allocation->exists && $allocation->node_id === $node->id) {
return true;
}
}
return false;
}
} }

View File

@ -2,23 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Allocations; namespace Pterodactyl\Http\Requests\Api\Application\Allocations;
use Pterodactyl\Models\Node;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetAllocationsRequest extends ApplicationApiRequest class GetAllocationsRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_ALLOCATIONS;
protected int $permission = AdminAcl::READ;
/**
* Determine if the node that we are requesting the allocations
* for exists on the Panel.
*/
public function resourceExists(): bool
{
$node = $this->route()->parameter('node');
return $node instanceof Node && $node->exists;
}
} }

View File

@ -2,14 +2,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Allocations; namespace Pterodactyl\Http\Requests\Api\Application\Allocations;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreAllocationRequest extends ApplicationApiRequest class StoreAllocationRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_ALLOCATIONS;
protected int $permission = AdminAcl::WRITE;
public function rules(): array public function rules(): array
{ {
return [ return [

View File

@ -2,147 +2,16 @@
namespace Pterodactyl\Http\Requests\Api\Application; namespace Pterodactyl\Http\Requests\Api\Application;
use Pterodactyl\Models\ApiKey; use Pterodactyl\Http\Requests\Api\ApiRequest;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Illuminate\Foundation\Http\FormRequest;
use Pterodactyl\Exceptions\PterodactylException;
use Pterodactyl\Http\Middleware\Api\ApiSubstituteBindings;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Exception\InvalidParameterException;
abstract class ApplicationApiRequest extends FormRequest abstract class ApplicationApiRequest extends ApiRequest
{ {
/** /**
* Tracks if the request has been validated internally or not to avoid * This will eventually be replaced with per-request permissions checking
* making duplicate validation calls. * on the API key and for the user.
*/
private bool $hasValidated = false;
/**
* The resource that should be checked when performing the authorization
* function for this request.
*
* @var string|null
*/
protected string $resource;
/**
* The permission level that a given API key should have for accessing
* the defined $resource during the request cycle.
*
* @var int
*/
protected int $permission = AdminAcl::NONE;
/**
* Determine if the current user is authorized to perform
* the requested action against the API.
*
* @throws \Pterodactyl\Exceptions\PterodactylException
*/ */
public function authorize(): bool public function authorize(): bool
{ {
if (is_null($this->resource)) { return $this->user()->root_admin;
throw new PterodactylException('An ACL resource must be defined on API requests.');
}
if ($this->key()->key_type === ApiKey::TYPE_ACCOUNT) {
return $this->user()->root_admin;
}
return AdminAcl::check($this->key(), $this->resource, $this->permission);
}
/**
* Determine if the requested resource exists on the server.
*/
public function resourceExists(): bool
{
return true;
}
/**
* Default set of rules to apply to API requests.
*/
public function rules(): array
{
return [];
}
/**
* Return the API key being used for the request.
*/
public function key(): ApiKey
{
return $this->attributes->get('api_key');
}
/**
* Grab a model from the route parameters. If no model is found in the
* binding mappings an exception will be thrown.
*
* @return mixed
*
* @deprecated
*
* @throws \Symfony\Component\Routing\Exception\InvalidParameterException
*/
public function getModel(string $model)
{
$parameterKey = array_get(array_flip(ApiSubstituteBindings::getMappings()), $model);
if (is_null($parameterKey)) {
throw new InvalidParameterException();
}
return $this->route()->parameter($parameterKey);
}
/**
* Validate that the resource exists and can be accessed prior to booting
* the validator and attempting to use the data.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
protected function prepareForValidation()
{
if (!$this->passesAuthorization()) {
$this->failedAuthorization();
}
$this->hasValidated = true;
}
/*
* Determine if the request passes the authorization check as well
* as the exists check.
*
* @return bool
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
protected function passesAuthorization()
{
// If we have already validated we do not need to call this function
// again. This is needed to work around Laravel's normal auth validation
// that occurs after validating the request params since we are doing auth
// validation in the prepareForValidation() function.
if ($this->hasValidated) {
return true;
}
if (!parent::passesAuthorization()) {
return false;
}
// Only let the user know that a resource does not exist if they are
// authenticated to access the endpoint. This avoids exposing that
// an item exists (or does not exist) to the user until they can prove
// that they have permission to know about it.
if ($this->attributes->get('is_missing_model', false) || !$this->resourceExists()) {
throw new NotFoundHttpException(trans('exceptions.api.resource_not_found'));
}
return true;
} }
} }

View File

@ -2,19 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Databases; namespace Pterodactyl\Http\Requests\Api\Application\Databases;
use Pterodactyl\Models\DatabaseHost;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class DeleteDatabaseRequest extends ApplicationApiRequest class DeleteDatabaseRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_DATABASE_HOSTS;
protected int $permission = AdminAcl::WRITE;
public function resourceExists(): bool
{
$databaseHost = $this->route()->parameter('databaseHost');
return $databaseHost instanceof DatabaseHost && $databaseHost->exists;
}
} }

View File

@ -2,14 +2,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Databases; namespace Pterodactyl\Http\Requests\Api\Application\Databases;
use Pterodactyl\Models\DatabaseHost;
class GetDatabaseRequest extends GetDatabasesRequest class GetDatabaseRequest extends GetDatabasesRequest
{ {
public function resourceExists(): bool
{
$databaseHost = $this->route()->parameter('databaseHost');
return $databaseHost instanceof DatabaseHost && $databaseHost->exists;
}
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Databases; namespace Pterodactyl\Http\Requests\Api\Application\Databases;
use Pterodactyl\Services\Acl\Api\AdminAcl as Acl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetDatabasesRequest extends ApplicationApiRequest class GetDatabasesRequest extends ApplicationApiRequest
{ {
protected string $resource = Acl::RESOURCE_DATABASE_HOSTS;
protected int $permission = Acl::READ;
} }

View File

@ -3,14 +3,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Databases; namespace Pterodactyl\Http\Requests\Api\Application\Databases;
use Pterodactyl\Models\DatabaseHost; use Pterodactyl\Models\DatabaseHost;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreDatabaseRequest extends ApplicationApiRequest class StoreDatabaseRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_DATABASE_HOSTS;
protected int $permission = AdminAcl::WRITE;
public function rules(array $rules = null): array public function rules(array $rules = null): array
{ {
return $rules ?? DatabaseHost::getRules(); return $rules ?? DatabaseHost::getRules();

View File

@ -3,14 +3,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Eggs; namespace Pterodactyl\Http\Requests\Api\Application\Eggs;
use Pterodactyl\Models\Egg; use Pterodactyl\Models\Egg;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class DeleteEggRequest extends ApplicationApiRequest class DeleteEggRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_EGGS;
protected int $permission = AdminAcl::WRITE;
public function resourceExists(): bool public function resourceExists(): bool
{ {
$egg = $this->route()->parameter('egg'); $egg = $this->route()->parameter('egg');

View File

@ -2,14 +2,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Eggs; namespace Pterodactyl\Http\Requests\Api\Application\Eggs;
use Pterodactyl\Models\Egg;
class GetEggRequest extends GetEggsRequest class GetEggRequest extends GetEggsRequest
{ {
public function resourceExists(): bool
{
$egg = $this->route()->parameter('egg');
return $egg instanceof Egg && $egg->exists;
}
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Eggs; namespace Pterodactyl\Http\Requests\Api\Application\Eggs;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetEggsRequest extends ApplicationApiRequest class GetEggsRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_EGGS;
protected int $permission = AdminAcl::READ;
} }

View File

@ -3,14 +3,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Eggs; namespace Pterodactyl\Http\Requests\Api\Application\Eggs;
use Pterodactyl\Models\Egg; use Pterodactyl\Models\Egg;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreEggRequest extends ApplicationApiRequest class StoreEggRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_EGGS;
protected int $permission = AdminAcl::WRITE;
public function rules(array $rules = null): array public function rules(array $rules = null): array
{ {
return $rules ?? Egg::getRules(); return $rules ?? Egg::getRules();

View File

@ -2,19 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Locations; namespace Pterodactyl\Http\Requests\Api\Application\Locations;
use Pterodactyl\Models\Location;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class DeleteLocationRequest extends ApplicationApiRequest class DeleteLocationRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_LOCATIONS;
protected int $permission = AdminAcl::WRITE;
public function resourceExists(): bool
{
$location = $this->route()->parameter('location');
return $location instanceof Location && $location->exists;
}
} }

View File

@ -2,14 +2,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Locations; namespace Pterodactyl\Http\Requests\Api\Application\Locations;
use Pterodactyl\Models\Location;
class GetLocationRequest extends GetLocationsRequest class GetLocationRequest extends GetLocationsRequest
{ {
public function resourceExists(): bool
{
$location = $this->route()->parameter('location');
return $location instanceof Location && $location->exists;
}
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Locations; namespace Pterodactyl\Http\Requests\Api\Application\Locations;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetLocationsRequest extends ApplicationApiRequest class GetLocationsRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_LOCATIONS;
protected int $permission = AdminAcl::READ;
} }

View File

@ -3,14 +3,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Locations; namespace Pterodactyl\Http\Requests\Api\Application\Locations;
use Pterodactyl\Models\Location; use Pterodactyl\Models\Location;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreLocationRequest extends ApplicationApiRequest class StoreLocationRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_LOCATIONS;
protected int $permission = AdminAcl::WRITE;
public function rules(): array public function rules(): array
{ {
return collect(Location::getRules())->only([ return collect(Location::getRules())->only([

View File

@ -6,13 +6,6 @@ use Pterodactyl\Models\Location;
class UpdateLocationRequest extends StoreLocationRequest class UpdateLocationRequest extends StoreLocationRequest
{ {
public function resourceExists(): bool
{
$location = $this->route()->parameter('location');
return $location instanceof Location && $location->exists;
}
public function rules(): array public function rules(): array
{ {
$locationId = $this->route()->parameter('location')->id; $locationId = $this->route()->parameter('location')->id;

View File

@ -2,19 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Mounts; namespace Pterodactyl\Http\Requests\Api\Application\Mounts;
use Pterodactyl\Models\Mount;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class DeleteMountRequest extends ApplicationApiRequest class DeleteMountRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_MOUNTS;
protected int $permission = AdminAcl::WRITE;
public function resourceExists(): bool
{
$mount = $this->route()->parameter('mount');
return $mount instanceof Mount && $mount->exists;
}
} }

View File

@ -2,14 +2,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Mounts; namespace Pterodactyl\Http\Requests\Api\Application\Mounts;
use Pterodactyl\Models\Mount;
class GetMountRequest extends GetMountsRequest class GetMountRequest extends GetMountsRequest
{ {
public function resourceExists(): bool
{
$mount = $this->route()->parameter('mount');
return $mount instanceof Mount && $mount->exists;
}
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Mounts; namespace Pterodactyl\Http\Requests\Api\Application\Mounts;
use Pterodactyl\Services\Acl\Api\AdminAcl as Acl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetMountsRequest extends ApplicationApiRequest class GetMountsRequest extends ApplicationApiRequest
{ {
protected string $resource = Acl::RESOURCE_MOUNTS;
protected int $permission = Acl::READ;
} }

View File

@ -2,14 +2,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Mounts; namespace Pterodactyl\Http\Requests\Api\Application\Mounts;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class MountEggsRequest extends ApplicationApiRequest class MountEggsRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_MOUNTS;
protected int $permission = AdminAcl::WRITE;
public function rules(array $rules = null): array public function rules(array $rules = null): array
{ {
return $rules ?? ['eggs' => 'required|exists:eggs,id']; return $rules ?? ['eggs' => 'required|exists:eggs,id'];

View File

@ -2,14 +2,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Mounts; namespace Pterodactyl\Http\Requests\Api\Application\Mounts;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class MountNodesRequest extends ApplicationApiRequest class MountNodesRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_MOUNTS;
protected int $permission = AdminAcl::WRITE;
public function rules(array $rules = null): array public function rules(array $rules = null): array
{ {
return $rules ?? ['nodes' => 'required|exists:nodes,id']; return $rules ?? ['nodes' => 'required|exists:nodes,id'];

View File

@ -3,14 +3,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Mounts; namespace Pterodactyl\Http\Requests\Api\Application\Mounts;
use Pterodactyl\Models\Mount; use Pterodactyl\Models\Mount;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreMountRequest extends ApplicationApiRequest class StoreMountRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_MOUNTS;
protected int $permission = AdminAcl::WRITE;
public function rules(array $rules = null): array public function rules(array $rules = null): array
{ {
return $rules ?? Mount::getRules(); return $rules ?? Mount::getRules();

View File

@ -2,19 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Nests; namespace Pterodactyl\Http\Requests\Api\Application\Nests;
use Pterodactyl\Models\Nest;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class DeleteNestRequest extends ApplicationApiRequest class DeleteNestRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_NESTS;
protected int $permission = AdminAcl::WRITE;
public function resourceExists(): bool
{
$nest = $this->route()->parameter('nest');
return $nest instanceof Nest && $nest->exists;
}
} }

View File

@ -2,14 +2,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Nests; namespace Pterodactyl\Http\Requests\Api\Application\Nests;
use Pterodactyl\Models\Nest;
class GetNestRequest extends GetNestsRequest class GetNestRequest extends GetNestsRequest
{ {
public function resourceExists(): bool
{
$nest = $this->route()->parameter('nest');
return $nest instanceof Nest && $nest->exists;
}
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Nests; namespace Pterodactyl\Http\Requests\Api\Application\Nests;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetNestsRequest extends ApplicationApiRequest class GetNestsRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_NESTS;
protected int $permission = AdminAcl::READ;
} }

View File

@ -2,17 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Nests; namespace Pterodactyl\Http\Requests\Api\Application\Nests;
use Pterodactyl\Models\Nest;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreNestRequest extends ApplicationApiRequest class StoreNestRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_NESTS;
protected int $permission = AdminAcl::WRITE;
public function rules(array $rules = null): array
{
return $rules ?? Nest::getRules();
}
} }

View File

@ -2,19 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Nodes; namespace Pterodactyl\Http\Requests\Api\Application\Nodes;
use Pterodactyl\Models\Node;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class DeleteNodeRequest extends ApplicationApiRequest class DeleteNodeRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_NODES;
protected int $permission = AdminAcl::WRITE;
public function resourceExists(): bool
{
$node = $this->route()->parameter('node');
return $node instanceof Node && $node->exists;
}
} }

View File

@ -2,14 +2,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Nodes; namespace Pterodactyl\Http\Requests\Api\Application\Nodes;
use Pterodactyl\Models\Node;
class GetNodeRequest extends GetNodesRequest class GetNodeRequest extends GetNodesRequest
{ {
public function resourceExists(): bool
{
$node = $this->route()->parameter('node');
return $node instanceof Node && $node->exists;
}
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Nodes; namespace Pterodactyl\Http\Requests\Api\Application\Nodes;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetNodesRequest extends ApplicationApiRequest class GetNodesRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_NODES;
protected int $permission = AdminAcl::READ;
} }

View File

@ -3,14 +3,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Nodes; namespace Pterodactyl\Http\Requests\Api\Application\Nodes;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreNodeRequest extends ApplicationApiRequest class StoreNodeRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_NODES;
protected int $permission = AdminAcl::WRITE;
/** /**
* Validation rules to apply to this request. * Validation rules to apply to this request.
*/ */

View File

@ -2,19 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Roles; namespace Pterodactyl\Http\Requests\Api\Application\Roles;
use Pterodactyl\Models\AdminRole;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class DeleteRoleRequest extends ApplicationApiRequest class DeleteRoleRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_ROLES;
protected int $permission = AdminAcl::WRITE;
public function resourceExists(): bool
{
$role = $this->route()->parameter('role');
return $role instanceof AdminRole && $role->exists;
}
} }

View File

@ -2,14 +2,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Roles; namespace Pterodactyl\Http\Requests\Api\Application\Roles;
use Pterodactyl\Models\AdminRole;
class GetRoleRequest extends GetRolesRequest class GetRoleRequest extends GetRolesRequest
{ {
public function resourceExists(): bool
{
$role = $this->route()->parameter('role');
return $role instanceof AdminRole && $role->exists;
}
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Roles; namespace Pterodactyl\Http\Requests\Api\Application\Roles;
use Pterodactyl\Services\Acl\Api\AdminAcl as Acl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetRolesRequest extends ApplicationApiRequest class GetRolesRequest extends ApplicationApiRequest
{ {
protected string $resource = Acl::RESOURCE_ROLES;
protected int $permission = Acl::READ;
} }

View File

@ -3,14 +3,10 @@
namespace Pterodactyl\Http\Requests\Api\Application\Roles; namespace Pterodactyl\Http\Requests\Api\Application\Roles;
use Pterodactyl\Models\AdminRole; use Pterodactyl\Models\AdminRole;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreRoleRequest extends ApplicationApiRequest class StoreRoleRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_ROLES;
protected int $permission = AdminAcl::WRITE;
public function rules(array $rules = null): array public function rules(array $rules = null): array
{ {
return $rules ?? AdminRole::getRules(); return $rules ?? AdminRole::getRules();

View File

@ -2,19 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers\Databases; namespace Pterodactyl\Http\Requests\Api\Application\Servers\Databases;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetServerDatabaseRequest extends ApplicationApiRequest class GetServerDatabaseRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_SERVER_DATABASES;
protected int $permission = AdminAcl::READ;
public function resourceExists(): bool
{
$server = $this->route()->parameter('server');
$database = $this->route()->parameter('database');
return $database->server_id === $server->id;
}
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers\Databases; namespace Pterodactyl\Http\Requests\Api\Application\Servers\Databases;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetServerDatabasesRequest extends ApplicationApiRequest class GetServerDatabasesRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_SERVER_DATABASES;
protected int $permission = AdminAcl::READ;
} }

View File

@ -2,9 +2,6 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers\Databases; namespace Pterodactyl\Http\Requests\Api\Application\Servers\Databases;
use Pterodactyl\Services\Acl\Api\AdminAcl;
class ServerDatabaseWriteRequest extends GetServerDatabasesRequest class ServerDatabaseWriteRequest extends GetServerDatabasesRequest
{ {
protected int $permission = AdminAcl::WRITE;
} }

View File

@ -6,15 +6,11 @@ use Webmozart\Assert\Assert;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\Builder;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Services\Databases\DatabaseManagementService; use Pterodactyl\Services\Databases\DatabaseManagementService;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreServerDatabaseRequest extends ApplicationApiRequest class StoreServerDatabaseRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_SERVER_DATABASES;
protected int $permission = AdminAcl::WRITE;
public function rules(): array public function rules(): array
{ {
$server = $this->route()->parameter('server'); $server = $this->route()->parameter('server');

View File

@ -2,35 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers; namespace Pterodactyl\Http\Requests\Api\Application\Servers;
use Pterodactyl\Models\Server;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetExternalServerRequest extends ApplicationApiRequest class GetExternalServerRequest extends ApplicationApiRequest
{ {
private Server $serverModel;
protected string $resource = AdminAcl::RESOURCE_SERVERS;
protected int $permission = AdminAcl::READ;
public function resourceExists(): bool
{
$repository = $this->container->make(ServerRepositoryInterface::class);
try {
$this->serverModel = $repository->findFirstWhere([
['external_id', '=', $this->route()->parameter('external_id')],
]);
} catch (RecordNotFoundException $exception) {
return false;
}
return true;
}
public function getServerModel(): Server
{
return $this->serverModel;
}
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers; namespace Pterodactyl\Http\Requests\Api\Application\Servers;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class GetServerRequest extends ApplicationApiRequest class GetServerRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_SERVERS;
protected int $permission = AdminAcl::READ;
} }

View File

@ -2,11 +2,8 @@
namespace Pterodactyl\Http\Requests\Api\Application\Servers; namespace Pterodactyl\Http\Requests\Api\Application\Servers;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class ServerWriteRequest extends ApplicationApiRequest class ServerWriteRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_SERVERS;
protected int $permission = AdminAcl::WRITE;
} }

View File

@ -4,16 +4,12 @@ namespace Pterodactyl\Http\Requests\Api\Application\Servers;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Illuminate\Contracts\Validation\Validator; use Illuminate\Contracts\Validation\Validator;
use Pterodactyl\Models\Objects\DeploymentObject; use Pterodactyl\Models\Objects\DeploymentObject;
use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest; use Pterodactyl\Http\Requests\Api\Application\ApplicationApiRequest;
class StoreServerRequest extends ApplicationApiRequest class StoreServerRequest extends ApplicationApiRequest
{ {
protected string $resource = AdminAcl::RESOURCE_SERVERS;
protected int $permission = AdminAcl::WRITE;
public function rules(): array public function rules(): array
{ {
$rules = Server::getRules(); $rules = Server::getRules();
@ -93,7 +89,9 @@ class StoreServerRequest extends ApplicationApiRequest
public function withValidator(Validator $validator) public function withValidator(Validator $validator)
{ {
$validator->sometimes('allocation.default', [ $validator->sometimes('allocation.default', [
'required', 'integer', 'bail', 'required',
'integer',
'bail',
Rule::exists('allocations', 'id')->where(function ($query) { Rule::exists('allocations', 'id')->where(function ($query) {
$query->whereNull('server_id'); $query->whereNull('server_id');
}), }),

Some files were not shown because too many files have changed in this diff Show More