Merge branch 'develop' into feature/file-uploads
This commit is contained in:
commit
54f9c5f187
136 changed files with 2178 additions and 971 deletions
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Pterodactyl\Http\Controllers\Api\Client;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Spatie\QueryBuilder\QueryBuilder;
|
||||
|
@ -39,31 +38,27 @@ class ClientController extends ClientApiController
|
|||
public function index(GetServersRequest $request): array
|
||||
{
|
||||
$user = $request->user();
|
||||
$level = $request->getFilterLevel();
|
||||
$transformer = $this->getTransformer(ServerTransformer::class);
|
||||
|
||||
// Start the query builder and ensure we eager load any requested relationships from the request.
|
||||
$builder = Server::query()->with($this->getIncludesForTransformer($transformer, ['node']));
|
||||
$builder = QueryBuilder::for(
|
||||
Server::query()->with($this->getIncludesForTransformer($transformer, ['node']))
|
||||
)->allowedFilters('uuid', 'name', 'external_id');
|
||||
|
||||
if ($level === User::FILTER_LEVEL_OWNER) {
|
||||
$builder = $builder->where('owner_id', $request->user()->id);
|
||||
}
|
||||
// If set to all, display all servers they can access, including those they access as an
|
||||
// admin. If set to subuser, only return the servers they can access because they are owner,
|
||||
// or marked as a subuser of the server.
|
||||
elseif (($level === User::FILTER_LEVEL_ALL && ! $user->root_admin) || $level === User::FILTER_LEVEL_SUBUSER) {
|
||||
// Either return all of the servers the user has access to because they are an admin `?type=admin` or
|
||||
// just return all of the servers the user has access to because they are the owner or a subuser of the
|
||||
// server.
|
||||
if ($request->input('type') === 'admin') {
|
||||
$builder = $user->root_admin
|
||||
? $builder->whereNotIn('id', $user->accessibleServers()->pluck('id')->all())
|
||||
// If they aren't an admin but want all the admin servers don't fail the request, just
|
||||
// make it a query that will never return any results back.
|
||||
: $builder->whereRaw('1 = 2');
|
||||
} elseif ($request->input('type') === 'owner') {
|
||||
$builder = $builder->where('owner_id', $user->id);
|
||||
} else {
|
||||
$builder = $builder->whereIn('id', $user->accessibleServers()->pluck('id')->all());
|
||||
}
|
||||
// If set to admin, only display the servers a user can access because they are an administrator.
|
||||
// This means only servers the user would not have access to if they were not an admin (because they
|
||||
// are not an owner or subuser) are returned.
|
||||
elseif ($level === User::FILTER_LEVEL_ADMIN && $user->root_admin) {
|
||||
$builder = $builder->whereNotIn('id', $user->accessibleServers()->pluck('id')->all());
|
||||
}
|
||||
|
||||
$builder = QueryBuilder::for($builder)->allowedFilters(
|
||||
'uuid', 'name', 'external_id'
|
||||
);
|
||||
|
||||
$servers = $builder->paginate(min($request->query('per_page', 50), 100))->appends($request->query());
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
|||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Exception\BadResponseException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Pterodactyl\Repositories\Wings\DaemonCommandRepository;
|
||||
|
@ -45,11 +44,13 @@ class CommandController extends ClientApiController
|
|||
{
|
||||
try {
|
||||
$this->repository->setServer($server)->send($request->input('command'));
|
||||
} catch (RequestException $exception) {
|
||||
if ($exception instanceof BadResponseException) {
|
||||
} catch (DaemonConnectionException $exception) {
|
||||
$previous = $exception->getPrevious();
|
||||
|
||||
if ($previous instanceof BadResponseException) {
|
||||
if (
|
||||
$exception->getResponse() instanceof ResponseInterface
|
||||
&& $exception->getResponse()->getStatusCode() === Response::HTTP_BAD_GATEWAY
|
||||
$previous->getResponse() instanceof ResponseInterface
|
||||
&& $previous->getResponse()->getStatusCode() === Response::HTTP_BAD_GATEWAY
|
||||
) {
|
||||
throw new HttpException(
|
||||
Response::HTTP_BAD_GATEWAY, 'Server must be online in order to send commands.', $exception
|
||||
|
@ -57,7 +58,7 @@ class CommandController extends ClientApiController
|
|||
}
|
||||
}
|
||||
|
||||
throw new DaemonConnectionException($exception);
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return $this->returnNoContent();
|
||||
|
|
|
@ -6,19 +6,18 @@ use Carbon\CarbonImmutable;
|
|||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use GuzzleHttp\Exception\TransferException;
|
||||
use Pterodactyl\Services\Nodes\NodeJWTService;
|
||||
use Illuminate\Contracts\Routing\ResponseFactory;
|
||||
use Pterodactyl\Repositories\Wings\DaemonFileRepository;
|
||||
use Pterodactyl\Transformers\Daemon\FileObjectTransformer;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CopyFileRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\ListFilesRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DeleteFileRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\RenameFileRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CreateFolderRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CompressFilesRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DecompressFilesRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\GetFileContentsRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\WriteFileContentRequest;
|
||||
|
||||
|
@ -69,13 +68,9 @@ class FileController extends ClientApiController
|
|||
*/
|
||||
public function directory(ListFilesRequest $request, Server $server): array
|
||||
{
|
||||
try {
|
||||
$contents = $this->fileRepository
|
||||
->setServer($server)
|
||||
->getDirectory($request->get('directory') ?? '/');
|
||||
} catch (TransferException $exception) {
|
||||
throw new DaemonConnectionException($exception, true);
|
||||
}
|
||||
$contents = $this->fileRepository
|
||||
->setServer($server)
|
||||
->getDirectory($request->get('directory') ?? '/');
|
||||
|
||||
return $this->fractal->collection($contents)
|
||||
->transformWith($this->getTransformer(FileObjectTransformer::class))
|
||||
|
@ -88,7 +83,9 @@ class FileController extends ClientApiController
|
|||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\GetFileContentsRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Server\FileSizeTooLargeException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function contents(GetFileContentsRequest $request, Server $server): Response
|
||||
{
|
||||
|
@ -139,6 +136,8 @@ class FileController extends ClientApiController
|
|||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\WriteFileContentRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function write(WriteFileContentRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
|
@ -156,6 +155,8 @@ class FileController extends ClientApiController
|
|||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\CreateFolderRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function create(CreateFolderRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
|
@ -172,6 +173,8 @@ class FileController extends ClientApiController
|
|||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\RenameFileRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function rename(RenameFileRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
|
@ -188,6 +191,8 @@ class FileController extends ClientApiController
|
|||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\CopyFileRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function copy(CopyFileRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
|
@ -202,9 +207,14 @@ class FileController extends ClientApiController
|
|||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\CompressFilesRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return array
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function compress(CompressFilesRequest $request, Server $server): array
|
||||
{
|
||||
// Allow up to five minutes for this request to process before timing out.
|
||||
set_time_limit(300);
|
||||
|
||||
$file = $this->fileRepository->setServer($server)
|
||||
->compressFiles(
|
||||
$request->input('root'), $request->input('files')
|
||||
|
@ -215,12 +225,32 @@ class FileController extends ClientApiController
|
|||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\DecompressFilesRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function decompress(DecompressFilesRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
// Allow up to five minutes for this request to process before timing out.
|
||||
set_time_limit(300);
|
||||
|
||||
$this->fileRepository->setServer($server)
|
||||
->decompressFile($request->input('root'), $request->input('file'));
|
||||
|
||||
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes files or folders for the server in the given root directory.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Files\DeleteFileRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function delete(DeleteFileRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
|
|
|
@ -33,6 +33,8 @@ class PowerController extends ClientApiController
|
|||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\SendPowerRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\Response
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function index(SendPowerRequest $request, Server $server): Response
|
||||
{
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Services\Servers\VariableValidatorService;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerVariableRepository;
|
||||
use Pterodactyl\Transformers\Api\Client\EggVariableTransformer;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Startup\UpdateStartupVariableRequest;
|
||||
|
||||
class StartupController extends ClientApiController
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\VariableValidatorService
|
||||
*/
|
||||
private $service;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Repositories\Eloquent\ServerVariableRepository
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* StartupController constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Services\Servers\VariableValidatorService $service
|
||||
* @param \Pterodactyl\Repositories\Eloquent\ServerVariableRepository $repository
|
||||
*/
|
||||
public function __construct(VariableValidatorService $service, ServerVariableRepository $repository)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->service = $service;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a single variable for a server.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Startup\UpdateStartupVariableRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return array
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function update(UpdateStartupVariableRequest $request, Server $server)
|
||||
{
|
||||
/** @var \Pterodactyl\Models\EggVariable $variable */
|
||||
$variable = $server->variables()->where('env_variable', $request->input('key'))->first();
|
||||
|
||||
if (is_null($variable) || !$variable->user_viewable || !$variable->user_editable) {
|
||||
throw new BadRequestHttpException(
|
||||
"The environment variable you are trying to edit [\"{$request->input('key')}\"] does not exist."
|
||||
);
|
||||
}
|
||||
|
||||
// Revalidate the variable value using the egg variable specific validation rules for it.
|
||||
$this->validate($request, ['value' => $variable->rules]);
|
||||
|
||||
$this->repository->updateOrCreate([
|
||||
'server_id' => $server->id,
|
||||
'variable_id' => $variable->id,
|
||||
], [
|
||||
'variable_value' => $request->input('value'),
|
||||
]);
|
||||
|
||||
$variable = $variable->refresh();
|
||||
$variable->server_value = $request->input('value');
|
||||
|
||||
return $this->fractal->item($variable)
|
||||
->transformWith($this->getTransformer(EggVariableTransformer::class))
|
||||
->toArray();
|
||||
}
|
||||
}
|
|
@ -3,7 +3,9 @@
|
|||
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Subuser;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Pterodactyl\Repositories\Eloquent\SubuserRepository;
|
||||
|
@ -57,6 +59,21 @@ class SubuserController extends ClientApiController
|
|||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single subuser associated with this server instance.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Subusers\GetSubuserRequest $request
|
||||
* @return array
|
||||
*/
|
||||
public function view(GetSubuserRequest $request)
|
||||
{
|
||||
$subuser = $request->attributes->get('subuser');
|
||||
|
||||
return $this->fractal->item($subuser)
|
||||
->transformWith($this->getTransformer(SubuserTransformer::class))
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new subuser for the given server.
|
||||
*
|
||||
|
@ -84,15 +101,16 @@ class SubuserController extends ClientApiController
|
|||
* Update a given subuser in the system for the server.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Subusers\UpdateSubuserRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return array
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function update(UpdateSubuserRequest $request, Server $server): array
|
||||
public function update(UpdateSubuserRequest $request): array
|
||||
{
|
||||
$subuser = $request->endpointSubuser();
|
||||
/** @var \Pterodactyl\Models\Subuser $subuser */
|
||||
$subuser = $request->attributes->get('subuser');
|
||||
|
||||
$this->repository->update($subuser->id, [
|
||||
'permissions' => $this->getDefaultPermissions($request),
|
||||
]);
|
||||
|
@ -106,14 +124,16 @@ class SubuserController extends ClientApiController
|
|||
* Removes a subusers from a server's assignment.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Subusers\DeleteSubuserRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function delete(DeleteSubuserRequest $request, Server $server)
|
||||
public function delete(DeleteSubuserRequest $request)
|
||||
{
|
||||
$this->repository->delete($request->endpointSubuser()->id);
|
||||
/** @var \Pterodactyl\Models\Subuser $subuser */
|
||||
$subuser = $request->attributes->get('subuser');
|
||||
|
||||
return JsonResponse::create([], JsonResponse::HTTP_NO_CONTENT);
|
||||
$this->repository->delete($subuser->id);
|
||||
|
||||
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Pterodactyl\Http\Controllers\Api\Remote\Backups;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Eloquent\BackupRepository;
|
||||
|
@ -31,25 +32,16 @@ class BackupStatusController extends Controller
|
|||
* @param \Pterodactyl\Http\Requests\Api\Remote\ReportBackupCompleteRequest $request
|
||||
* @param string $backup
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function __invoke(ReportBackupCompleteRequest $request, string $backup)
|
||||
{
|
||||
/** @var \Pterodactyl\Models\Backup $backup */
|
||||
$backup = $this->repository->findFirstWhere([['uuid', '=', $backup]]);
|
||||
$this->repository->updateWhere([['uuid', '=', $backup]], [
|
||||
'is_successful' => $request->input('successful') ? true : false,
|
||||
'sha256_hash' => $request->input('checksum'),
|
||||
'bytes' => $request->input('size'),
|
||||
'completed_at' => CarbonImmutable::now(),
|
||||
]);
|
||||
|
||||
if ($request->input('successful')) {
|
||||
$this->repository->update($backup->id, [
|
||||
'sha256_hash' => $request->input('checksum'),
|
||||
'bytes' => $request->input('size'),
|
||||
'completed_at' => Carbon::now(),
|
||||
], true, true);
|
||||
} else {
|
||||
$this->repository->delete($backup->id);
|
||||
}
|
||||
|
||||
return JsonResponse::create([], JsonResponse::HTTP_NO_CONTENT);
|
||||
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Middleware\Api\Client\Server;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SubuserBelongsToServer
|
||||
{
|
||||
/**
|
||||
* Ensure that the user being accessed in the request is a user that is currently assigned
|
||||
* as a subuser for this server instance. We'll let the requests themselves handle wether or
|
||||
* not the user making the request can actually modify or delete the subuser record.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
/** @var \Pterodactyl\Models\Server $server */
|
||||
$server = $request->route()->parameter('server');
|
||||
/** @var \Pterodactyl\Models\User $user */
|
||||
$user = $request->route()->parameter('user');
|
||||
|
||||
// Don't do anything if there isn't a user present in the request.
|
||||
if (is_null($user)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
$request->attributes->set('subuser', $server->subusers()->where('user_id', $user->id)->firstOrFail());
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace Pterodactyl\Http\Middleware\Api\Client;
|
||||
|
||||
use Closure;
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\Backup;
|
||||
use Pterodactyl\Models\Database;
|
||||
use Illuminate\Container\Container;
|
||||
|
@ -52,6 +53,10 @@ class SubstituteClientApiBindings extends ApiSubstituteBindings
|
|||
return Backup::query()->where('uuid', $value)->firstOrFail();
|
||||
});
|
||||
|
||||
$this->router->model('user', User::class, function ($value) {
|
||||
return User::query()->where('uuid', $value)->firstOrFail();
|
||||
});
|
||||
|
||||
return parent::handle($request, $next);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,10 +29,6 @@ class DatabaseHostFormRequest extends AdminFormRequest
|
|||
$this->merge(['node_id' => null]);
|
||||
}
|
||||
|
||||
$this->merge([
|
||||
'host' => gethostbyname($this->input('host')),
|
||||
]);
|
||||
|
||||
return parent::getValidatorInstance();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ class BaseSettingsFormRequest extends AdminFormRequest
|
|||
'app:name' => 'required|string|max:255',
|
||||
'pterodactyl:auth:2fa_required' => 'required|integer|in:0,1,2',
|
||||
'app:locale' => ['required', 'string', Rule::in(array_keys($this->getAvailableLanguages()))],
|
||||
'app:analytics' => 'nullable|string',
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -31,6 +32,7 @@ class BaseSettingsFormRequest extends AdminFormRequest
|
|||
'app:name' => 'Company Name',
|
||||
'pterodactyl:auth:2fa_required' => 'Require 2-Factor Authentication',
|
||||
'app:locale' => 'Default Language',
|
||||
'app:analytics' => 'Google Analytics',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,4 +17,14 @@ class StoreApiKeyRequest extends ClientApiRequest
|
|||
'allowed_ips.*' => 'ip',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string[]
|
||||
*/
|
||||
public function messages()
|
||||
{
|
||||
return [
|
||||
'allowed_ips.*' => 'All of the IP addresses entered must be valid IPv4 addresses.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
|
||||
class GetServersRequest extends ClientApiRequest
|
||||
{
|
||||
/**
|
||||
|
@ -13,28 +11,4 @@ class GetServersRequest extends ClientApiRequest
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filtering method for servers when the client base endpoint is requested.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getFilterLevel(): int
|
||||
{
|
||||
switch ($this->input('type')) {
|
||||
case 'all':
|
||||
return User::FILTER_LEVEL_ALL;
|
||||
break;
|
||||
case 'admin':
|
||||
return User::FILTER_LEVEL_ADMIN;
|
||||
break;
|
||||
case 'owner':
|
||||
return User::FILTER_LEVEL_OWNER;
|
||||
break;
|
||||
case 'subuser-of':
|
||||
default:
|
||||
return User::FILTER_LEVEL_SUBUSER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Files;
|
||||
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
|
||||
class DecompressFilesRequest extends ClientApiRequest
|
||||
{
|
||||
/**
|
||||
* Checks that the authenticated user is allowed to create new files for the server. We don't
|
||||
* rely on the archive permission here as it makes more sense to make sure the user can create
|
||||
* additional files rather than make an archive.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function permission(): string
|
||||
{
|
||||
return Permission::ACTION_FILE_CREATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'root' => 'sometimes|nullable|string',
|
||||
'file' => 'required|string',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Startup;
|
||||
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
|
||||
class UpdateStartupVariableRequest extends ClientApiRequest
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function permission()
|
||||
{
|
||||
return Permission::ACTION_STARTUP_UPDATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual validation of the variable's value will happen inside the controller.
|
||||
*
|
||||
* @return array|string[]
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'key' => 'required|string',
|
||||
'value' => 'present|string',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -3,12 +3,10 @@
|
|||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Subusers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Exceptions\Http\HttpForbiddenException;
|
||||
use Pterodactyl\Repositories\Eloquent\SubuserRepository;
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Pterodactyl\Services\Servers\GetUserPermissionsService;
|
||||
|
||||
abstract class SubuserRequest extends ClientApiRequest
|
||||
{
|
||||
|
@ -30,10 +28,10 @@ abstract class SubuserRequest extends ClientApiRequest
|
|||
return false;
|
||||
}
|
||||
|
||||
// If there is a subuser present in the URL, validate that it is not the same as the
|
||||
// current request user. You're not allowed to modify yourself.
|
||||
if ($this->route()->hasParameter('subuser')) {
|
||||
if ($this->endpointSubuser()->user_id === $this->user()->id) {
|
||||
$user = $this->route()->parameter('user');
|
||||
// Don't allow a user to edit themselves on the server.
|
||||
if ($user instanceof User) {
|
||||
if ($user->uuid === $this->user()->uuid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -71,68 +69,14 @@ abstract class SubuserRequest extends ClientApiRequest
|
|||
// Otherwise, get the current subuser's permission set, and ensure that the
|
||||
// permissions they are trying to assign are not _more_ than the ones they
|
||||
// already have.
|
||||
if (count(array_diff($permissions, $this->currentUserPermissions())) > 0) {
|
||||
/** @var \Pterodactyl\Models\Subuser|null $subuser */
|
||||
/** @var \Pterodactyl\Services\Servers\GetUserPermissionsService $service */
|
||||
$service = $this->container->make(GetUserPermissionsService::class);
|
||||
|
||||
if (count(array_diff($permissions, $service->handle($server, $user))) > 0) {
|
||||
throw new HttpForbiddenException(
|
||||
'Cannot assign permissions to a subuser that your account does not actively possess.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently authenticated user's permissions.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
public function currentUserPermissions(): array
|
||||
{
|
||||
/** @var \Pterodactyl\Repositories\Eloquent\SubuserRepository $repository */
|
||||
$repository = $this->container->make(SubuserRepository::class);
|
||||
|
||||
/* @var \Pterodactyl\Models\Subuser $model */
|
||||
try {
|
||||
$model = $repository->findFirstWhere([
|
||||
['server_id', $this->route()->parameter('server')->id],
|
||||
['user_id', $this->user()->id],
|
||||
]);
|
||||
} catch (RecordNotFoundException $exception) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $model->permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the subuser model for the given request which can then be validated. If
|
||||
* required request parameters are missing a 404 error will be returned, otherwise
|
||||
* a model exception will be returned if the model is not found.
|
||||
*
|
||||
* This returns the subuser based on the endpoint being hit, not the actual subuser
|
||||
* for the account making the request.
|
||||
*
|
||||
* @return \Pterodactyl\Models\Subuser
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
public function endpointSubuser()
|
||||
{
|
||||
/** @var \Pterodactyl\Repositories\Eloquent\SubuserRepository $repository */
|
||||
$repository = $this->container->make(SubuserRepository::class);
|
||||
|
||||
$parameters = $this->route()->parameters();
|
||||
if (
|
||||
! isset($parameters['server'], $parameters['server'])
|
||||
|| ! is_string($parameters['subuser'])
|
||||
|| ! $parameters['server'] instanceof Server
|
||||
) {
|
||||
throw new NotFoundHttpException;
|
||||
}
|
||||
|
||||
return $this->model ?: $this->model = $repository->getUserForServer(
|
||||
$parameters['server']->id, $parameters['subuser']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ class AssetComposer
|
|||
'enabled' => config('recaptcha.enabled', false),
|
||||
'siteKey' => config('recaptcha.website_key') ?? '',
|
||||
],
|
||||
'analytics' => config('app.analytics') ?? '',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue