Update to Laravel 8

Co-authored-by: Matthew Penner <me@matthewp.io>
This commit is contained in:
Dane Everitt 2021-01-23 12:09:16 -08:00
parent 028921b42a
commit a043071e3c
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
211 changed files with 4394 additions and 2933 deletions

View File

@ -19,9 +19,9 @@ jobs:
- 3306 - 3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
strategy: strategy:
fail-fast: true fail-fast: false
matrix: matrix:
php: [7.3, 7.4] php: [7.4, 8.0]
name: PHP ${{ matrix.php }} name: PHP ${{ matrix.php }}
steps: steps:
- name: checkout - name: checkout
@ -44,7 +44,7 @@ jobs:
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
extensions: cli, openssl, gd, mysql, pdo, mbstring, tokenizer, bcmath, xml, curl, zip extensions: cli, openssl, gd, mysql, pdo, mbstring, tokenizer, bcmath, xml, curl, zip
tools: composer:v1 tools: composer:v2
coverage: none coverage: none
- name: configure - name: configure
run: cp .env.ci .env run: cp .env.ci .env

5
.gitignore vendored
View File

@ -1,6 +1,9 @@
/vendor /vendor
*.DS_Store* *.DS_Store*
.env !.env.ci
!.env.dusk
!.env.example
.env*
.vagrant/* .vagrant/*
.vscode/* .vscode/*
storage/framework/* storage/framework/*

View File

@ -17,7 +17,7 @@ class SeedCommand extends BaseSeedCommand
*/ */
public function handle() public function handle()
{ {
if (!$this->hasCompletedMigrations()) { if (! $this->hasCompletedMigrations()) {
return $this->showMigrationWarning(); return $this->showMigrationWarning();
} }

View File

@ -14,7 +14,7 @@ class UpCommand extends BaseUpCommand
*/ */
public function handle() public function handle()
{ {
if (!$this->hasCompletedMigrations()) { if (! $this->hasCompletedMigrations()) {
return $this->showMigrationWarning(); return $this->showMigrationWarning();
} }

View File

@ -2,8 +2,8 @@
namespace Pterodactyl\Console\Commands\Schedule; namespace Pterodactyl\Console\Commands\Schedule;
use Throwable;
use Exception; use Exception;
use Throwable;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Pterodactyl\Models\Schedule; use Pterodactyl\Models\Schedule;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;

View File

@ -99,9 +99,9 @@ class BulkPowerActionCommand extends Command
if (! empty($nodes) && ! empty($servers)) { if (! empty($nodes) && ! empty($servers)) {
$instance->whereIn('id', $servers)->orWhereIn('node_id', $nodes); $instance->whereIn('id', $servers)->orWhereIn('node_id', $nodes);
} else if (empty($nodes) && ! empty($servers)) { } elseif (empty($nodes) && ! empty($servers)) {
$instance->whereIn('id', $servers); $instance->whereIn('id', $servers);
} else if (! empty($nodes) && empty($servers)) { } elseif (! empty($nodes) && empty($servers)) {
$instance->whereIn('node_id', $nodes); $instance->whereIn('node_id', $nodes);
} }

View File

@ -9,11 +9,10 @@
namespace Pterodactyl\Console\Commands\User; namespace Pterodactyl\Console\Commands\User;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Webmozart\Assert\Assert;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Pterodactyl\Services\Users\UserDeletionService; use Pterodactyl\Services\Users\UserDeletionService;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
class DeleteUserCommand extends Command class DeleteUserCommand extends Command
{ {
@ -42,7 +41,8 @@ class DeleteUserCommand extends Command
* *
* @param \Pterodactyl\Services\Users\UserDeletionService $deletionService * @param \Pterodactyl\Services\Users\UserDeletionService $deletionService
*/ */
public function __construct(UserDeletionService $deletionService) { public function __construct(UserDeletionService $deletionService)
{
parent::__construct(); parent::__construct();
$this->deletionService = $deletionService; $this->deletionService = $deletionService;
@ -96,7 +96,5 @@ class DeleteUserCommand extends Command
$this->deletionService->handle($deleteUser); $this->deletionService->handle($deleteUser);
$this->info(trans('command/messages.user.deleted')); $this->info(trans('command/messages.user.deleted'));
} }
return;
} }
} }

View File

@ -39,7 +39,7 @@ trait RequiresDatabaseMigrations
*/ */
protected function showMigrationWarning(): int protected function showMigrationWarning(): int
{ {
$this->getOutput()->writeln("<options=bold> $this->getOutput()->writeln('<options=bold>
| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
| | | |
| Your database has not been properly migrated! | | Your database has not been properly migrated! |
@ -52,9 +52,9 @@ You must run the following command to finish migrating your database:
You will not be able to use Pterodactyl Panel as expected without fixing your You will not be able to use Pterodactyl Panel as expected without fixing your
database state by running the command above. database state by running the command above.
"); ');
$this->getOutput()->error("You must correct the error above before continuing."); $this->getOutput()->error('You must correct the error above before continuing.');
return 1; return 1;
} }

View File

@ -2,8 +2,6 @@
namespace Pterodactyl\Contracts\Repository; namespace Pterodactyl\Contracts\Repository;
use Illuminate\Support\Collection;
interface AllocationRepositoryInterface extends RepositoryInterface interface AllocationRepositoryInterface extends RepositoryInterface
{ {
/** /**

View File

@ -4,9 +4,6 @@ namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Pterodactyl\Contracts\Repository\Attributes\SearchableInterface;
interface NodeRepositoryInterface extends RepositoryInterface interface NodeRepositoryInterface extends RepositoryInterface
{ {

View File

@ -5,10 +5,14 @@ namespace Pterodactyl\Exceptions;
use Exception; use Exception;
use Throwable; use Throwable;
use PDOException; use PDOException;
use Psr\Log\LoggerInterface; use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Swift_TransportException; use Swift_TransportException;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Illuminate\Container\Container; use Illuminate\Container\Container;
use Illuminate\Database\Connection; use Illuminate\Database\Connection;
use Illuminate\Foundation\Application;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Session\TokenMismatchException; use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
@ -43,17 +47,6 @@ class Handler extends ExceptionHandler
ValidationException::class, ValidationException::class,
]; ];
/**
* A list of exceptions that should be logged with cleaned stack
* traces to avoid exposing credentials or other sensitive information.
*
* @var array
*/
protected $cleanStacks = [
PDOException::class,
Swift_TransportException::class,
];
/** /**
* A list of the inputs that are never flashed for validation exceptions. * A list of the inputs that are never flashed for validation exceptions.
* *
@ -67,56 +60,40 @@ class Handler extends ExceptionHandler
]; ];
/** /**
* Report or log an exception. Skips Laravel's internal reporter since we * Registers the exception handling callbacks for the application. This
* don't need or want the user information in our logs by default. * will capture specific exception types that we do not want to include
* the detailed stack traces for since they could reveal credentials to
* whoever can read the logs.
* *
* If you want to implement logging in a different format to integrate with * @noinspection PhpUnusedLocalVariableInspection
* services such as AWS Cloudwatch or other monitoring you can replace the
* contents of this function with a call to the parent reporter.
*
* @param \Throwable $exception
* @return mixed
*
* @throws \Throwable
*/ */
public function report(Throwable $exception) public function register()
{ {
if (! config('app.exceptions.report_all', false) && $this->shouldntReport($exception)) { if (config('app.exceptions.report_all', false)) {
return null; $this->dontReport = [];
} }
if (method_exists($exception, 'report')) { $this->reportable(function (PDOException $ex) {
return $exception->report(); $ex = $this->generateCleanedExceptionStack($ex);
} });
try { $this->reportable(function (Swift_TransportException $ex) {
$logger = $this->container->make(LoggerInterface::class); $ex = $this->generateCleanedExceptionStack($ex);
} catch (Exception $ex) { });
throw $exception;
}
foreach ($this->cleanStacks as $class) {
if ($exception instanceof $class) {
$exception = $this->generateCleanedExceptionStack($exception);
break;
}
}
return $logger->error($exception);
} }
private function generateCleanedExceptionStack(Throwable $exception) private function generateCleanedExceptionStack(Throwable $exception): string
{ {
$cleanedStack = ''; $cleanedStack = '';
foreach ($exception->getTrace() as $index => $item) { foreach ($exception->getTrace() as $index => $item) {
$cleanedStack .= sprintf( $cleanedStack .= sprintf(
"#%d %s(%d): %s%s%s\n", "#%d %s(%d): %s%s%s\n",
$index, $index,
array_get($item, 'file'), Arr::get($item, 'file'),
array_get($item, 'line'), Arr::get($item, 'line'),
array_get($item, 'class'), Arr::get($item, 'class'),
array_get($item, 'type'), Arr::get($item, 'type'),
array_get($item, 'function') Arr::get($item, 'function')
); );
} }
@ -142,7 +119,7 @@ class Handler extends ExceptionHandler
*/ */
public function render($request, Throwable $exception) public function render($request, Throwable $exception)
{ {
$connections = Container::getInstance()->make(Connection::class); $connections = $this->container->make(Connection::class);
// If we are currently wrapped up inside a transaction, we will roll all the way // If we are currently wrapped up inside a transaction, we will roll all the way
// back to the beginning. This needs to happen, otherwise session data does not // back to the beginning. This needs to happen, otherwise session data does not
@ -170,21 +147,21 @@ class Handler extends ExceptionHandler
*/ */
public function invalidJson($request, ValidationException $exception) public function invalidJson($request, ValidationException $exception)
{ {
$codes = collect($exception->validator->failed())->mapWithKeys(function ($reasons, $field) { $codes = Collection::make($exception->validator->failed())->mapWithKeys(function ($reasons, $field) {
$cleaned = []; $cleaned = [];
foreach ($reasons as $reason => $attrs) { foreach ($reasons as $reason => $attrs) {
$cleaned[] = snake_case($reason); $cleaned[] = Str::snake($reason);
} }
return [str_replace('.', '_', $field) => $cleaned]; return [str_replace('.', '_', $field) => $cleaned];
})->toArray(); })->toArray();
$errors = collect($exception->errors())->map(function ($errors, $field) use ($codes, $exception) { $errors = Collection::make($exception->errors())->map(function ($errors, $field) use ($codes, $exception) {
$response = []; $response = [];
foreach ($errors as $key => $error) { foreach ($errors as $key => $error) {
$meta = [ $meta = [
'source_field' => $field, 'source_field' => $field,
'rule' => str_replace(self::PTERODACTYL_RULE_STRING, 'p_', array_get( 'rule' => str_replace(self::PTERODACTYL_RULE_STRING, 'p_', Arr::get(
$codes, str_replace('.', '_', $field) . '.' . $key $codes, str_replace('.', '_', $field) . '.' . $key
)), )),
]; ];
@ -235,7 +212,7 @@ class Handler extends ExceptionHandler
'detail' => $exception->getMessage(), 'detail' => $exception->getMessage(),
'source' => [ 'source' => [
'line' => $exception->getLine(), 'line' => $exception->getLine(),
'file' => str_replace(base_path(), '', $exception->getFile()), 'file' => str_replace(Application::getInstance()->basePath(), '', $exception->getFile()),
], ],
'meta' => [ 'meta' => [
'trace' => explode("\n", $exception->getTraceAsString()), 'trace' => explode("\n", $exception->getTraceAsString()),
@ -262,15 +239,15 @@ class Handler extends ExceptionHandler
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception * @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\Response * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
*/ */
protected function unauthenticated($request, AuthenticationException $exception) protected function unauthenticated($request, AuthenticationException $exception)
{ {
if ($request->expectsJson()) { if ($request->expectsJson()) {
return response()->json(self::convertToArray($exception), 401); return new JsonResponse(self::convertToArray($exception), JsonResponse::HTTP_UNAUTHORIZED);
} }
return redirect()->guest(route('auth.login')); return $this->container->make('redirect')->guest('/auth/login');
} }
/** /**

View File

@ -42,7 +42,7 @@ class DaemonConnectionException extends DisplayException
$body = $response->getBody(); $body = $response->getBody();
if (is_string($body) || (is_object($body) && method_exists($body, '__toString'))) { if (is_string($body) || (is_object($body) && method_exists($body, '__toString'))) {
$body = json_decode(is_string($body) ? $body : $body->__toString(), true); $body = json_decode(is_string($body) ? $body : $body->__toString(), true);
$message = "[Wings Error]: " . Arr::get($body, 'error', $message); $message = '[Wings Error]: ' . Arr::get($body, 'error', $message);
} }
} }

View File

@ -16,6 +16,6 @@ class TwoFactorAuthRequiredException extends HttpException implements HttpExcept
*/ */
public function __construct(Throwable $previous = null) public function __construct(Throwable $previous = null)
{ {
parent::__construct(Response::HTTP_BAD_REQUEST, "Two-factor authentication is required on this account in order to access this endpoint.", $previous); parent::__construct(Response::HTTP_BAD_REQUEST, 'Two-factor authentication is required on this account in order to access this endpoint.', $previous);
} }
} }

View File

@ -8,8 +8,8 @@ use Illuminate\Support\Arr;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
use InvalidArgumentException; use InvalidArgumentException;
use League\Flysystem\AdapterInterface;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use League\Flysystem\AdapterInterface;
use League\Flysystem\AwsS3v3\AwsS3Adapter; use League\Flysystem\AwsS3v3\AwsS3Adapter;
use League\Flysystem\Memory\MemoryAdapter; use League\Flysystem\Memory\MemoryAdapter;
use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\Config\Repository;

View File

@ -0,0 +1,33 @@
<?php
namespace Pterodactyl\Extensions\Lcobucci\JWT\Encoding;
use DateTimeImmutable;
use Lcobucci\JWT\ClaimsFormatter;
use Lcobucci\JWT\Token\RegisteredClaims;
final class TimestampDates implements ClaimsFormatter
{
/**
* The default time encoder for JWTs using this library is not supported correctly
* by Wings and will cause a flood of errors and panic conditions because the times
* cannot be parsed correctly. The default is time with microseconds, we just need
* to use the normal unix timestamp here.
*
* @param array $claims
* @return array
*/
public function formatClaims(array $claims): array
{
foreach (RegisteredClaims::DATE_CLAIMS as $claim) {
if (! array_key_exists($claim, $claims)) {
continue;
}
assert($claims[$claim] instanceof DateTimeImmutable);
$claims[$claim] = $claims[$claim]->getTimestamp();
}
return $claims;
}
}

View File

@ -3,17 +3,13 @@
namespace Pterodactyl\Http\Controllers\Admin; namespace Pterodactyl\Http\Controllers\Admin;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use Illuminate\Support\Str;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Pterodactyl\Models\Nest; use Pterodactyl\Models\Nest;
use Pterodactyl\Models\Mount; use Pterodactyl\Models\Mount;
use Pterodactyl\Models\Location; use Pterodactyl\Models\Location;
use Prologue\Alerts\AlertsMessageBag; use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Mounts\MountUpdateService;
use Pterodactyl\Http\Requests\Admin\MountFormRequest; use Pterodactyl\Http\Requests\Admin\MountFormRequest;
use Pterodactyl\Services\Mounts\MountCreationService;
use Pterodactyl\Services\Mounts\MountDeletionService;
use Pterodactyl\Repositories\Eloquent\MountRepository; use Pterodactyl\Repositories\Eloquent\MountRepository;
use Pterodactyl\Contracts\Repository\NestRepositoryInterface; use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;

View File

@ -79,7 +79,7 @@ class EggController extends Controller
public function store(EggFormRequest $request): RedirectResponse public function store(EggFormRequest $request): RedirectResponse
{ {
$data = $request->normalize(); $data = $request->normalize();
if (!empty($data['docker_images']) && !is_array($data['docker_images'])) { if (! empty($data['docker_images']) && ! is_array($data['docker_images'])) {
$data['docker_images'] = array_map(function ($value) { $data['docker_images'] = array_map(function ($value) {
return trim($value); return trim($value);
}, explode("\n", $data['docker_images'])); }, explode("\n", $data['docker_images']));
@ -116,7 +116,7 @@ class EggController extends Controller
public function update(EggFormRequest $request, Egg $egg): RedirectResponse public function update(EggFormRequest $request, Egg $egg): RedirectResponse
{ {
$data = $request->normalize(); $data = $request->normalize();
if (!empty($data['docker_images']) && !is_array($data['docker_images'])) { if (! empty($data['docker_images']) && ! is_array($data['docker_images'])) {
$data['docker_images'] = array_map(function ($value) { $data['docker_images'] = array_map(function ($value) {
return trim($value); return trim($value);
}, explode("\n", $data['docker_images'])); }, explode("\n", $data['docker_images']));

View File

@ -118,7 +118,7 @@ class CreateServerController extends Controller
public function store(ServerFormRequest $request) public function store(ServerFormRequest $request)
{ {
$data = $request->except(['_token']); $data = $request->except(['_token']);
if (!empty($data['custom_image'])) { if (! empty($data['custom_image'])) {
$data['image'] = $data['custom_image']; $data['image'] = $data['custom_image'];
unset($data['custom_image']); unset($data['custom_image']);
} }

View File

@ -89,7 +89,8 @@ class ServerTransferController extends Controller
* *
* @throws \Throwable * @throws \Throwable
*/ */
public function transfer(Request $request, Server $server) { public function transfer(Request $request, Server $server)
{
$validatedData = $request->validate([ $validatedData = $request->validate([
'node_id' => 'required|exists:nodes,id', 'node_id' => 'required|exists:nodes,id',
'allocation_id' => 'required|bail|unique:servers|exists:allocations,id', 'allocation_id' => 'required|bail|unique:servers|exists:allocations,id',

View File

@ -9,14 +9,12 @@
namespace Pterodactyl\Http\Controllers\Admin; namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\Support\Arr;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Pterodactyl\Models\Mount; use Pterodactyl\Models\Mount;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Pterodactyl\Models\MountServer; use Pterodactyl\Models\MountServer;
use Prologue\Alerts\AlertsMessageBag; use Prologue\Alerts\AlertsMessageBag;
use GuzzleHttp\Exception\RequestException;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
@ -37,7 +35,6 @@ use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface; use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
use Pterodactyl\Services\Servers\ServerConfigurationStructureService; use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
use Pterodactyl\Http\Requests\Admin\Servers\Databases\StoreServerDatabaseRequest; use Pterodactyl\Http\Requests\Admin\Servers\Databases\StoreServerDatabaseRequest;
@ -338,7 +335,7 @@ class ServersController extends Controller
public function saveStartup(Request $request, Server $server) public function saveStartup(Request $request, Server $server)
{ {
$data = $request->except('_token'); $data = $request->except('_token');
if (!empty($data['custom_docker_image'])) { if (! empty($data['custom_docker_image'])) {
$data['docker_image'] = $data['custom_docker_image']; $data['docker_image'] = $data['custom_docker_image'];
unset($data['custom_docker_image']); unset($data['custom_docker_image']);
} }

View File

@ -67,7 +67,7 @@ class ClientController extends ClientApiController
? $builder ? $builder
: $builder->whereNotIn('servers.id', $user->accessibleServers()->pluck('id')->all()); : $builder->whereNotIn('servers.id', $user->accessibleServers()->pluck('id')->all());
} }
} else if ($type === 'owner') { } elseif ($type === 'owner') {
$builder = $builder->where('servers.owner_id', $user->id); $builder = $builder->where('servers.owner_id', $user->id);
} else { } else {
$builder = $builder->whereIn('servers.id', $user->accessibleServers()->pluck('id')->all()); $builder = $builder->whereIn('servers.id', $user->accessibleServers()->pluck('id')->all());

View File

@ -61,6 +61,7 @@ class BackupController extends ClientApiController
public function index(GetBackupsRequest $request, Server $server) public function index(GetBackupsRequest $request, Server $server)
{ {
$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($this->getTransformer(BackupTransformer::class))
->toArray(); ->toArray();

View File

@ -138,7 +138,7 @@ class DownloadBackupController extends ClientApiController
return sprintf( return sprintf(
'%s/download/backup?token=%s', '%s/download/backup?token=%s',
$server->node->getConnectionAddress(), $server->node->getConnectionAddress(),
$token->__toString() $token->toString()
); );
} }
} }

View File

@ -6,7 +6,6 @@ use Carbon\CarbonImmutable;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Pterodactyl\Services\Nodes\NodeJWTService; use Pterodactyl\Services\Nodes\NodeJWTService;
use Illuminate\Contracts\Routing\ResponseFactory; use Illuminate\Contracts\Routing\ResponseFactory;
use Pterodactyl\Repositories\Wings\DaemonFileRepository; use Pterodactyl\Repositories\Wings\DaemonFileRepository;
@ -15,9 +14,9 @@ use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CopyFileRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CopyFileRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\PullFileRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Files\PullFileRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\ListFilesRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Files\ListFilesRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\ChmodFilesRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DeleteFileRequest; 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\RenameFileRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\ChmodFilesRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\CreateFolderRequest; 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\CompressFilesRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DecompressFilesRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Files\DecompressFilesRequest;
@ -127,7 +126,7 @@ class FileController extends ClientApiController
'url' => sprintf( 'url' => sprintf(
'%s/download/file?token=%s', '%s/download/file?token=%s',
$server->node->getConnectionAddress(), $server->node->getConnectionAddress(),
$token->__toString() $token->toString()
), ),
], ],
]; ];

View File

@ -67,7 +67,7 @@ class FileUploadController extends ClientApiController
return sprintf( return sprintf(
'%s/upload/file?token=%s', '%s/upload/file?token=%s',
$server->node->getConnectionAddress(), $server->node->getConnectionAddress(),
$token->__toString() $token->toString()
); );
} }
} }

View File

@ -112,7 +112,7 @@ class NetworkAllocationController extends ClientApiController
/** /**
* Set the notes for the allocation for a server. * Set the notes for the allocation for a server.
*s *s.
* *
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Network\NewAllocationRequest $request * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Network\NewAllocationRequest $request
* @param \Pterodactyl\Models\Server $server * @param \Pterodactyl\Models\Server $server

View File

@ -10,7 +10,6 @@ use Pterodactyl\Models\Server;
use Pterodactyl\Models\Schedule; use Pterodactyl\Models\Schedule;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Pterodactyl\Helpers\Utilities; use Pterodactyl\Helpers\Utilities;
use Pterodactyl\Jobs\Schedule\RunTaskJob;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Repositories\Eloquent\ScheduleRepository; use Pterodactyl\Repositories\Eloquent\ScheduleRepository;
use Pterodactyl\Services\Schedules\ProcessScheduleService; use Pterodactyl\Services\Schedules\ProcessScheduleService;
@ -173,7 +172,7 @@ class ScheduleController extends ClientApiController
*/ */
public function execute(TriggerScheduleRequest $request, Server $server, Schedule $schedule) public function execute(TriggerScheduleRequest $request, Server $server, Schedule $schedule)
{ {
if (!$schedule->is_active) { if (! $schedule->is_active) {
throw new BadRequestHttpException( throw new BadRequestHttpException(
'Cannot trigger schedule exection for a schedule that is not currently active.' 'Cannot trigger schedule exection for a schedule that is not currently active.'
); );

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Http\Controllers\Api\Client\Servers; namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
@ -88,7 +87,7 @@ class SettingsController extends ClientApiController
*/ */
public function dockerImage(SetDockerImageRequest $request, Server $server) public function dockerImage(SetDockerImageRequest $request, Server $server)
{ {
if (!in_array($server->image, $server->egg->docker_images)) { if (! in_array($server->image, $server->egg->docker_images)) {
throw new BadRequestHttpException( throw new BadRequestHttpException(
'This server\'s Docker image has been manually set by an administrator and cannot be updated.' 'This server\'s Docker image has been manually set by an administrator and cannot be updated.'
); );

View File

@ -86,11 +86,11 @@ class StartupController extends ClientApiController
if (is_null($variable) || ! $variable->user_viewable) { if (is_null($variable) || ! $variable->user_viewable) {
throw new BadRequestHttpException( throw new BadRequestHttpException(
"The environment variable you are trying to edit does not exist." 'The environment variable you are trying to edit does not exist.'
); );
} else if (! $variable->user_editable) { } elseif (! $variable->user_editable) {
throw new BadRequestHttpException( throw new BadRequestHttpException(
"The environment variable you are trying to edit is read-only." 'The environment variable you are trying to edit is read-only.'
); );
} }

View File

@ -85,7 +85,7 @@ class WebsocketController extends ClientApiController
return new JsonResponse([ return new JsonResponse([
'data' => [ 'data' => [
'token' => $token->__toString(), 'token' => $token->toString(),
'socket' => $socket . sprintf('/api/servers/%s/ws', $server->uuid), 'socket' => $socket . sprintf('/api/servers/%s/ws', $server->uuid),
], ],
]); ]);

View File

@ -6,8 +6,8 @@ use Carbon\CarbonImmutable;
use Pterodactyl\Models\Backup; use Pterodactyl\Models\Backup;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use League\Flysystem\AwsS3v3\AwsS3Adapter; use League\Flysystem\AwsS3v3\AwsS3Adapter;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Extensions\Backups\BackupManager; use Pterodactyl\Extensions\Backups\BackupManager;
use Pterodactyl\Repositories\Eloquent\BackupRepository; use Pterodactyl\Repositories\Eloquent\BackupRepository;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

View File

@ -85,7 +85,7 @@ class ServerDetailsController extends Controller
->where('node_id', $node->id) ->where('node_id', $node->id)
// If you don't cast this to a string you'll end up with a stringified per_page returned in // If you don't cast this to a string you'll end up with a stringified per_page returned in
// the metadata, and then Wings will panic crash as a result. // the metadata, and then Wings will panic crash as a result.
->paginate((int)$request->input('per_page', 50)); ->paginate((int) $request->input('per_page', 50));
return new ServerConfigurationCollection($servers); return new ServerConfigurationCollection($servers);
} }

View File

@ -2,7 +2,7 @@
namespace Pterodactyl\Http\Controllers\Api\Remote\Servers; namespace Pterodactyl\Http\Controllers\Api\Remote\Servers;
use Cake\Chronos\Chronos; use Carbon\CarbonImmutable;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
@ -110,11 +110,11 @@ class ServerTransferController extends Controller
Arr::set($data, 'suspended', false); Arr::set($data, 'suspended', false);
$this->connection->transaction(function () use ($data, $server) { $this->connection->transaction(function () use ($data, $server) {
// This token is used by the new node the server is being transfered to. It allows // This token is used by the new node the server is being transferred to. It allows
// that node to communicate with the old node during the process to initiate the // that node to communicate with the old node during the process to initiate the
// actual file transfer. // actual file transfer.
$token = $this->jwtService $token = $this->jwtService
->setExpiresAt(Chronos::now()->addMinutes(15)) ->setExpiresAt(CarbonImmutable::now()->addMinutes(15))
->setSubject($server->uuid) ->setSubject($server->uuid)
->handle($server->node, $server->uuid, 'sha256'); ->handle($server->node, $server->uuid, 'sha256');
@ -128,7 +128,7 @@ class ServerTransferController extends Controller
$this->daemonTransferRepository $this->daemonTransferRepository
->setServer($server) ->setServer($server)
->setNode($server->transfer->newNode) ->setNode($server->transfer->newNode)
->notify($server, $data, $server->node, $token->__toString()); ->notify($server, $data, $server->node, $token->toString());
}); });
return new JsonResponse([], Response::HTTP_NO_CONTENT); return new JsonResponse([], Response::HTTP_NO_CONTENT);

View File

@ -12,7 +12,6 @@ use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Http\Requests\Auth\LoginCheckpointRequest; use Pterodactyl\Http\Requests\Auth\LoginCheckpointRequest;
use Illuminate\Contracts\Cache\Repository as CacheRepository; use Illuminate\Contracts\Cache\Repository as CacheRepository;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface; use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Repositories\Eloquent\RecoveryTokenRepository; use Pterodactyl\Repositories\Eloquent\RecoveryTokenRepository;
class LoginCheckpointController extends AbstractLoginController class LoginCheckpointController extends AbstractLoginController

View File

@ -2,7 +2,7 @@
namespace Pterodactyl\Http\Controllers\Auth; namespace Pterodactyl\Http\Controllers\Auth;
use Cake\Chronos\Chronos; use Carbon\CarbonImmutable;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Auth\AuthManager; use Illuminate\Auth\AuthManager;
@ -101,7 +101,7 @@ class LoginController extends AbstractLoginController
if ($user->use_totp) { if ($user->use_totp) {
$token = Str::random(64); $token = Str::random(64);
$this->cache->put($token, $user->id, Chronos::now()->addMinutes(5)); $this->cache->put($token, $user->id, CarbonImmutable::now()->addMinutes(5));
return new JsonResponse([ return new JsonResponse([
'data' => [ 'data' => [

View File

@ -3,7 +3,7 @@
namespace Pterodactyl\Http\Middleware\Api; namespace Pterodactyl\Http\Middleware\Api;
use Closure; use Closure;
use Cake\Chronos\Chronos; use Carbon\CarbonImmutable;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Pterodactyl\Models\ApiKey; use Pterodactyl\Models\ApiKey;
@ -110,7 +110,7 @@ class AuthenticateKey
throw new AccessDeniedHttpException; throw new AccessDeniedHttpException;
} }
$this->repository->withoutFreshModel()->update($model->id, ['last_used_at' => Chronos::now()]); $this->repository->withoutFreshModel()->update($model->id, ['last_used_at' => CarbonImmutable::now()]);
return $model; return $model;
} }

View File

@ -8,8 +8,8 @@ use Pterodactyl\Models\Server;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
use Symfony\Component\HttpKernel\Exception\ConflictHttpException; use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Pterodactyl\Exceptions\Http\Server\ServerTransferringException; use Pterodactyl\Exceptions\Http\Server\ServerTransferringException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class AuthenticateServerAccess class AuthenticateServerAccess
{ {

View File

@ -7,11 +7,11 @@ use Illuminate\Http\Request;
use Pterodactyl\Models\Task; use Pterodactyl\Models\Task;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use InvalidArgumentException; use InvalidArgumentException;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Backup; use Pterodactyl\Models\Backup;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Subuser; use Pterodactyl\Models\Subuser;
use Pterodactyl\Models\Schedule;
use Pterodactyl\Models\Database; use Pterodactyl\Models\Database;
use Pterodactyl\Models\Schedule;
use Pterodactyl\Models\Allocation; use Pterodactyl\Models\Allocation;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

View File

@ -43,7 +43,7 @@ class SubstituteClientApiBindings extends ApiSubstituteBindings
} }
}); });
$this->router->bind('database', function ($value) use ($request) { $this->router->bind('database', function ($value) {
$id = Container::getInstance()->make(HashidsInterface::class)->decodeFirst($value); $id = Container::getInstance()->make(HashidsInterface::class)->decodeFirst($value);
return Database::query()->where('id', $id)->firstOrFail(); return Database::query()->where('id', $id)->firstOrFail();

View File

@ -59,14 +59,14 @@ class RequireTwoFactorAuthentication
return $next($request); return $next($request);
} }
$level = (int)config('pterodactyl.auth.2fa_required'); $level = (int) config('pterodactyl.auth.2fa_required');
// If this setting is not configured, or the user is already using 2FA then we can just // If this setting is not configured, or the user is already using 2FA then we can just
// send them right through, nothing else needs to be checked. // send them right through, nothing else needs to be checked.
// //
// If the level is set as admin and the user is not an admin, pass them through as well. // If the level is set as admin and the user is not an admin, pass them through as well.
if ($level === self::LEVEL_NONE || $user->use_totp) { if ($level === self::LEVEL_NONE || $user->use_totp) {
return $next($request); return $next($request);
} else if ($level === self::LEVEL_ADMIN && ! $user->root_admin) { } elseif ($level === self::LEVEL_ADMIN && ! $user->root_admin) {
return $next($request); return $next($request);
} }

View File

@ -44,7 +44,7 @@ class EggFormRequest extends AdminFormRequest
public function withValidator($validator) public function withValidator($validator)
{ {
$validator->sometimes('config_from', 'exists:eggs,id', function () { $validator->sometimes('config_from', 'exists:eggs,id', function () {
return (int)$this->input('config_from') !== 0; return (int) $this->input('config_from') !== 0;
}); });
} }
} }

View File

@ -24,7 +24,7 @@ class ServerConfigurationCollection extends ResourceCollection
$egg = Container::getInstance()->make(EggConfigurationService::class); $egg = Container::getInstance()->make(EggConfigurationService::class);
$configuration = Container::getInstance()->make(ServerConfigurationStructureService::class); $configuration = Container::getInstance()->make(ServerConfigurationStructureService::class);
return $this->collection->map(function (Server $server) use ($configuration, $egg) { return $this->collection->map(function (Server $server) use ($configuration, $egg) {
return [ return [
'uuid' => $server->uuid, 'uuid' => $server->uuid,
'settings' => $configuration->handle($server), 'settings' => $configuration->handle($server),

View File

@ -8,7 +8,6 @@ use Carbon\CarbonImmutable;
use Pterodactyl\Models\Task; use Pterodactyl\Models\Task;
use InvalidArgumentException; use InvalidArgumentException;
use Pterodactyl\Models\Schedule; use Pterodactyl\Models\Schedule;
use Illuminate\Support\Facades\Log;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;

View File

@ -18,6 +18,10 @@ use Pterodactyl\Services\Acl\Api\AdminAcl;
*/ */
class ApiKey extends Model class ApiKey extends Model
{ {
/**
* The resource name for this model when it is transformed into an
* API representation using fractal.
*/
const RESOURCE_NAME = 'api_key'; const RESOURCE_NAME = 'api_key';
/** /**

View File

@ -2,6 +2,18 @@
namespace Pterodactyl\Models; namespace Pterodactyl\Models;
/**
* @property int $id
* @property string $name
* @property string $host
* @property int $port
* @property string $username
* @property string $password
* @property int|null $max_databases
* @property int|null $node_id
* @property \Carbon\CarbonImmutable $created_at
* @property \Carbon\CarbonImmutable $updated_at
*/
class DatabaseHost extends Model class DatabaseHost extends Model
{ {
/** /**
@ -10,6 +22,11 @@ class DatabaseHost extends Model
*/ */
const RESOURCE_NAME = 'database_host'; const RESOURCE_NAME = 'database_host';
/**
* @var bool
*/
protected $immutableDates = true;
/** /**
* The table associated with the model. * The table associated with the model.
* *

View File

@ -42,12 +42,12 @@ class MultiFieldServerFilter implements Filter
$parts = explode(':', $value); $parts = explode(':', $value);
$builder->when( $builder->when(
!Str::startsWith($value, ':'), ! Str::startsWith($value, ':'),
// When the string does not start with a ":" it means we're looking for an IP or IP:Port // When the string does not start with a ":" it means we're looking for an IP or IP:Port
// combo, so use a query to handle that. // combo, so use a query to handle that.
function (Builder $builder) use ($parts) { function (Builder $builder) use ($parts) {
$builder->orWhere('allocations.ip', $parts[0]); $builder->orWhere('allocations.ip', $parts[0]);
if (!is_null($parts[1] ?? null)) { if (! is_null($parts[1] ?? null)) {
$builder->where('allocations.port', 'LIKE', "{$parts[1]}%"); $builder->where('allocations.port', 'LIKE', "{$parts[1]}%");
} }
}, },

View File

@ -6,11 +6,14 @@ use Illuminate\Support\Str;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Illuminate\Container\Container; use Illuminate\Container\Container;
use Illuminate\Contracts\Validation\Factory; use Illuminate\Contracts\Validation\Factory;
use Illuminate\Database\Eloquent\Model as IlluminateModel; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Pterodactyl\Exceptions\Model\DataValidationException; use Pterodactyl\Exceptions\Model\DataValidationException;
use Illuminate\Database\Eloquent\Model as IlluminateModel;
abstract class Model extends IlluminateModel abstract class Model extends IlluminateModel
{ {
use HasFactory;
/** /**
* Set to true to return immutable Carbon date instances from the model. * Set to true to return immutable Carbon date instances from the model.
* *

View File

@ -87,7 +87,7 @@ class Mount extends Model
public $timestamps = false; public $timestamps = false;
/** /**
* Blacklisted source paths * Blacklisted source paths.
* *
* @var string[] * @var string[]
*/ */
@ -98,7 +98,7 @@ class Mount extends Model
]; ];
/** /**
* Blacklisted target paths * Blacklisted target paths.
* *
* @var string[] * @var string[]
*/ */

View File

@ -202,7 +202,7 @@ class Node extends Model
*/ */
public function getDecryptedKey(): string public function getDecryptedKey(): string
{ {
return (string)Container::getInstance()->make(Encrypter::class)->decrypt( return (string) Container::getInstance()->make(Encrypter::class)->decrypt(
$this->daemon_token $this->daemon_token
); );
} }

View File

@ -7,6 +7,7 @@ use Cache;
use Pterodactyl\Models\User; use Pterodactyl\Models\User;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Pterodactyl\Models\Subuser; use Pterodactyl\Models\Subuser;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
use Pterodactyl\Observers\UserObserver; use Pterodactyl\Observers\UserObserver;
@ -29,6 +30,8 @@ class AppServiceProvider extends ServiceProvider
View::share('appVersion', $this->versionData()['version'] ?? 'undefined'); View::share('appVersion', $this->versionData()['version'] ?? 'undefined');
View::share('appIsGit', $this->versionData()['is_git'] ?? false); View::share('appIsGit', $this->versionData()['is_git'] ?? false);
Paginator::useBootstrap();
} }
/** /**

View File

@ -13,7 +13,7 @@ class BladeServiceProvider extends ServiceProvider
{ {
$this->app->make('blade.compiler') $this->app->make('blade.compiler')
->directive('datetimeHuman', function ($expression) { ->directive('datetimeHuman', function ($expression) {
return "<?php echo \Cake\Chronos\Chronos::createFromFormat(\Cake\Chronos\Chronos::DEFAULT_TO_STRING_FORMAT, $expression)->setTimezone(config('app.timezone'))->toDateTimeString(); ?>"; return "<?php echo \Carbon\CarbonImmutable::createFromFormat(\Carbon\CarbonImmutable::DEFAULT_TO_STRING_FORMAT, $expression)->setTimezone(config('app.timezone'))->toDateTimeString(); ?>";
}); });
} }
} }

View File

@ -8,7 +8,6 @@ use Illuminate\Foundation\Application;
use Illuminate\Database\DatabaseManager; use Illuminate\Database\DatabaseManager;
use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
use Pterodactyl\Exceptions\Repository\DuplicateDatabaseNameException;
class DatabaseRepository extends EloquentRepository implements DatabaseRepositoryInterface class DatabaseRepository extends EloquentRepository implements DatabaseRepositoryInterface
{ {

View File

@ -13,7 +13,6 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Pterodactyl\Contracts\Repository\RepositoryInterface; use Pterodactyl\Contracts\Repository\RepositoryInterface;
use Pterodactyl\Exceptions\Model\DataValidationException; use Pterodactyl\Exceptions\Model\DataValidationException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\Attributes\SearchableInterface;
abstract class EloquentRepository extends Repository implements RepositoryInterface abstract class EloquentRepository extends Repository implements RepositoryInterface
{ {

View File

@ -4,8 +4,6 @@ namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\LazyCollection;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface; use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
class NodeRepository extends EloquentRepository implements NodeRepositoryInterface class NodeRepository extends EloquentRepository implements NodeRepositoryInterface

View File

@ -51,7 +51,7 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
if (! is_null($server) && is_null($node)) { if (! is_null($server) && is_null($node)) {
$instance = $instance->where('id', '=', $server); $instance = $instance->where('id', '=', $server);
} else if (is_null($server) && ! is_null($node)) { } elseif (is_null($server) && ! is_null($node)) {
$instance = $instance->where('node_id', '=', $node); $instance = $instance->where('node_id', '=', $node);
} }
@ -71,7 +71,7 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
if (! is_null($server) && is_null($node)) { if (! is_null($server) && is_null($node)) {
$instance = $instance->where('id', '=', $server); $instance = $instance->where('id', '=', $server);
} else if (is_null($server) && ! is_null($node)) { } elseif (is_null($server) && ! is_null($node)) {
$instance = $instance->where('node_id', '=', $node); $instance = $instance->where('node_id', '=', $node);
} }

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Repositories\Wings; namespace Pterodactyl\Repositories\Wings;
use Illuminate\Support\Arr;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
use Pterodactyl\Models\Backup; use Pterodactyl\Models\Backup;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;

View File

@ -37,7 +37,7 @@ class DaemonFileRepository extends DaemonRepository
throw new DaemonConnectionException($exception); throw new DaemonConnectionException($exception);
} }
$length = (int)$response->getHeader('Content-Length')[0] ?? 0; $length = (int) $response->getHeader('Content-Length')[0] ?? 0;
if ($notLargerThan && $length > $notLargerThan) { if ($notLargerThan && $length > $notLargerThan) {
throw new FileSizeTooLargeException; throw new FileSizeTooLargeException;

View File

@ -3,7 +3,6 @@
namespace Pterodactyl\Repositories\Wings; namespace Pterodactyl\Repositories\Wings;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
use Pterodactyl\Models\User;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use GuzzleHttp\Exception\TransferException; use GuzzleHttp\Exception\TransferException;
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException; use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
@ -157,7 +156,7 @@ class DaemonServerRepository extends DaemonRepository
{ {
Assert::isInstanceOf($this->server, Server::class); Assert::isInstanceOf($this->server, Server::class);
$this->revokeJTIs([ md5($id . $this->server->uuid) ]); $this->revokeJTIs([md5($id . $this->server->uuid)]);
} }
/** /**

View File

@ -8,7 +8,6 @@ use Pterodactyl\Models\Server;
use Pterodactyl\Models\Database; use Pterodactyl\Models\Database;
use Pterodactyl\Helpers\Utilities; use Pterodactyl\Helpers\Utilities;
use Illuminate\Database\ConnectionInterface; use Illuminate\Database\ConnectionInterface;
use Symfony\Component\VarDumper\Cloner\Data;
use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Encryption\Encrypter;
use Pterodactyl\Extensions\DynamicDatabaseConnection; use Pterodactyl\Extensions\DynamicDatabaseConnection;
use Pterodactyl\Repositories\Eloquent\DatabaseRepository; use Pterodactyl\Repositories\Eloquent\DatabaseRepository;

View File

@ -2,8 +2,8 @@
namespace Pterodactyl\Services\Deployment; namespace Pterodactyl\Services\Deployment;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Webmozart\Assert\Assert;
use Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException; use Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException;
class FindViableNodesService class FindViableNodesService

View File

@ -108,7 +108,7 @@ class EggConfigurationService
// Normalize the output of the configuration for the new Wings Daemon to more // Normalize the output of the configuration for the new Wings Daemon to more
// easily ingest, as well as make things more flexible down the road. // easily ingest, as well as make things more flexible down the road.
foreach ($configs as $file => $data) { foreach ($configs as $file => $data) {
$append = array_merge((array)$data, ['file' => $file, 'replace' => []]); $append = array_merge((array) $data, ['file' => $file, 'replace' => []]);
foreach ($this->iterate($data->find, $structure) as $find => $replace) { foreach ($this->iterate($data->find, $structure) as $find => $replace) {
if (is_object($replace)) { if (is_object($replace)) {

View File

@ -119,7 +119,7 @@ class EggImporterService
], true, true); ], true, true);
collect($parsed->variables)->each(function ($variable) use ($egg) { collect($parsed->variables)->each(function ($variable) use ($egg) {
$this->eggVariableRepository->create(array_merge((array)$variable, [ $this->eggVariableRepository->create(array_merge((array) $variable, [
'egg_id' => $egg->id, 'egg_id' => $egg->id,
])); ]));
}); });

View File

@ -2,13 +2,14 @@
namespace Pterodactyl\Services\Nodes; namespace Pterodactyl\Services\Nodes;
use DateTimeInterface; use DateTimeImmutable;
use Lcobucci\JWT\Builder;
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Lcobucci\JWT\Signer\Key;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Pterodactyl\Extensions\Lcobucci\JWT\Encoding\TimestampDates;
class NodeJWTService class NodeJWTService
{ {
@ -18,7 +19,7 @@ class NodeJWTService
private $claims = []; private $claims = [];
/** /**
* @var int|null * @var \DateTimeImmutable|null
*/ */
private $expiresAt; private $expiresAt;
@ -41,12 +42,12 @@ class NodeJWTService
} }
/** /**
* @param \DateTimeInterface $date * @param \DateTimeImmutable $date
* @return $this * @return $this
*/ */
public function setExpiresAt(DateTimeInterface $date) public function setExpiresAt(DateTimeImmutable $date)
{ {
$this->expiresAt = $date->getTimestamp(); $this->expiresAt = $date;
return $this; return $this;
} }
@ -68,24 +69,27 @@ class NodeJWTService
* @param \Pterodactyl\Models\Node $node * @param \Pterodactyl\Models\Node $node
* @param string|null $identifiedBy * @param string|null $identifiedBy
* @param string $algo * @param string $algo
* @return \Lcobucci\JWT\Token * @return \Lcobucci\JWT\Token\Plain
*/ */
public function handle(Node $node, string $identifiedBy, string $algo = 'md5') public function handle(Node $node, string $identifiedBy, string $algo = 'md5')
{ {
$signer = new Sha256; $identifier = hash($algo, $identifiedBy);
$config = Configuration::forSymmetricSigner(new Sha256, InMemory::plainText($node->getDecryptedKey()));
$builder = (new Builder)->issuedBy(config('app.url')) $builder = $config->builder(new TimestampDates)
->issuedBy(config('app.url'))
->permittedFor($node->getConnectionAddress()) ->permittedFor($node->getConnectionAddress())
->identifiedBy(hash($algo, $identifiedBy), true) ->identifiedBy($identifier)
->issuedAt(CarbonImmutable::now()->getTimestamp()) ->withHeader('jti', $identifier)
->canOnlyBeUsedAfter(CarbonImmutable::now()->subMinutes(5)->getTimestamp()); ->issuedAt(CarbonImmutable::now())
->canOnlyBeUsedAfter(CarbonImmutable::now()->subMinutes(5));
if ($this->expiresAt) { if ($this->expiresAt) {
$builder = $builder->expiresAt($this->expiresAt); $builder = $builder->expiresAt($this->expiresAt);
} }
if (!empty($this->subject)) { if (! empty($this->subject)) {
$builder = $builder->relatedTo($this->subject, true); $builder = $builder->relatedTo($this->subject)->withHeader('sub', $this->subject);
} }
foreach ($this->claims as $key => $value) { foreach ($this->claims as $key => $value) {
@ -94,6 +98,6 @@ class NodeJWTService
return $builder return $builder
->withClaim('unique_id', Str::random(16)) ->withClaim('unique_id', Str::random(16))
->getToken($signer, new Key($node->getDecryptedKey())); ->getToken($config->signer(), $config->signingKey());
} }
} }

View File

@ -5,11 +5,9 @@ namespace Pterodactyl\Services\Nodes;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Pterodactyl\Models\Node; use Pterodactyl\Models\Node;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use GuzzleHttp\Exception\ConnectException;
use Illuminate\Database\ConnectionInterface; use Illuminate\Database\ConnectionInterface;
use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Contracts\Encryption\Encrypter;
use Pterodactyl\Repositories\Eloquent\NodeRepository; use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Daemon\ConfigurationRepository;
use Pterodactyl\Repositories\Wings\DaemonConfigurationRepository; use Pterodactyl\Repositories\Wings\DaemonConfigurationRepository;
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException; use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
use Pterodactyl\Exceptions\Service\Node\ConfigurationNotPersistedException; use Pterodactyl\Exceptions\Service\Node\ConfigurationNotPersistedException;
@ -101,7 +99,7 @@ class NodeUpdateService
// inject their own response pages, causing this logic to get fucked up. // inject their own response pages, causing this logic to get fucked up.
// //
// @see https://github.com/pterodactyl/panel/issues/2712 // @see https://github.com/pterodactyl/panel/issues/2712
return [ $updated, true ]; return [$updated, true];
} }
return [$updated, false]; return [$updated, false];

View File

@ -82,7 +82,7 @@ class BuildModificationService
$updateData = $this->structureService->handle($server); $updateData = $this->structureService->handle($server);
if (!empty($updateData['build'])) { if (! empty($updateData['build'])) {
$this->daemonServerRepository->setServer($server)->update([ $this->daemonServerRepository->setServer($server)->update([
'build' => $updateData['build'], 'build' => $updateData['build'],
]); ]);

View File

@ -4,7 +4,6 @@ namespace Pterodactyl\Services\Servers;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Database\ConnectionInterface; use Illuminate\Database\ConnectionInterface;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Repositories\Wings\DaemonServerRepository; use Pterodactyl\Repositories\Wings\DaemonServerRepository;
class ReinstallServerService class ReinstallServerService

View File

@ -38,7 +38,7 @@ class ServerConfigurationStructureService
$clone = $server; $clone = $server;
// If any overrides have been set on this call make sure to update them on the // If any overrides have been set on this call make sure to update them on the
// cloned instance so that the configuration generated uses them. // cloned instance so that the configuration generated uses them.
if (!empty($override)) { if (! empty($override)) {
$clone = $server->fresh(); $clone = $server->fresh();
foreach ($override as $key => $value) { foreach ($override as $key => $value) {
$clone->setAttribute($key, $value); $clone->setAttribute($key, $value);
@ -95,10 +95,10 @@ class ServerConfigurationStructureService
'id' => $server->egg->uuid, 'id' => $server->egg->uuid,
'file_denylist' => [ 'file_denylist' => [
'config.yml', 'config.yml',
'**/*.json' '**/*.json',
] ],
// 'file_denylist' => explode(PHP_EOL, $server->egg->inherit_file_denylist), // 'file_denylist' => explode(PHP_EOL, $server->egg->inherit_file_denylist),
] ],
]; ];
} }
@ -124,12 +124,12 @@ class ServerConfigurationStructureService
})->toArray(), })->toArray(),
'env' => $this->environment->handle($server), 'env' => $this->environment->handle($server),
'oom_disabled' => $server->oom_disabled, 'oom_disabled' => $server->oom_disabled,
'memory' => (int)$server->memory, 'memory' => (int) $server->memory,
'swap' => (int)$server->swap, 'swap' => (int) $server->swap,
'io' => (int)$server->io, 'io' => (int) $server->io,
'cpu' => (int)$server->cpu, 'cpu' => (int) $server->cpu,
'threads' => $server->threads, 'threads' => $server->threads,
'disk' => (int)$server->disk, 'disk' => (int) $server->disk,
'image' => $server->image, 'image' => $server->image,
], ],
'service' => [ 'service' => [
@ -137,7 +137,7 @@ class ServerConfigurationStructureService
'skip_scripts' => $server->skip_scripts, 'skip_scripts' => $server->skip_scripts,
], ],
'rebuild' => false, 'rebuild' => false,
'suspended' => (int)$server->suspended, 'suspended' => (int) $server->suspended,
]; ];
} }
} }

View File

@ -92,7 +92,7 @@ class ServerDeletionService
try { try {
$this->databaseManagementService->delete($database); $this->databaseManagementService->delete($database);
} catch (Exception $exception) { } catch (Exception $exception) {
if (!$this->force) { if (! $this->force) {
throw $exception; throw $exception;
} }

View File

@ -20,7 +20,7 @@ class StartupCommandService
foreach ($server->variables as $variable) { foreach ($server->variables as $variable) {
$find[] = '{{' . $variable->env_variable . '}}'; $find[] = '{{' . $variable->env_variable . '}}';
$replace[] = ($variable->user_viewable && !$hideAllValues) ? ($variable->server_value ?? $variable->default_value) : '[hidden]'; $replace[] = ($variable->user_viewable && ! $hideAllValues) ? ($variable->server_value ?? $variable->default_value) : '[hidden]';
} }
return str_replace($find, $replace, $server->startup); return str_replace($find, $replace, $server->startup);

View File

@ -91,7 +91,7 @@ class StartupModificationService
{ {
$eggId = Arr::get($data, 'egg_id'); $eggId = Arr::get($data, 'egg_id');
if (is_digit($eggId) && $server->egg_id !== (int)$eggId) { if (is_digit($eggId) && $server->egg_id !== (int) $eggId) {
/** @var \Pterodactyl\Models\Egg $egg */ /** @var \Pterodactyl\Models\Egg $egg */
$egg = Egg::query()->findOrFail($data['egg_id']); $egg = Egg::query()->findOrFail($data['egg_id']);

View File

@ -6,7 +6,6 @@ use Webmozart\Assert\Assert;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Illuminate\Database\ConnectionInterface; use Illuminate\Database\ConnectionInterface;
use Pterodactyl\Repositories\Wings\DaemonServerRepository; use Pterodactyl\Repositories\Wings\DaemonServerRepository;
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
use Pterodactyl\Exceptions\Http\Server\ServerTransferringException; use Pterodactyl\Exceptions\Http\Server\ServerTransferringException;
class SuspensionService class SuspensionService

View File

@ -68,7 +68,7 @@ class VariableValidatorService
} }
return Collection::make($variables)->map(function ($item) use ($fields) { return Collection::make($variables)->map(function ($item) use ($fields) {
return (object)[ return (object) [
'id' => $item->id, 'id' => $item->id,
'key' => $item->env_variable, 'key' => $item->env_variable,
'value' => $fields[$item->env_variable] ?? null, 'value' => $fields[$item->env_variable] ?? null,

View File

@ -2,7 +2,7 @@
namespace Pterodactyl\Transformers\Api\Application; namespace Pterodactyl\Transformers\Api\Application;
use Cake\Chronos\Chronos; use Carbon\CarbonImmutable;
use Pterodactyl\Models\ApiKey; use Pterodactyl\Models\ApiKey;
use Illuminate\Container\Container; use Illuminate\Container\Container;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@ -107,7 +107,7 @@ abstract class BaseTransformer extends TransformerAbstract
*/ */
protected function formatTimestamp(string $timestamp): string protected function formatTimestamp(string $timestamp): string
{ {
return Chronos::createFromFormat(Chronos::DEFAULT_TO_STRING_FORMAT, $timestamp) return CarbonImmutable::createFromFormat(CarbonImmutable::DEFAULT_TO_STRING_FORMAT, $timestamp)
->setTimezone(self::RESPONSE_TIMEZONE) ->setTimezone(self::RESPONSE_TIMEZONE)
->toIso8601String(); ->toIso8601String();
} }

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Transformers\Api\Application; namespace Pterodactyl\Transformers\Api\Application;
use Cake\Chronos\Chronos;
use Pterodactyl\Models\Database; use Pterodactyl\Models\Database;
use Pterodactyl\Models\DatabaseHost; use Pterodactyl\Models\DatabaseHost;
use Pterodactyl\Services\Acl\Api\AdminAcl; use Pterodactyl\Services\Acl\Api\AdminAcl;
@ -41,12 +40,8 @@ class DatabaseHostTransformer extends BaseTransformer
'port' => $model->port, 'port' => $model->port,
'username' => $model->username, 'username' => $model->username,
'node' => $model->node_id, 'node' => $model->node_id,
'created_at' => Chronos::createFromFormat(Chronos::DEFAULT_TO_STRING_FORMAT, $model->created_at) 'created_at' => $model->created_at->toIso8601String(),
->setTimezone(config('app.timezone')) 'updated_at' => $model->updated_at->toIso8601String(),
->toIso8601String(),
'updated_at' => Chronos::createFromFormat(Chronos::DEFAULT_TO_STRING_FORMAT, $model->updated_at)
->setTimezone(config('app.timezone'))
->toIso8601String(),
]; ];
} }

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Transformers\Api\Application; namespace Pterodactyl\Transformers\Api\Application;
use Cake\Chronos\Chronos;
use Pterodactyl\Models\Database; use Pterodactyl\Models\Database;
use Pterodactyl\Models\DatabaseHost; use Pterodactyl\Models\DatabaseHost;
use Pterodactyl\Services\Acl\Api\AdminAcl; use Pterodactyl\Services\Acl\Api\AdminAcl;
@ -56,12 +55,8 @@ class ServerDatabaseTransformer extends BaseTransformer
'username' => $model->username, 'username' => $model->username,
'remote' => $model->remote, 'remote' => $model->remote,
'max_connections' => $model->max_connections, 'max_connections' => $model->max_connections,
'created_at' => Chronos::createFromFormat(Chronos::DEFAULT_TO_STRING_FORMAT, $model->created_at) 'created_at' => $model->created_at->toIso8601String(),
->setTimezone(config('app.timezone')) 'updated_at' => $model->updated_at->toIso8601String(),
->toIso8601String(),
'updated_at' => Chronos::createFromFormat(Chronos::DEFAULT_TO_STRING_FORMAT, $model->updated_at)
->setTimezone(config('app.timezone'))
->toIso8601String(),
]; ];
} }

View File

@ -3,7 +3,6 @@
namespace Pterodactyl\Transformers\Api\Application; namespace Pterodactyl\Transformers\Api\Application;
use Pterodactyl\Models\Subuser; use Pterodactyl\Models\Subuser;
use Pterodactyl\Models\Permission;
use Pterodactyl\Services\Acl\Api\AdminAcl; use Pterodactyl\Services\Acl\Api\AdminAcl;
class SubuserTransformer extends BaseTransformer class SubuserTransformer extends BaseTransformer

View File

@ -3,7 +3,6 @@
namespace Pterodactyl\Transformers\Api\Client; namespace Pterodactyl\Transformers\Api\Client;
use BadMethodCallException; use BadMethodCallException;
use InvalidArgumentException;
use Pterodactyl\Models\EggVariable; use Pterodactyl\Models\EggVariable;
class EggVariableTransformer extends BaseClientTransformer class EggVariableTransformer extends BaseClientTransformer
@ -25,7 +24,7 @@ class EggVariableTransformer extends BaseClientTransformer
// This guards against someone incorrectly retrieving variables (haha, me) and then passing // This guards against someone incorrectly retrieving variables (haha, me) and then passing
// them into the transformer and along to the user. Just throw an exception and break the entire // them into the transformer and along to the user. Just throw an exception and break the entire
// pathway since you should never be exposing these types of variables to a client. // pathway since you should never be exposing these types of variables to a client.
if (!$variable->user_viewable) { if (! $variable->user_viewable) {
throw new BadMethodCallException( throw new BadMethodCallException(
'Cannot transform a hidden egg variable in a client transformer.' 'Cannot transform a hidden egg variable in a client transformer.'
); );

View File

@ -12,7 +12,7 @@
*/ */
$app = new Illuminate\Foundation\Application( $app = new Illuminate\Foundation\Application(
realpath(__DIR__ . '/../') $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
); );
/* /*

View File

@ -1,5 +1,6 @@
<?php <?php
use NunoMaduro\Collision\Provider;
use Illuminate\Contracts\Console\Kernel; use Illuminate\Contracts\Console\Kernel;
use Symfony\Component\Console\Output\ConsoleOutput; use Symfony\Component\Console\Output\ConsoleOutput;
@ -15,6 +16,10 @@ $kernel = $app->make(Kernel::class);
*/ */
$kernel->bootstrap(); $kernel->bootstrap();
// Register the collision service provider so that errors during the test
// setup process are output nicely.
(new Provider)->register();
$output = new ConsoleOutput; $output = new ConsoleOutput;
if (config('database.default') !== 'testing') { if (config('database.default') !== 'testing') {

View File

@ -11,64 +11,60 @@
} }
], ],
"require": { "require": {
"php": "^7.2", "php": "^7.4 || ^8.0",
"ext-json": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"ext-pdo_mysql": "*", "ext-pdo_mysql": "*",
"ext-zip": "*", "ext-zip": "*",
"appstract/laravel-blade-directives": "^1.8", "aws/aws-sdk-php": "^3.171",
"aws/aws-sdk-php": "^3.134", "doctrine/dbal": "^2.12",
"cakephp/chronos": "^1.3", "fideloper/proxy": "^4.4",
"doctrine/dbal": "^2.10", "guzzlehttp/guzzle": "^7.2",
"fideloper/proxy": "^4.2", "hashids/hashids": "^4.1",
"guzzlehttp/guzzle": "^6.5", "laracasts/utilities": "^3.2",
"hashids/hashids": "^4.0", "laravel/framework": "^8.22",
"laracasts/utilities": "^3.1", "laravel/helpers": "^1.4",
"laravel/framework": "^7.17", "laravel/tinker": "^2.5",
"laravel/helpers": "^1.2", "laravel/ui": "^3.0",
"laravel/tinker": "^2.4", "lcobucci/jwt": "^4.0",
"laravel/ui": "^2.0",
"lcobucci/jwt": "^3.3",
"league/flysystem-aws-s3-v3": "^1.0", "league/flysystem-aws-s3-v3": "^1.0",
"league/flysystem-memory": "^1.0", "league/flysystem-memory": "^1.0",
"matriphe/iso-639": "^1.2", "matriphe/iso-639": "^1.2",
"pragmarx/google2fa": "^5.0", "pragmarx/google2fa": "^5.0",
"predis/predis": "^1.1", "predis/predis": "^1.1",
"prologue/alerts": "^0.4", "prologue/alerts": "^0.4",
"psy/psysh": "^0.10.4",
"s1lentium/iptools": "^1.1", "s1lentium/iptools": "^1.1",
"spatie/laravel-fractal": "^5.7", "spatie/laravel-fractal": "^5.8",
"spatie/laravel-query-builder": "^2.8", "spatie/laravel-query-builder": "^3.3",
"staudenmeir/belongs-to-through": "^2.10", "staudenmeir/belongs-to-through": "^2.11",
"symfony/yaml": "^4.4", "symfony/yaml": "^4.4",
"webmozart/assert": "^1.9" "webmozart/assert": "^1.9"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.3", "barryvdh/laravel-debugbar": "^3.5",
"barryvdh/laravel-ide-helper": "^2.7", "barryvdh/laravel-ide-helper": "^2.9",
"codedungeon/phpunit-result-printer": "^0.28.0", "facade/ignition": "^2.5",
"friendsofphp/php-cs-fixer": "2.16.1", "fakerphp/faker": "^1.13",
"fzaninotto/faker": "^1.9", "friendsofphp/php-cs-fixer": "^2.18",
"laravel/dusk": "^6.3", "laravel/dusk": "^6.11",
"mockery/mockery": "^1.4", "mockery/mockery": "^1.4",
"nunomaduro/collision": "^5.2",
"php-mock/php-mock-phpunit": "^2.6", "php-mock/php-mock-phpunit": "^2.6",
"phpunit/phpunit": "^8.5" "phpunit/phpunit": "^9.0"
}, },
"autoload": { "autoload": {
"classmap": [
"database"
],
"files": [ "files": [
"app/helpers.php" "app/helpers.php"
], ],
"psr-4": { "psr-4": {
"Pterodactyl\\": "app/" "Pterodactyl\\": "app/",
"Database\\Factories\\": "database/Factories/",
"Database\\Seeders\\": "database/Seeders/"
} }
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"Pterodactyl\\Tests\\Browser\\": "tests/Browser", "Pterodactyl\\Tests\\": "tests/"
"Pterodactyl\\Tests\\Integration\\": "tests/Integration",
"Tests\\": "tests/"
} }
}, },
"scripts": { "scripts": {

4816
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -45,7 +45,7 @@ return [
'collation' => 'utf8mb4_unicode_ci', 'collation' => 'utf8mb4_unicode_ci',
'prefix' => env('DB_PREFIX', ''), 'prefix' => env('DB_PREFIX', ''),
'strict' => env('DB_STRICT_MODE', false), 'strict' => env('DB_STRICT_MODE', false),
'timezone' => env('DB_TIMEZONE', Time::getMySQLTimezoneOffset(env('APP_TIMEZONE', 'UTC'))) 'timezone' => env('DB_TIMEZONE', Time::getMySQLTimezoneOffset(env('APP_TIMEZONE', 'UTC'))),
], ],
/* /*
@ -68,7 +68,7 @@ return [
'collation' => 'utf8mb4_unicode_ci', 'collation' => 'utf8mb4_unicode_ci',
'prefix' => '', 'prefix' => '',
'strict' => false, 'strict' => false,
'timezone' => env('DB_TIMEZONE', Time::getMySQLTimezoneOffset(env('APP_TIMEZONE', 'UTC'))) 'timezone' => env('DB_TIMEZONE', Time::getMySQLTimezoneOffset(env('APP_TIMEZONE', 'UTC'))),
], ],
], ],

View File

@ -10,7 +10,7 @@ return [
| setup on the panel. When set to true, configurations stored in the | setup on the panel. When set to true, configurations stored in the
| database will not be applied. | database will not be applied.
*/ */
'load_environment_only' => (bool)env('APP_ENVIRONMENT_ONLY', false), 'load_environment_only' => (bool) env('APP_ENVIRONMENT_ONLY', false),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -0,0 +1,29 @@
<?php
namespace Database\Factories;
use Pterodactyl\Models\Allocation;
use Illuminate\Database\Eloquent\Factories\Factory;
class AllocationFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Allocation::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'ip' => $this->faker->ipv4,
'port' => $this->faker->randomNumber(5),
];
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Database\Factories;
use Carbon\Carbon;
use Illuminate\Support\Str;
use Pterodactyl\Models\ApiKey;
use Illuminate\Database\Eloquent\Factories\Factory;
class ApiKeyFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = ApiKey::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
static $token;
return [
'key_type' => ApiKey::TYPE_APPLICATION,
'identifier' => Str::random(\Pterodactyl\Models\ApiKey::IDENTIFIER_LENGTH),
'token' => $token ?: $token = encrypt(Str::random(\Pterodactyl\Models\ApiKey::KEY_LENGTH)),
'allowed_ips' => null,
'memo' => 'Test Function Key',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
];
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Database\Factories;
use Ramsey\Uuid\Uuid;
use Pterodactyl\Models\Backup;
use Illuminate\Database\Eloquent\Factories\Factory;
class BackupFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Backup::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'uuid' => Uuid::uuid4()->toString(),
'is_successful' => true,
'name' => $this->faker->sentence,
'disk' => Backup::ADAPTER_WINGS,
];
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Database\Factories;
use Carbon\Carbon;
use Illuminate\Support\Str;
use Pterodactyl\Models\Database;
use Illuminate\Database\Eloquent\Factories\Factory;
class DatabaseFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Database::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
static $password;
return [
'database' => Str::random(10),
'username' => Str::random(10),
'remote' => '%',
'password' => $password ?: encrypt('test123'),
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
];
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Database\Factories;
use Pterodactyl\Models\DatabaseHost;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Database\Eloquent\Factories\Factory;
class DatabaseHostFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = DatabaseHost::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'name' => $this->faker->colorName,
'host' => $this->faker->unique()->ipv4,
'port' => 3306,
'username' => $this->faker->colorName,
'password' => Crypt::encrypt($this->faker->word),
];
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Database\Factories;
use Ramsey\Uuid\Uuid;
use Pterodactyl\Models\Egg;
use Illuminate\Database\Eloquent\Factories\Factory;
class EggFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Egg::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'uuid' => Uuid::uuid4()->toString(),
'name' => $this->faker->name,
'description' => implode(' ', $this->faker->sentences()),
'startup' => 'java -jar test.jar',
];
}
}

View File

@ -0,0 +1,63 @@
<?php
namespace Database\Factories;
use Illuminate\Support\Str;
use Pterodactyl\Models\EggVariable;
use Illuminate\Database\Eloquent\Factories\Factory;
class EggVariableFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = EggVariable::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'name' => $this->faker->firstName,
'description' => $this->faker->sentence(),
'env_variable' => Str::upper(Str::replaceArray(' ', ['_'], $this->faker->words(2, true))),
'default_value' => $this->faker->colorName,
'user_viewable' => 0,
'user_editable' => 0,
'rules' => 'required|string',
];
}
/**
* Indicate that the egg variable is viewable.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function viewable(): Factory
{
return $this->state(function (array $attributes) {
return [
'user_viewable' => 1,
];
});
}
/**
* Indicate that the egg variable is editable.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function editable(): Factory
{
return $this->state(function (array $attributes) {
return [
'user_editable' => 1,
];
});
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Database\Factories;
use Illuminate\Support\Str;
use Pterodactyl\Models\Location;
use Illuminate\Database\Eloquent\Factories\Factory;
class LocationFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Location::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'short' => Str::random(8),
'long' => Str::random(32),
];
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Database\Factories;
use Ramsey\Uuid\Uuid;
use Pterodactyl\Models\Nest;
use Illuminate\Database\Eloquent\Factories\Factory;
class NestFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Nest::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'uuid' => Uuid::uuid4()->toString(),
'author' => 'testauthor@example.com',
'name' => $this->faker->word,
'description' => null,
];
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Database\Factories;
use Ramsey\Uuid\Uuid;
use Illuminate\Support\Str;
use Pterodactyl\Models\Node;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Database\Eloquent\Factories\Factory;
class NodeFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Node::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'uuid' => Uuid::uuid4()->toString(),
'public' => true,
'name' => $this->faker->firstName,
'fqdn' => $this->faker->ipv4,
'scheme' => 'http',
'behind_proxy' => false,
'memory' => 1024,
'memory_overallocate' => 0,
'disk' => 10240,
'disk_overallocate' => 0,
'upload_size' => 100,
'daemon_token_id' => Str::random(Node::DAEMON_TOKEN_ID_LENGTH),
'daemon_token' => Crypt::encrypt(Str::random(Node::DAEMON_TOKEN_LENGTH)),
'daemonListen' => 8080,
'daemonSFTP' => 2022,
'daemonBase' => '/var/lib/pterodactyl/volumes',
];
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Database\Factories;
use Pterodactyl\Models\Schedule;
use Illuminate\Database\Eloquent\Factories\Factory;
class ScheduleFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Schedule::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'name' => $this->faker->firstName(),
];
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace Database\Factories;
use Carbon\Carbon;
use Ramsey\Uuid\Uuid;
use Illuminate\Support\Str;
use Pterodactyl\Models\Server;
use Illuminate\Database\Eloquent\Factories\Factory;
class ServerFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Server::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'uuid' => Uuid::uuid4()->toString(),
'uuidShort' => Str::lower(Str::random(8)),
'name' => $this->faker->firstName,
'description' => implode(' ', $this->faker->sentences()),
'skip_scripts' => 0,
'suspended' => 0,
'memory' => 512,
'swap' => 0,
'disk' => 512,
'io' => 500,
'cpu' => 0,
'threads' => null,
'oom_disabled' => 0,
'installed' => 1,
'allocation_limit' => null,
'database_limit' => null,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
];
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Database\Factories;
use Pterodactyl\Models\Subuser;
use Pterodactyl\Models\Permission;
use Illuminate\Database\Eloquent\Factories\Factory;
class SubuserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Subuser::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'permissions' => [
Permission::ACTION_WEBSOCKET_CONNECT,
],
];
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Database\Factories;
use Pterodactyl\Models\Task;
use Illuminate\Database\Eloquent\Factories\Factory;
class TaskFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Task::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
return [
'sequence_id' => $this->faker->randomNumber(1),
'action' => 'command',
'payload' => 'test command',
'time_offset' => 120,
'is_queued' => false,
];
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace Database\Factories;
use Carbon\Carbon;
use Ramsey\Uuid\Uuid;
use Pterodactyl\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition(): array
{
static $password;
return [
'external_id' => $this->faker->unique()->isbn10,
'uuid' => Uuid::uuid4()->toString(),
'username' => $this->faker->userName,
'email' => $this->faker->safeEmail,
'name_first' => $this->faker->firstName,
'name_last' => $this->faker->lastName,
'password' => $password ?: $password = bcrypt('password'),
'language' => 'en',
'root_admin' => false,
'use_totp' => false,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
];
}
/**
* Indicate that the user is an admin.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function admin(): Factory
{
return $this->state(function (array $attributes) {
return [
'root_admin' => true,
];
});
}
}

View File

@ -1,5 +1,7 @@
<?php <?php
namespace Database\Seeders;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder class DatabaseSeeder extends Seeder

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