diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 000000000..fff6b3500
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,2 @@
+public
+resources/views
diff --git a/resources/scripts/.eslintrc.yml b/.eslintrc.yml
similarity index 100%
rename from resources/scripts/.eslintrc.yml
rename to .eslintrc.yml
diff --git a/.github/ISSUE_TEMPLATE/--installation-help.md b/.github/ISSUE_TEMPLATE/--installation-help.md
deleted file mode 100644
index 4d5d27e71..000000000
--- a/.github/ISSUE_TEMPLATE/--installation-help.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-name: "â›” Installation Help"
-about: 'Visit our Discord for installation help: https://pterodactyl.io/discord'
-
----
-
-We use GitHub issues only to discuss about Pterodactyl bugs and new features. For
-this kind of questions about using Pterodactyl, please visit our Discord for assistance: https://pterodactyl.io/discord
-
-DO NOT REPORT ISSUES CONFIGURING: SSL, PHP, APACHE, NGINX, YOUR MACHINE, SSH, SFTP, ETC. ON THIS GITHUB TRACKER.
-
-For assistance installating this software, as well as debugging issues with dependencies, please use our discord server: https://discord.gg/pterodactyl
-
-PLEASE stop spamming our tracker with "bugs" that are not related to this project.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000..b3b99a661
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: true
+contact_links:
+ - name: 🤷 Installation Help
+ url: https://discord.gg/pterodactyl
+ about: Please visit our Discord for help with your installation.
+ - name: âť“ General Question
+ url: https://discord.gg/pterodactyl
+ about: Please visit our Discord for general questions about Pterodactyl.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index faf955b18..0dfb9e661 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,56 @@ This file is a running track of new features and fixes to each version of the pa
This project follows [Semantic Versioning](http://semver.org) guidelines.
+## v1.0.3
+### Fixed
+* Fixes bug causing subusers to not be creatable or editable via the frontend for servers.
+* Fixes system timezone not being passed along properly to the MySQL connection causing scheduled tasks to run every minute when the MySQL instance and Panel timezone did not line up.
+* Fixes listing servers owned by a user in the admin area to actually list their servers.
+
+### Changed
+* Adds SameSite `lax` attribute for cookies generated by the Panel.
+* Adds better filtering for searching servers in the admin area to better key off name, uuid, or owner username/email.
+
+## v1.0.2
+### Added
+* Adds support for searching inside the file editor.
+* Adds support for manually executing a schedule regardless of if it is currently queued or not.
+* Adds an indicator to the schedule UI to show when a schedule is currently processing.
+* Adds support for setting the `backup_limit` of a server via the API.
+* **[Security]** Adds login throttling to the 2FA verification endpoint.
+
+### Fixed
+* Fixes subuser page title missing server name.
+* Fixes schedule task `sequence_id` not properly being reset when a schedule's task is deleted.
+* Fixes misc. UI bugs throughout the frontend when long text overflows its bounds.
+* Fixes user deletion command to properly handle email & ID searching.
+* Fixes color issues in the terminal causing certain text & background combinations to be illegible.
+* Fixes reCAPTCHA not properly resetting on login failure.
+* Fixes error messages not properly resetting between login screens.
+* Fixes a UI crash when attempting to create or view a directory or file that contained the `%` somewhere in the name.
+
+### Changed
+* Updated the search modal to close itself when the ESC key is pressed.
+* Updates the schedule view and editing UI to better display information to users.
+* Changed logic powering server searching on the frontend to return more accurate results and return all servers when executing the query as an admin.
+* Admin CP link no longer opens in a new tab.
+* Mounts will no longer allow a user to mount certain directory combinations. This blocks mounting one server's files into another server, and blocks using the server data directory as a mount destination.
+* Cleaned up assorted server build modification code.
+* Updates default eggs to have improved install scripts and more consistent container usage.
+
+## v1.0.1
+### Fixed
+* Fixes 500 error when mounting a mount to a server, and other related errors when handling mounts.
+* Ensures that `server_transfers` database is deleted if it already exists to avoid unnecessary error.
+* Fixes servers getting marked as "not installed" when modifying their startup arguments.
+* Fixes filemanager breadcrumbs being set incorrectly when navigating between files and folders.
+
+### Changed
+* Change the requests per minute from 240 to 720 for the client API to avoid unecessarily displaying
+"Too Many Requests" errors.
+* Added error output to certain commands that will output and terminate the command execution if the database
+migrations have not been run correctly for the instance.
+
## v1.0.0
Pterodactyl 1.0 represents the culmination of over two years of work, almost 2,000 commits, endless bug and feature requests, and a dream that
has been in the making since 2013. 🎉
diff --git a/README.md b/README.md
index df1b21d4a..ace35378b 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,6 @@
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/pterodactyl/panel/tests?label=Tests&style=for-the-badge)
![Discord](https://img.shields.io/discord/122900397965705216?label=Discord&logo=Discord&logoColor=white&style=for-the-badge)
![GitHub Releases](https://img.shields.io/github/downloads/pterodactyl/panel/latest/total?style=for-the-badge)
-![GitHub Pre-Releases](https://img.shields.io/github/downloads-pre/pterodactyl/panel/v1.0.0-rc.7/total?style=for-the-badge)
![GitHub contributors](https://img.shields.io/github/contributors/pterodactyl/panel?style=for-the-badge)
# Pterodactyl Panel
@@ -16,18 +15,21 @@ Stop settling for less. Make game servers a first class citizen on your platform
![Image](https://cdn.pterodactyl.io/site-assets/pterodactyl_v1_demo.gif)
## Sponsors
-I would like to extend my sincere thanks to the following sponsors for helping find Pterodactyl's developement.
+I would like to extend my sincere thanks to the following sponsors for helping fund Pterodactyl's developement.
[Interested in becoming a sponsor?](https://github.com/sponsors/DaneEveritt)
| Company | About |
| ------- | ----- |
+| [**WISP**](https://wisp.gg) | Extra features. |
| [**Bloom.host**](https://bloom.host) | Bloom.host offers dedicated core VPS and Minecraft hosting with Ryzen 9 processors. With owned-hardware, we offer truly unbeatable prices on high-performance hosting. |
-| [**VersatileNode**](https://versatilenode.com/) | Looking to host a minecraft server, vps, or a website? VersatileNode is one of the most affordable hosting providers to provide quality yet cheap services with incredible support. |
| [**MineStrator**](https://minestrator.com/) | Looking for a French highend hosting company for you minecraft server? More than 14,000 members on our discord, trust us. |
| [**DedicatedMC**](https://dedicatedmc.io/) | DedicatedMC provides Raw Power hosting at affordable pricing, making sure to never compromise on your performance and giving you the best performance money can buy. |
| [**Skynode**](https://www.skynode.pro/) | Skynode provides blazing fast game servers along with a top-notch user experience. Whatever our clients are looking for, we're able to provide it! |
| [**XCORE-SERVER.de**](https://xcore-server.de/) | XCORE-SERVER.de offers High-End Servers for hosting and gaming since 2012. Fast, excellent and well-known for eSports Gaming. |
-| [**RoyaleHosting**](https://royalehosting.net/) | Build your dreams and deploy them with RoyaleHosting’s reliable servers and network. Easy to use, provisioned in a couple of minutes. |
+| [**RoyaleHosting**](https://royalehosting.net/) | Build your dreams and deploy them with RoyaleHosting’s reliable servers and network. Easy to use, provisioned in a couple of minutes. |
+| [**Spill Hosting**](https://spillhosting.no/) | Spill Hosting is a Norwegian hosting service, which aims to cheap services on quality servers. Premium i9-9900K processors will run your game like a dream. |
+| [**DeinServerHost**](https://deinserverhost.de/) | DeinServerHost offers Dedicated, vps and Gameservers for many popular Games like Minecraft and Rust in Germany since 2013. |
+| [**HostBend**](https://hostbend.com/) | HostBend offers a variety of solutions for developers, students, and others who have a tight budget but don't want to compromise quality and support. |
## Documentation
* [Panel Documentation](https://pterodactyl.io/panel/1.0/getting_started.html)
diff --git a/app/Console/Commands/Environment/AppSettingsCommand.php b/app/Console/Commands/Environment/AppSettingsCommand.php
index 60254a9ef..01518d610 100644
--- a/app/Console/Commands/Environment/AppSettingsCommand.php
+++ b/app/Console/Commands/Environment/AppSettingsCommand.php
@@ -144,6 +144,11 @@ class AppSettingsCommand extends Command
$this->variables['APP_ENVIRONMENT_ONLY'] = $this->confirm(trans('command/messages.environment.app.settings'), true) ? 'false' : 'true';
}
+ // Make sure session cookies are set as "secure" when using HTTPS
+ if (strpos($this->variables['APP_URL'], 'https://') === 0) {
+ $this->variables['SESSION_SECURE_COOKIE'] = 'true';
+ }
+
$this->checkForRedis();
$this->writeToEnvironment($this->variables);
diff --git a/app/Console/Commands/Schedule/ProcessRunnableCommand.php b/app/Console/Commands/Schedule/ProcessRunnableCommand.php
index 67654708c..310b2f3b1 100644
--- a/app/Console/Commands/Schedule/ProcessRunnableCommand.php
+++ b/app/Console/Commands/Schedule/ProcessRunnableCommand.php
@@ -1,62 +1,37 @@
.
- *
- * This software is licensed under the terms of the MIT license.
- * https://opensource.org/licenses/MIT
- */
namespace Pterodactyl\Console\Commands\Schedule;
-use Cake\Chronos\Chronos;
+use Throwable;
+use Exception;
use Illuminate\Console\Command;
-use Illuminate\Support\Collection;
+use Pterodactyl\Models\Schedule;
+use Illuminate\Support\Facades\Log;
use Pterodactyl\Services\Schedules\ProcessScheduleService;
-use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
class ProcessRunnableCommand extends Command
{
/**
* @var string
*/
- protected $description = 'Process schedules in the database and determine which are ready to run.';
-
- /**
- * @var \Pterodactyl\Services\Schedules\ProcessScheduleService
- */
- protected $processScheduleService;
-
- /**
- * @var \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface
- */
- protected $repository;
+ protected $signature = 'p:schedule:process';
/**
* @var string
*/
- protected $signature = 'p:schedule:process';
-
- /**
- * ProcessRunnableCommand constructor.
- *
- * @param \Pterodactyl\Services\Schedules\ProcessScheduleService $processScheduleService
- * @param \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface $repository
- */
- public function __construct(ProcessScheduleService $processScheduleService, ScheduleRepositoryInterface $repository)
- {
- parent::__construct();
-
- $this->processScheduleService = $processScheduleService;
- $this->repository = $repository;
- }
+ protected $description = 'Process schedules in the database and determine which are ready to run.';
/**
* Handle command execution.
*/
public function handle()
{
- $schedules = $this->repository->getSchedulesToProcess(Chronos::now()->toAtomString());
+ $schedules = Schedule::query()->with('tasks')
+ ->where('is_active', true)
+ ->where('is_processing', false)
+ ->whereRaw('next_run_at <= NOW()')
+ ->get();
+
if ($schedules->count() < 1) {
$this->line('There are no scheduled tasks for servers that need to be run.');
@@ -64,23 +39,41 @@ class ProcessRunnableCommand extends Command
}
$bar = $this->output->createProgressBar(count($schedules));
- $schedules->each(function ($schedule) use ($bar) {
- if ($schedule->tasks instanceof Collection && count($schedule->tasks) > 0) {
- $this->processScheduleService->handle($schedule);
-
- if ($this->input->isInteractive()) {
- $bar->clear();
- $this->line(trans('command/messages.schedule.output_line', [
- 'schedule' => $schedule->name,
- 'hash' => $schedule->hashid,
- ]));
- }
- }
-
+ foreach ($schedules as $schedule) {
+ $bar->clear();
+ $this->processSchedule($schedule);
$bar->advance();
$bar->display();
- });
+ }
$this->line('');
}
+
+ /**
+ * Processes a given schedule and logs and errors encountered the console output. This should
+ * never throw an exception out, otherwise you'll end up killing the entire run group causing
+ * any other schedules to not process correctly.
+ *
+ * @param \Pterodactyl\Models\Schedule $schedule
+ * @see https://github.com/pterodactyl/panel/issues/2609
+ */
+ protected function processSchedule(Schedule $schedule)
+ {
+ if ($schedule->tasks->isEmpty()) {
+ return;
+ }
+
+ try {
+ $this->getLaravel()->make(ProcessScheduleService::class)->handle($schedule);
+
+ $this->line(trans('command/messages.schedule.output_line', [
+ 'schedule' => $schedule->name,
+ 'hash' => $schedule->hashid,
+ ]));
+ } catch (Throwable | Exception $exception) {
+ Log::error($exception, ['schedule_id' => $schedule->id]);
+
+ $this->error("An error was encountered while processing Schedule #{$schedule->id}: " . $exception->getMessage());
+ }
+ }
}
diff --git a/app/Console/Commands/User/DeleteUserCommand.php b/app/Console/Commands/User/DeleteUserCommand.php
index f458b51dc..64885dca1 100644
--- a/app/Console/Commands/User/DeleteUserCommand.php
+++ b/app/Console/Commands/User/DeleteUserCommand.php
@@ -58,8 +58,9 @@ class DeleteUserCommand extends Command
Assert::notEmpty($search, 'Search term should be an email address, got: %s.');
$results = User::query()
- ->where('email', 'LIKE', "$search%")
- ->where('username', 'LIKE', "$search%")
+ ->where('id', 'LIKE', "$search%")
+ ->orWhere('username', 'LIKE', "$search%")
+ ->orWhere('email', 'LIKE', "$search%")
->get();
if (count($results) < 1) {
diff --git a/app/Contracts/Repository/ScheduleRepositoryInterface.php b/app/Contracts/Repository/ScheduleRepositoryInterface.php
index 4f340601c..b6e73a2de 100644
--- a/app/Contracts/Repository/ScheduleRepositoryInterface.php
+++ b/app/Contracts/Repository/ScheduleRepositoryInterface.php
@@ -15,16 +15,6 @@ interface ScheduleRepositoryInterface extends RepositoryInterface
*/
public function findServerSchedules(int $server): Collection;
- /**
- * Load the tasks relationship onto the Schedule module if they are not
- * already present.
- *
- * @param \Pterodactyl\Models\Schedule $schedule
- * @param bool $refresh
- * @return \Pterodactyl\Models\Schedule
- */
- public function loadTasks(Schedule $schedule, bool $refresh = false): Schedule;
-
/**
* Return a schedule model with all of the associated tasks as a relationship.
*
@@ -34,12 +24,4 @@ interface ScheduleRepositoryInterface extends RepositoryInterface
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getScheduleWithTasks(int $schedule): Schedule;
-
- /**
- * Return all of the schedules that should be processed.
- *
- * @param string $timestamp
- * @return \Illuminate\Support\Collection
- */
- public function getSchedulesToProcess(string $timestamp): Collection;
}
diff --git a/app/Contracts/Repository/ServerRepositoryInterface.php b/app/Contracts/Repository/ServerRepositoryInterface.php
index d70584b50..d7e3dfc5d 100644
--- a/app/Contracts/Repository/ServerRepositoryInterface.php
+++ b/app/Contracts/Repository/ServerRepositoryInterface.php
@@ -139,16 +139,4 @@ interface ServerRepositoryInterface extends RepositoryInterface
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function loadAllServersForNode(int $node, int $limit): LengthAwarePaginator;
-
- /**
- * Returns every server that exists for a given node.
- *
- * This is different from {@see loadAllServersForNode} because
- * it does not paginate the response.
- *
- * @param int $node
- *
- * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
- */
- public function loadEveryServerForNode(int $node);
}
diff --git a/app/Helpers/Time.php b/app/Helpers/Time.php
new file mode 100644
index 000000000..248ff55f0
--- /dev/null
+++ b/app/Helpers/Time.php
@@ -0,0 +1,25 @@
+getTimezone()->getOffset(CarbonImmutable::now('UTC')) / 3600);
+
+ return sprintf('%s%s:00', $offset > 0 ? '+' : '-', str_pad(abs($offset), 2, '0', STR_PAD_LEFT));
+ }
+}
diff --git a/app/Helpers/Utilities.php b/app/Helpers/Utilities.php
index d900425d9..d6b4e752f 100644
--- a/app/Helpers/Utilities.php
+++ b/app/Helpers/Utilities.php
@@ -52,7 +52,12 @@ class Utilities
)->getNextRunDate());
}
- public static function checked($name, $default)
+ /**
+ * @param string $name
+ * @param mixed $default
+ * @return string
+ */
+ public static function checked(string $name, $default)
{
$errors = session('errors');
diff --git a/app/Http/Controllers/Admin/MountController.php b/app/Http/Controllers/Admin/MountController.php
index 3f40e555c..79c729976 100644
--- a/app/Http/Controllers/Admin/MountController.php
+++ b/app/Http/Controllers/Admin/MountController.php
@@ -3,6 +3,7 @@
namespace Pterodactyl\Http\Controllers\Admin;
use Ramsey\Uuid\Uuid;
+use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Pterodactyl\Models\Nest;
use Pterodactyl\Models\Mount;
@@ -101,7 +102,6 @@ class MountController extends Controller
*/
public function create(MountFormRequest $request)
{
- /** @var \Pterodactyl\Models\Mount $mount */
$model = (new Mount())->fill($request->validated());
$model->forceFill(['uuid' => Uuid::uuid4()->toString()]);
diff --git a/app/Http/Controllers/Admin/Servers/ServerController.php b/app/Http/Controllers/Admin/Servers/ServerController.php
index a0b73f552..c8e54b1c3 100644
--- a/app/Http/Controllers/Admin/Servers/ServerController.php
+++ b/app/Http/Controllers/Admin/Servers/ServerController.php
@@ -6,7 +6,9 @@ use Illuminate\Http\Request;
use Pterodactyl\Models\Server;
use Spatie\QueryBuilder\QueryBuilder;
use Illuminate\Contracts\View\Factory;
+use Spatie\QueryBuilder\AllowedFilter;
use Pterodactyl\Http\Controllers\Controller;
+use Pterodactyl\Models\Filters\AdminServerFilter;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
class ServerController extends Controller
@@ -45,8 +47,10 @@ class ServerController extends Controller
public function index(Request $request)
{
$servers = QueryBuilder::for(Server::query()->with('node', 'user', 'allocation'))
- ->allowedFilters(['uuid', 'name', 'image'])
- ->allowedSorts(['id', 'uuid'])
+ ->allowedFilters([
+ AllowedFilter::exact('owner_id'),
+ AllowedFilter::custom('*', new AdminServerFilter),
+ ])
->paginate(config()->get('pterodactyl.paginate.admin.servers'));
return $this->view->make('admin.servers.index', ['servers' => $servers]);
diff --git a/app/Http/Controllers/Api/Client/ClientController.php b/app/Http/Controllers/Api/Client/ClientController.php
index 5eec40b51..243868b5e 100644
--- a/app/Http/Controllers/Api/Client/ClientController.php
+++ b/app/Http/Controllers/Api/Client/ClientController.php
@@ -5,6 +5,8 @@ namespace Pterodactyl\Http\Controllers\Api\Client;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\Permission;
use Spatie\QueryBuilder\QueryBuilder;
+use Spatie\QueryBuilder\AllowedFilter;
+use Pterodactyl\Models\Filters\MultiFieldServerFilter;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Transformers\Api\Client\ServerTransformer;
use Pterodactyl\Http\Requests\Api\Client\GetServersRequest;
@@ -43,21 +45,32 @@ class ClientController extends ClientApiController
// Start the query builder and ensure we eager load any requested relationships from the request.
$builder = QueryBuilder::for(
Server::query()->with($this->getIncludesForTransformer($transformer, ['node']))
- )->allowedFilters('uuid', 'name', 'external_id');
+ )->allowedFilters([
+ 'uuid',
+ 'name',
+ 'external_id',
+ AllowedFilter::custom('*', new MultiFieldServerFilter),
+ ]);
+ $type = $request->input('type');
// 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);
+ // server. If ?type=admin-all is passed all servers on the system will be returned to the user, rather
+ // than only servers they can see because they are an admin.
+ if (in_array($type, ['admin', 'admin-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.
+ if (! $user->root_admin) {
+ $builder->whereRaw('1 = 2');
+ } else {
+ $builder = $type === 'admin-all'
+ ? $builder
+ : $builder->whereNotIn('servers.id', $user->accessibleServers()->pluck('id')->all());
+ }
+ } else if ($type === 'owner') {
+ $builder = $builder->where('servers.owner_id', $user->id);
} else {
- $builder = $builder->whereIn('id', $user->accessibleServers()->pluck('id')->all());
+ $builder = $builder->whereIn('servers.id', $user->accessibleServers()->pluck('id')->all());
}
$servers = $builder->paginate(min($request->query('per_page', 50), 100))->appends($request->query());
diff --git a/app/Http/Controllers/Api/Client/Servers/ScheduleController.php b/app/Http/Controllers/Api/Client/Servers/ScheduleController.php
index d35b597ed..a9310abd6 100644
--- a/app/Http/Controllers/Api/Client/Servers/ScheduleController.php
+++ b/app/Http/Controllers/Api/Client/Servers/ScheduleController.php
@@ -10,15 +10,19 @@ use Pterodactyl\Models\Server;
use Pterodactyl\Models\Schedule;
use Illuminate\Http\JsonResponse;
use Pterodactyl\Helpers\Utilities;
+use Pterodactyl\Jobs\Schedule\RunTaskJob;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Repositories\Eloquent\ScheduleRepository;
+use Pterodactyl\Services\Schedules\ProcessScheduleService;
use Pterodactyl\Transformers\Api\Client\ScheduleTransformer;
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\Schedules\ViewScheduleRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\StoreScheduleRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\DeleteScheduleRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\UpdateScheduleRequest;
+use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\TriggerScheduleRequest;
class ScheduleController extends ClientApiController
{
@@ -27,16 +31,23 @@ class ScheduleController extends ClientApiController
*/
private $repository;
+ /**
+ * @var \Pterodactyl\Services\Schedules\ProcessScheduleService
+ */
+ private $service;
+
/**
* ScheduleController constructor.
*
* @param \Pterodactyl\Repositories\Eloquent\ScheduleRepository $repository
+ * @param \Pterodactyl\Services\Schedules\ProcessScheduleService $service
*/
- public function __construct(ScheduleRepository $repository)
+ public function __construct(ScheduleRepository $repository, ProcessScheduleService $service)
{
parent::__construct();
$this->repository = $repository;
+ $this->service = $service;
}
/**
@@ -147,6 +158,30 @@ class ScheduleController extends ClientApiController
->toArray();
}
+ /**
+ * Executes a given schedule immediately rather than waiting on it's normally scheduled time
+ * to pass. This does not care about the schedule state.
+ *
+ * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\TriggerScheduleRequest $request
+ * @param \Pterodactyl\Models\Server $server
+ * @param \Pterodactyl\Models\Schedule $schedule
+ * @return \Illuminate\Http\JsonResponse
+ *
+ * @throws \Throwable
+ */
+ public function execute(TriggerScheduleRequest $request, Server $server, Schedule $schedule)
+ {
+ if (!$schedule->is_active) {
+ throw new BadRequestHttpException(
+ 'Cannot trigger schedule exection for a schedule that is not currently active.'
+ );
+ }
+
+ $this->service->handle($schedule, true);
+
+ return new JsonResponse([], JsonResponse::HTTP_ACCEPTED);
+ }
+
/**
* Deletes a schedule and it's associated tasks.
*
diff --git a/app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php b/app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php
index 0d613b6b0..c6f8ee339 100644
--- a/app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php
+++ b/app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php
@@ -56,7 +56,8 @@ class ScheduleTaskController extends ClientApiController
);
}
- $lastTask = $schedule->tasks->last();
+ /** @var \Pterodactyl\Models\Task|null $lastTask */
+ $lastTask = $schedule->tasks()->orderByDesc('sequence_id')->first();
/** @var \Pterodactyl\Models\Task $task */
$task = $this->repository->create([
@@ -102,13 +103,16 @@ class ScheduleTaskController extends ClientApiController
}
/**
- * Determines if a user can delete the task for a given server.
+ * Delete a given task for a schedule. If there are subsequent tasks stored in the database
+ * for this schedule their sequence IDs are decremented properly.
*
* @param \Pterodactyl\Http\Requests\Api\Client\ClientApiRequest $request
* @param \Pterodactyl\Models\Server $server
* @param \Pterodactyl\Models\Schedule $schedule
* @param \Pterodactyl\Models\Task $task
* @return \Illuminate\Http\JsonResponse
+ *
+ * @throws \Exception
*/
public function delete(ClientApiRequest $request, Server $server, Schedule $schedule, Task $task)
{
@@ -120,8 +124,12 @@ class ScheduleTaskController extends ClientApiController
throw new HttpForbiddenException('You do not have permission to perform this action.');
}
- $this->repository->delete($task->id);
+ $schedule->tasks()->where('sequence_id', '>', $task->sequence_id)->update([
+ 'sequence_id' => $schedule->tasks()->getConnection()->raw('(sequence_id - 1)'),
+ ]);
- return JsonResponse::create(null, Response::HTTP_NO_CONTENT);
+ $task->delete();
+
+ return new JsonResponse(null, Response::HTTP_NO_CONTENT);
}
}
diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php b/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php
index 2e4aa8ab1..d18c0921f 100644
--- a/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php
+++ b/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php
@@ -3,11 +3,14 @@
namespace Pterodactyl\Http\Controllers\Api\Remote\Servers;
use Illuminate\Http\Request;
+use Pterodactyl\Models\Server;
use Illuminate\Http\JsonResponse;
+use Illuminate\Support\Facades\DB;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Services\Eggs\EggConfigurationService;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
+use Pterodactyl\Http\Resources\Wings\ServerConfigurationCollection;
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
class ServerDetailsController extends Controller
@@ -27,11 +30,6 @@ class ServerDetailsController extends Controller
*/
private $configurationStructureService;
- /**
- * @var \Pterodactyl\Repositories\Eloquent\NodeRepository
- */
- private $nodeRepository;
-
/**
* ServerConfigurationController constructor.
*
@@ -49,7 +47,6 @@ class ServerDetailsController extends Controller
$this->eggConfigurationService = $eggConfigurationService;
$this->repository = $repository;
$this->configurationStructureService = $configurationStructureService;
- $this->nodeRepository = $nodeRepository;
}
/**
@@ -66,7 +63,7 @@ class ServerDetailsController extends Controller
{
$server = $this->repository->getByUuid($uuid);
- return JsonResponse::create([
+ return new JsonResponse([
'settings' => $this->configurationStructureService->handle($server),
'process_configuration' => $this->eggConfigurationService->handle($server),
]);
@@ -76,25 +73,19 @@ class ServerDetailsController extends Controller
* Lists all servers with their configurations that are assigned to the requesting node.
*
* @param \Illuminate\Http\Request $request
- *
- * @return \Illuminate\Http\JsonResponse
- *
- * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
+ * @return \Pterodactyl\Http\Resources\Wings\ServerConfigurationCollection
*/
public function list(Request $request)
{
+ /** @var \Pterodactyl\Models\Node $node */
$node = $request->attributes->get('node');
- $servers = $this->repository->loadEveryServerForNode($node->id);
- $configurations = [];
+ // Avoid run-away N+1 SQL queries by pre-loading the relationships that are used
+ // within each of the services called below.
+ $servers = Server::query()->with('allocations', 'egg', 'mounts', 'variables', 'location')
+ ->where('node_id', $node->id)
+ ->paginate($request->input('per_page', 50));
- foreach ($servers as $server) {
- $configurations[$server->uuid] = [
- 'settings' => $this->configurationStructureService->handle($server),
- 'process_configuration' => $this->eggConfigurationService->handle($server),
- ];
- }
-
- return JsonResponse::create($configurations);
+ return new ServerConfigurationCollection($servers);
}
}
diff --git a/app/Http/Controllers/Auth/LoginCheckpointController.php b/app/Http/Controllers/Auth/LoginCheckpointController.php
index c44f18a81..70d83a323 100644
--- a/app/Http/Controllers/Auth/LoginCheckpointController.php
+++ b/app/Http/Controllers/Auth/LoginCheckpointController.php
@@ -2,11 +2,13 @@
namespace Pterodactyl\Http\Controllers\Auth;
+use Pterodactyl\Models\User;
use Illuminate\Auth\AuthManager;
use Illuminate\Http\JsonResponse;
use PragmaRX\Google2FA\Google2FA;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Contracts\Encryption\Encrypter;
+use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Http\Requests\Auth\LoginCheckpointRequest;
use Illuminate\Contracts\Cache\Repository as CacheRepository;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
@@ -80,29 +82,31 @@ class LoginCheckpointController extends AbstractLoginController
* @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException
* @throws \PragmaRX\Google2FA\Exceptions\InvalidCharactersException
* @throws \PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException
- * @throws \Pterodactyl\Exceptions\DisplayException
+ * @throws \Exception
+ * @throws \Illuminate\Validation\ValidationException
*/
public function __invoke(LoginCheckpointRequest $request): JsonResponse
{
- $token = $request->input('confirmation_token');
- $recoveryToken = $request->input('recovery_token');
-
- try {
- /** @var \Pterodactyl\Models\User $user */
- $user = $this->repository->find($this->cache->get($token, 0));
- } catch (RecordNotFoundException $exception) {
- return $this->sendFailedLoginResponse($request, null, 'The authentication token provided has expired, please refresh the page and try again.');
+ if ($this->hasTooManyLoginAttempts($request)) {
+ $this->sendLockoutResponse($request);
}
- // If we got a recovery token try to find one that matches for the user and then continue
- // through the process (and delete the token).
- if (! is_null($recoveryToken)) {
- foreach ($user->recoveryTokens as $token) {
- if (password_verify($recoveryToken, $token->token)) {
- $this->recoveryTokenRepository->delete($token->id);
+ $token = $request->input('confirmation_token');
+ try {
+ /** @var \Pterodactyl\Models\User $user */
+ $user = User::query()->findOrFail($this->cache->get($token, 0));
+ } catch (ModelNotFoundException $exception) {
+ $this->incrementLoginAttempts($request);
- return $this->sendLoginResponse($user, $request);
- }
+ return $this->sendFailedLoginResponse(
+ $request, null, 'The authentication token provided has expired, please refresh the page and try again.'
+ );
+ }
+
+ // Recovery tokens go through a slightly different pathway for usage.
+ if (! is_null($recoveryToken = $request->input('recovery_token'))) {
+ if ($this->isValidRecoveryToken($user, $recoveryToken)) {
+ return $this->sendLoginResponse($user, $request);
}
} else {
$decrypted = $this->encrypter->decrypt($user->totp_secret);
@@ -114,6 +118,31 @@ class LoginCheckpointController extends AbstractLoginController
}
}
+ $this->incrementLoginAttempts($request);
+
return $this->sendFailedLoginResponse($request, $user, ! empty($recoveryToken) ? 'The recovery token provided is not valid.' : null);
}
+
+ /**
+ * Determines if a given recovery token is valid for the user account. If we find a matching token
+ * it will be deleted from the database.
+ *
+ * @param \Pterodactyl\Models\User $user
+ * @param string $value
+ * @return bool
+ *
+ * @throws \Exception
+ */
+ protected function isValidRecoveryToken(User $user, string $value)
+ {
+ foreach ($user->recoveryTokens as $token) {
+ if (password_verify($value, $token->token)) {
+ $token->delete();
+
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/app/Http/Middleware/Api/Daemon/DaemonAuthenticate.php b/app/Http/Middleware/Api/Daemon/DaemonAuthenticate.php
index bc365e63c..d222f58ec 100644
--- a/app/Http/Middleware/Api/Daemon/DaemonAuthenticate.php
+++ b/app/Http/Middleware/Api/Daemon/DaemonAuthenticate.php
@@ -69,7 +69,7 @@ class DaemonAuthenticate
// Ensure that all of the correct parts are provided in the header.
if (count($parts) !== 2 || empty($parts[0]) || empty($parts[1])) {
throw new BadRequestHttpException(
- 'The Authorization headed provided was not in a valid format.'
+ 'The Authorization header provided was not in a valid format.'
);
}
diff --git a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php
index 15780d695..5e4f9c200 100644
--- a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php
+++ b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php
@@ -55,6 +55,7 @@ class StoreServerRequest extends ApplicationApiRequest
'feature_limits' => 'required|array',
'feature_limits.databases' => $rules['database_limit'],
'feature_limits.allocations' => $rules['allocation_limit'],
+ 'feature_limits.backups' => $rules['backup_limit'],
// Placeholders for rules added in withValidator() function.
'allocation.default' => '',
@@ -102,6 +103,7 @@ class StoreServerRequest extends ApplicationApiRequest
'start_on_completion' => array_get($data, 'start_on_completion', false),
'database_limit' => array_get($data, 'feature_limits.databases'),
'allocation_limit' => array_get($data, 'feature_limits.allocations'),
+ 'backup_limit' => array_get($data, 'feature_limits.backups'),
];
}
diff --git a/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php b/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php
index 3f0e1c8ca..a387634c1 100644
--- a/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php
+++ b/app/Http/Requests/Api/Application/Servers/UpdateServerBuildConfigurationRequest.php
@@ -47,6 +47,7 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
'feature_limits' => 'required|array',
'feature_limits.databases' => $rules['database_limit'],
'feature_limits.allocations' => $rules['allocation_limit'],
+ 'feature_limits.backups' => $rules['backup_limit'],
];
}
@@ -60,8 +61,9 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
$data = parent::validated();
$data['allocation_id'] = $data['allocation'];
- $data['database_limit'] = $data['feature_limits']['databases'];
- $data['allocation_limit'] = $data['feature_limits']['allocations'];
+ $data['database_limit'] = $data['feature_limits']['databases'] ?? null;
+ $data['allocation_limit'] = $data['feature_limits']['allocations'] ?? null;
+ $data['backup_limit'] = $data['feature_limits']['backups'] ?? null;
unset($data['allocation'], $data['feature_limits']);
// Adjust the limits field to match what is expected by the model.
@@ -90,6 +92,7 @@ class UpdateServerBuildConfigurationRequest extends ServerWriteRequest
'remove_allocations.*' => 'allocation to remove',
'feature_limits.databases' => 'Database Limit',
'feature_limits.allocations' => 'Allocation Limit',
+ 'feature_limits.backups' => 'Backup Limit',
];
}
diff --git a/app/Http/Requests/Api/Client/Servers/Schedules/TriggerScheduleRequest.php b/app/Http/Requests/Api/Client/Servers/Schedules/TriggerScheduleRequest.php
new file mode 100644
index 000000000..d89f5ed30
--- /dev/null
+++ b/app/Http/Requests/Api/Client/Servers/Schedules/TriggerScheduleRequest.php
@@ -0,0 +1,25 @@
+make(EggConfigurationService::class);
+ $configuration = Container::getInstance()->make(ServerConfigurationStructureService::class);
+
+ return $this->collection->map(function (Server $server) use ($configuration, $egg) {
+ return [
+ 'uuid' => $server->uuid,
+ 'settings' => $configuration->handle($server),
+ 'process_configuration' => $egg->handle($server),
+ ];
+ })->toArray();
+ }
+}
diff --git a/app/Jobs/Schedule/RunTaskJob.php b/app/Jobs/Schedule/RunTaskJob.php
index bab1d61db..8784a37cb 100644
--- a/app/Jobs/Schedule/RunTaskJob.php
+++ b/app/Jobs/Schedule/RunTaskJob.php
@@ -7,11 +7,12 @@ use Pterodactyl\Jobs\Job;
use Carbon\CarbonImmutable;
use Pterodactyl\Models\Task;
use InvalidArgumentException;
+use Pterodactyl\Models\Schedule;
+use Illuminate\Support\Facades\Log;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\DispatchesJobs;
-use Pterodactyl\Repositories\Eloquent\TaskRepository;
use Pterodactyl\Services\Backups\InitiateBackupService;
use Pterodactyl\Repositories\Wings\DaemonPowerRepository;
use Pterodactyl\Repositories\Wings\DaemonCommandRepository;
@@ -42,15 +43,13 @@ class RunTaskJob extends Job implements ShouldQueue
* @param \Pterodactyl\Repositories\Wings\DaemonCommandRepository $commandRepository
* @param \Pterodactyl\Services\Backups\InitiateBackupService $backupService
* @param \Pterodactyl\Repositories\Wings\DaemonPowerRepository $powerRepository
- * @param \Pterodactyl\Repositories\Eloquent\TaskRepository $taskRepository
*
* @throws \Throwable
*/
public function handle(
DaemonCommandRepository $commandRepository,
InitiateBackupService $backupService,
- DaemonPowerRepository $powerRepository,
- TaskRepository $taskRepository
+ DaemonPowerRepository $powerRepository
) {
// Do not process a task that is not set to active.
if (! $this->task->schedule->is_active) {
diff --git a/app/Models/Filters/AdminServerFilter.php b/app/Models/Filters/AdminServerFilter.php
new file mode 100644
index 000000000..d523e48e0
--- /dev/null
+++ b/app/Models/Filters/AdminServerFilter.php
@@ -0,0 +1,40 @@
+getQuery()->from !== 'servers') {
+ throw new BadMethodCallException(
+ 'Cannot use the AdminServerFilter against a non-server model.'
+ );
+ }
+ $query
+ ->select('servers.*')
+ ->leftJoin('users', 'users.id', '=', 'servers.owner_id')
+ ->where(function (Builder $builder) use ($value) {
+ $builder->where('servers.uuid', $value)
+ ->orWhere('servers.uuid', 'LIKE', "$value%")
+ ->orWhere('servers.uuidShort', $value)
+ ->orWhere('servers.external_id', $value)
+ ->orWhereRaw('LOWER(users.username) LIKE ?', ["%$value%"])
+ ->orWhereRaw('LOWER(users.email) LIKE ?', ["$value%"])
+ ->orWhereRaw('LOWER(servers.name) LIKE ?', ["%$value%"]);
+ })
+ ->groupBy('servers.id');
+ }
+}
diff --git a/app/Models/Filters/MultiFieldServerFilter.php b/app/Models/Filters/MultiFieldServerFilter.php
new file mode 100644
index 000000000..21c45b779
--- /dev/null
+++ b/app/Models/Filters/MultiFieldServerFilter.php
@@ -0,0 +1,74 @@
+getQuery()->from !== 'servers') {
+ throw new BadMethodCallException(
+ 'Cannot use the MultiFieldServerFilter against a non-server model.'
+ );
+ }
+
+ if (preg_match(self::IPV4_REGEX, $value) || preg_match('/^:\d{1,5}$/', $value)) {
+ $query
+ // Only select the server values, otherwise you'll end up merging the allocation and
+ // server objects together, resulting in incorrect behavior and returned values.
+ ->select('servers.*')
+ ->join('allocations', 'allocations.server_id', '=', 'servers.id')
+ ->where(function (Builder $builder) use ($value) {
+ $parts = explode(':', $value);
+
+ $builder->when(
+ !Str::startsWith($value, ':'),
+ // 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.
+ function (Builder $builder) use ($parts) {
+ $builder->orWhere('allocations.ip', $parts[0]);
+ if (!is_null($parts[1] ?? null)) {
+ $builder->where('allocations.port', 'LIKE', "{$parts[1]}%");
+ }
+ },
+ // Otherwise, just try to search for that specific port in the allocations.
+ function (Builder $builder) use ($value) {
+ $builder->orWhere('allocations.port', 'LIKE', substr($value, 1) . '%');
+ }
+ );
+ })
+ ->groupBy('servers.id');
+
+ return;
+ }
+
+ $query
+ ->where(function (Builder $builder) use ($value) {
+ $builder->where('servers.uuid', $value)
+ ->orWhere('servers.uuid', 'LIKE', "$value%")
+ ->orWhere('servers.uuidShort', $value)
+ ->orWhere('servers.external_id', $value)
+ ->orWhereRaw('LOWER(servers.name) LIKE ?', ["%$value%"]);
+ });
+ }
+}
diff --git a/app/Models/Mount.php b/app/Models/Mount.php
index b69c0c78d..ee9879b19 100644
--- a/app/Models/Mount.php
+++ b/app/Models/Mount.php
@@ -2,6 +2,8 @@
namespace Pterodactyl\Models;
+use Illuminate\Validation\Rules\NotIn;
+
/**
* @property int $id
* @property string $uuid
@@ -63,6 +65,20 @@ class Mount extends Model
'user_mountable' => 'sometimes|boolean',
];
+ /**
+ * Implement language verification by overriding Eloquence's gather
+ * rules function.
+ */
+ public static function getRules()
+ {
+ $rules = parent::getRules();
+
+ $rules['source'][] = new NotIn(Mount::$invalidSourcePaths);
+ $rules['target'][] = new NotIn(Mount::$invalidTargetPaths);
+
+ return $rules;
+ }
+
/**
* Disable timestamps on this model.
*
@@ -70,6 +86,26 @@ class Mount extends Model
*/
public $timestamps = false;
+ /**
+ * Blacklisted source paths
+ *
+ * @var string[]
+ */
+ public static $invalidSourcePaths = [
+ '/etc/pterodactyl',
+ '/var/lib/pterodactyl/volumes',
+ '/srv/daemon-data',
+ ];
+
+ /**
+ * Blacklisted target paths
+ *
+ * @var string[]
+ */
+ public static $invalidTargetPaths = [
+ '/home/container',
+ ];
+
/**
* Returns all eggs that have this mount assigned.
*
diff --git a/app/Models/Schedule.php b/app/Models/Schedule.php
index d737edd2c..de0475639 100644
--- a/app/Models/Schedule.php
+++ b/app/Models/Schedule.php
@@ -2,6 +2,8 @@
namespace Pterodactyl\Models;
+use Cron\CronExpression;
+use Carbon\CarbonImmutable;
use Illuminate\Container\Container;
use Pterodactyl\Contracts\Extensions\HashidsInterface;
@@ -114,6 +116,20 @@ class Schedule extends Model
'next_run_at' => 'nullable|date',
];
+ /**
+ * Returns the schedule's execution crontab entry as a string.
+ *
+ * @return \Carbon\CarbonImmutable
+ */
+ public function getNextRunDate()
+ {
+ $formatted = sprintf('%s %s %s * %s', $this->cron_minute, $this->cron_hour, $this->cron_day_of_month, $this->cron_day_of_week);
+
+ return CarbonImmutable::createFromTimestamp(
+ CronExpression::factory($formatted)->getNextRunDate()->getTimestamp()
+ );
+ }
+
/**
* Return a hashid encoded string to represent the ID of the schedule.
*
diff --git a/app/Models/Server.php b/app/Models/Server.php
index aa4a39f06..c8b8615fe 100644
--- a/app/Models/Server.php
+++ b/app/Models/Server.php
@@ -83,6 +83,13 @@ class Server extends Model
'oom_disabled' => true,
];
+ /**
+ * The default relationships to load for all server models.
+ *
+ * @var string[]
+ */
+ protected $with = ['allocation'];
+
/**
* The attributes that should be mutated to dates.
*
@@ -122,7 +129,7 @@ class Server extends Model
'installed' => 'in:0,1,2',
'database_limit' => 'present|nullable|integer|min:0',
'allocation_limit' => 'sometimes|nullable|integer|min:0',
- 'backup_limit' => 'present|integer|min:0',
+ 'backup_limit' => 'present|nullable|integer|min:0',
];
/**
diff --git a/app/Repositories/Eloquent/ScheduleRepository.php b/app/Repositories/Eloquent/ScheduleRepository.php
index 389d06720..cb1b2cbf0 100644
--- a/app/Repositories/Eloquent/ScheduleRepository.php
+++ b/app/Repositories/Eloquent/ScheduleRepository.php
@@ -31,23 +31,6 @@ class ScheduleRepository extends EloquentRepository implements ScheduleRepositor
return $this->getBuilder()->withCount('tasks')->where('server_id', '=', $server)->get($this->getColumns());
}
- /**
- * Load the tasks relationship onto the Schedule module if they are not
- * already present.
- *
- * @param \Pterodactyl\Models\Schedule $schedule
- * @param bool $refresh
- * @return \Pterodactyl\Models\Schedule
- */
- public function loadTasks(Schedule $schedule, bool $refresh = false): Schedule
- {
- if (! $schedule->relationLoaded('tasks') || $refresh) {
- $schedule->load('tasks');
- }
-
- return $schedule;
- }
-
/**
* Return a schedule model with all of the associated tasks as a relationship.
*
@@ -64,19 +47,4 @@ class ScheduleRepository extends EloquentRepository implements ScheduleRepositor
throw new RecordNotFoundException;
}
}
-
- /**
- * Return all of the schedules that should be processed.
- *
- * @param string $timestamp
- * @return \Illuminate\Support\Collection
- */
- public function getSchedulesToProcess(string $timestamp): Collection
- {
- return $this->getBuilder()->with('tasks')
- ->where('is_active', true)
- ->where('is_processing', false)
- ->where('next_run_at', '<=', $timestamp)
- ->get($this->getColumns());
- }
}
diff --git a/app/Repositories/Eloquent/ServerRepository.php b/app/Repositories/Eloquent/ServerRepository.php
index 5e884a661..fdfd82fc2 100644
--- a/app/Repositories/Eloquent/ServerRepository.php
+++ b/app/Repositories/Eloquent/ServerRepository.php
@@ -270,22 +270,4 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
->where('node_id', '=', $node)
->paginate($limit);
}
-
- /**
- * Returns every server that exists for a given node.
- *
- * This is different from {@see loadAllServersForNode} because
- * it does not paginate the response.
- *
- * @param int $node
- *
- * @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
- */
- public function loadEveryServerForNode(int $node)
- {
- return $this->getBuilder()
- ->with('nest')
- ->where('node_id', '=', $node)
- ->get();
- }
}
diff --git a/app/Services/Deployment/FindViableNodesService.php b/app/Services/Deployment/FindViableNodesService.php
index d89c73f5e..8c3d7c757 100644
--- a/app/Services/Deployment/FindViableNodesService.php
+++ b/app/Services/Deployment/FindViableNodesService.php
@@ -4,7 +4,6 @@ namespace Pterodactyl\Services\Deployment;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\Node;
-use Illuminate\Support\LazyCollection;
use Pterodactyl\Exceptions\Service\Deployment\NoViableNodeException;
class FindViableNodesService
@@ -32,7 +31,7 @@ class FindViableNodesService
*/
public function setLocations(array $locations): self
{
- Assert::allInteger($locations, 'An array of location IDs should be provided when calling setLocations.');
+ Assert::allIntegerish($locations, 'An array of location IDs should be provided when calling setLocations.');
$this->locations = $locations;
@@ -97,8 +96,8 @@ class FindViableNodesService
}
$results = $query->groupBy('nodes.id')
- ->havingRaw('(IFNULL(SUM(servers.memory), 0) + ?) <= (nodes.memory * (1 + (nodes.memory_overallocate / 100)))', [ $this->memory ])
- ->havingRaw('(IFNULL(SUM(servers.disk), 0) + ?) <= (nodes.disk * (1 + (nodes.disk_overallocate / 100)))', [ $this->disk ])
+ ->havingRaw('(IFNULL(SUM(servers.memory), 0) + ?) <= (nodes.memory * (1 + (nodes.memory_overallocate / 100)))', [$this->memory])
+ ->havingRaw('(IFNULL(SUM(servers.disk), 0) + ?) <= (nodes.disk * (1 + (nodes.disk_overallocate / 100)))', [$this->disk])
->get()
->toBase();
diff --git a/app/Services/Schedules/ProcessScheduleService.php b/app/Services/Schedules/ProcessScheduleService.php
index 3fa3604a4..86775430b 100644
--- a/app/Services/Schedules/ProcessScheduleService.php
+++ b/app/Services/Schedules/ProcessScheduleService.php
@@ -2,12 +2,12 @@
namespace Pterodactyl\Services\Schedules;
-use Cron\CronExpression;
+use Exception;
use Pterodactyl\Models\Schedule;
use Illuminate\Contracts\Bus\Dispatcher;
use Pterodactyl\Jobs\Schedule\RunTaskJob;
-use Pterodactyl\Contracts\Repository\TaskRepositoryInterface;
-use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
+use Illuminate\Database\ConnectionInterface;
+use Pterodactyl\Exceptions\DisplayException;
class ProcessScheduleService
{
@@ -17,63 +17,66 @@ class ProcessScheduleService
private $dispatcher;
/**
- * @var \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface
+ * @var \Illuminate\Database\ConnectionInterface
*/
- private $scheduleRepository;
-
- /**
- * @var \Pterodactyl\Contracts\Repository\TaskRepositoryInterface
- */
- private $taskRepository;
+ private $connection;
/**
* ProcessScheduleService constructor.
*
+ * @param \Illuminate\Database\ConnectionInterface $connection
* @param \Illuminate\Contracts\Bus\Dispatcher $dispatcher
- * @param \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface $scheduleRepository
- * @param \Pterodactyl\Contracts\Repository\TaskRepositoryInterface $taskRepository
*/
- public function __construct(
- Dispatcher $dispatcher,
- ScheduleRepositoryInterface $scheduleRepository,
- TaskRepositoryInterface $taskRepository
- ) {
+ public function __construct(ConnectionInterface $connection, Dispatcher $dispatcher)
+ {
$this->dispatcher = $dispatcher;
- $this->scheduleRepository = $scheduleRepository;
- $this->taskRepository = $taskRepository;
+ $this->connection = $connection;
}
/**
* Process a schedule and push the first task onto the queue worker.
*
* @param \Pterodactyl\Models\Schedule $schedule
+ * @param bool $now
*
- * @throws \Pterodactyl\Exceptions\Model\DataValidationException
- * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
+ * @throws \Throwable
*/
- public function handle(Schedule $schedule)
+ public function handle(Schedule $schedule, bool $now = false)
{
- $this->scheduleRepository->loadTasks($schedule);
-
/** @var \Pterodactyl\Models\Task $task */
- $task = $schedule->getRelation('tasks')->where('sequence_id', 1)->first();
+ $task = $schedule->tasks()->orderBy('sequence_id', 'asc')->first();
- $formattedCron = sprintf('%s %s %s * %s',
- $schedule->cron_minute,
- $schedule->cron_hour,
- $schedule->cron_day_of_month,
- $schedule->cron_day_of_week
- );
+ if (is_null($task)) {
+ throw new DisplayException(
+ 'Cannot process schedule for task execution: no tasks are registered.'
+ );
+ }
- $this->scheduleRepository->update($schedule->id, [
- 'is_processing' => true,
- 'next_run_at' => CronExpression::factory($formattedCron)->getNextRunDate(),
- ]);
+ $this->connection->transaction(function () use ($schedule, $task) {
+ $schedule->forceFill([
+ 'is_processing' => true,
+ 'next_run_at' => $schedule->getNextRunDate(),
+ ])->saveOrFail();
- $this->taskRepository->update($task->id, ['is_queued' => true]);
+ $task->update(['is_queued' => true]);
+ });
- $this->dispatcher->dispatch(
- (new RunTaskJob($task))->delay($task->time_offset)
- );
+ $job = new RunTaskJob($task);
+
+ if (! $now) {
+ $this->dispatcher->dispatch($job->delay($task->time_offset));
+ } else {
+ // When using dispatchNow the RunTaskJob::failed() function is not called automatically
+ // so we need to manually trigger it and then continue with the exception throw.
+ //
+ // @see https://github.com/pterodactyl/panel/issues/2550
+ try {
+ $this->dispatcher->dispatchNow($job);
+ } catch (Exception $exception) {
+ $job->failed($exception);
+
+ throw $exception;
+ }
+ }
}
}
diff --git a/app/Services/Servers/BuildModificationService.php b/app/Services/Servers/BuildModificationService.php
index 86ff5bb69..43c863831 100644
--- a/app/Services/Servers/BuildModificationService.php
+++ b/app/Services/Servers/BuildModificationService.php
@@ -4,22 +4,14 @@ namespace Pterodactyl\Services\Servers;
use Illuminate\Support\Arr;
use Pterodactyl\Models\Server;
-use GuzzleHttp\Exception\RequestException;
+use Pterodactyl\Models\Allocation;
use Illuminate\Database\ConnectionInterface;
use Pterodactyl\Exceptions\DisplayException;
+use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
-use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
-use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
-use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
-use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
class BuildModificationService
{
- /**
- * @var \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface
- */
- private $allocationRepository;
-
/**
* @var \Illuminate\Database\ConnectionInterface
*/
@@ -30,11 +22,6 @@ class BuildModificationService
*/
private $daemonServerRepository;
- /**
- * @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
- */
- private $repository;
-
/**
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
*/
@@ -43,23 +30,17 @@ class BuildModificationService
/**
* BuildModificationService constructor.
*
- * @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $allocationRepository
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $structureService
* @param \Illuminate\Database\ConnectionInterface $connection
* @param \Pterodactyl\Repositories\Wings\DaemonServerRepository $daemonServerRepository
- * @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
*/
public function __construct(
- AllocationRepositoryInterface $allocationRepository,
ServerConfigurationStructureService $structureService,
ConnectionInterface $connection,
- DaemonServerRepository $daemonServerRepository,
- ServerRepositoryInterface $repository
+ DaemonServerRepository $daemonServerRepository
) {
- $this->allocationRepository = $allocationRepository;
$this->daemonServerRepository = $daemonServerRepository;
$this->connection = $connection;
- $this->repository = $repository;
$this->structureService = $structureService;
}
@@ -70,9 +51,8 @@ class BuildModificationService
* @param array $data
* @return \Pterodactyl\Models\Server
*
+ * @throws \Throwable
* @throws \Pterodactyl\Exceptions\DisplayException
- * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
- * @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function handle(Server $server, array $data)
{
@@ -82,48 +62,35 @@ class BuildModificationService
if (isset($data['allocation_id']) && $data['allocation_id'] != $server->allocation_id) {
try {
- $this->allocationRepository->findFirstWhere([
- ['id', '=', $data['allocation_id']],
- ['server_id', '=', $server->id],
- ]);
- } catch (RecordNotFoundException $ex) {
- throw new DisplayException(trans('admin/server.exceptions.default_allocation_not_found'));
+ Allocation::query()->where('id', $data['allocation_id'])->where('server_id', $server->id)->firstOrFail();
+ } catch (ModelNotFoundException $ex) {
+ throw new DisplayException('The requested default allocation is not currently assigned to this server.');
}
}
- /* @var \Pterodactyl\Models\Server $server */
- $server = $this->repository->withFreshModel()->update($server->id, [
- 'oom_disabled' => array_get($data, 'oom_disabled'),
- 'memory' => array_get($data, 'memory'),
- 'swap' => array_get($data, 'swap'),
- 'io' => array_get($data, 'io'),
- 'cpu' => array_get($data, 'cpu'),
- 'threads' => array_get($data, 'threads'),
- 'disk' => array_get($data, 'disk'),
- 'allocation_id' => array_get($data, 'allocation_id'),
- 'database_limit' => array_get($data, 'database_limit', 0),
- 'allocation_limit' => array_get($data, 'allocation_limit', 0),
- 'backup_limit' => array_get($data, 'backup_limit', 0),
- ]);
+ // If any of these values are passed through in the data array go ahead and set
+ // them correctly on the server model.
+ $merge = Arr::only($data, ['oom_disabled', 'memory', 'swap', 'io', 'cpu', 'threads', 'disk', 'allocation_id']);
+
+ $server->forceFill(array_merge($merge, [
+ 'database_limit' => Arr::get($data, 'database_limit', 0) ?? null,
+ 'allocation_limit' => Arr::get($data, 'allocation_limit', 0) ?? null,
+ 'backup_limit' => Arr::get($data, 'backup_limit', 0) ?? 0,
+ ]))->saveOrFail();
+
+ $server = $server->fresh();
$updateData = $this->structureService->handle($server);
- try {
- $this->daemonServerRepository
- ->setServer($server)
- ->update(Arr::only($updateData, ['build']));
+ $this->daemonServerRepository->setServer($server)->update($updateData['build'] ?? []);
- $this->connection->commit();
- } catch (RequestException $exception) {
- throw new DaemonConnectionException($exception);
- }
+ $this->connection->commit();
return $server;
}
/**
- * Process the allocations being assigned in the data and ensure they
- * are available for a server.
+ * Process the allocations being assigned in the data and ensure they are available for a server.
*
* @param \Pterodactyl\Models\Server $server
* @param array $data
@@ -132,55 +99,53 @@ class BuildModificationService
*/
private function processAllocations(Server $server, array &$data)
{
- $firstAllocationId = null;
-
- if (! array_key_exists('add_allocations', $data) && ! array_key_exists('remove_allocations', $data)) {
+ if (empty($data['add_allocations']) && empty($data['remove_allocations'])) {
return;
}
- // Handle the addition of allocations to this server.
- if (array_key_exists('add_allocations', $data) && ! empty($data['add_allocations'])) {
- $unassigned = $this->allocationRepository->getUnassignedAllocationIds($server->node_id);
+ // Handle the addition of allocations to this server. Only assign allocations that are not currently
+ // assigned to a different server, and only allocations on the same node as the server.
+ if (! empty($data['add_allocations'])) {
+ $query = Allocation::query()
+ ->where('node_id', $server->node_id)
+ ->whereIn('id', $data['add_allocations'])
+ ->whereNull('server_id');
- $updateIds = [];
- foreach ($data['add_allocations'] as $allocation) {
- if (! in_array($allocation, $unassigned)) {
- continue;
- }
+ // Keep track of all the allocations we're just now adding so that we can use the first
+ // one to reset the default allocation to.
+ $freshlyAllocated = $query->pluck('id')->first();
- $firstAllocationId = $firstAllocationId ?? $allocation;
- $updateIds[] = $allocation;
- }
-
- if (! empty($updateIds)) {
- $this->allocationRepository->updateWhereIn('id', $updateIds, ['server_id' => $server->id]);
- }
+ $query->update(['server_id' => $server->id, 'notes' => null]);
}
- // Handle removal of allocations from this server.
- if (array_key_exists('remove_allocations', $data) && ! empty($data['remove_allocations'])) {
- $assigned = $server->allocations->pluck('id')->toArray();
-
- $updateIds = [];
+ if (! empty($data['remove_allocations'])) {
foreach ($data['remove_allocations'] as $allocation) {
- if (! in_array($allocation, $assigned)) {
- continue;
- }
-
- if ($allocation == $data['allocation_id']) {
- if (is_null($firstAllocationId)) {
- throw new DisplayException(trans('admin/server.exceptions.no_new_default_allocation'));
+ // If we are attempting to remove the default allocation for the server, see if we can reassign
+ // to the first provided value in add_allocations. If there is no new first allocation then we
+ // will throw an exception back.
+ if ($allocation === ($data['allocation_id'] ?? $server->allocation_id)) {
+ if (empty($freshlyAllocated)) {
+ throw new DisplayException(
+ 'You are attempting to delete the default allocation for this server but there is no fallback allocation to use.'
+ );
}
- $data['allocation_id'] = $firstAllocationId;
+ // Update the default allocation to be the first allocation that we are creating.
+ $data['allocation_id'] = $freshlyAllocated;
}
-
- $updateIds[] = $allocation;
}
- if (! empty($updateIds)) {
- $this->allocationRepository->updateWhereIn('id', $updateIds, ['server_id' => null]);
- }
+ // Remove any of the allocations we got that are currently assigned to this server on
+ // this node. Also set the notes to null, otherwise when re-allocated to a new server those
+ // notes will be carried over.
+ Allocation::query()->where('node_id', $server->node_id)
+ ->where('server_id', $server->id)
+ // Only remove the allocations that we didn't also attempt to add to the server...
+ ->whereIn('id', array_diff($data['remove_allocations'], $data['add_allocations'] ?? []))
+ ->update([
+ 'notes' => null,
+ 'server_id' => null,
+ ]);
}
}
}
diff --git a/app/Services/Servers/ServerConfigurationStructureService.php b/app/Services/Servers/ServerConfigurationStructureService.php
index fb4412170..dc2a4bfb2 100644
--- a/app/Services/Servers/ServerConfigurationStructureService.php
+++ b/app/Services/Servers/ServerConfigurationStructureService.php
@@ -7,8 +7,6 @@ use Pterodactyl\Models\Server;
class ServerConfigurationStructureService
{
- const REQUIRED_RELATIONS = ['allocation', 'allocations', 'egg'];
-
/**
* @var \Pterodactyl\Services\Servers\EnvironmentService
*/
@@ -31,13 +29,11 @@ class ServerConfigurationStructureService
* daemon, if you modify the structure eggs will break unexpectedly.
*
* @param \Pterodactyl\Models\Server $server
- * @param bool $legacy
+ * @param bool $legacy deprecated
* @return array
*/
public function handle(Server $server, bool $legacy = false): array
{
- $server->loadMissing(self::REQUIRED_RELATIONS);
-
return $legacy ?
$this->returnLegacyFormat($server)
: $this->returnCurrentFormat($server);
@@ -93,6 +89,7 @@ class ServerConfigurationStructureService
*
* @param \Pterodactyl\Models\Server $server
* @return array
+ * @deprecated
*/
protected function returnLegacyFormat(Server $server)
{
diff --git a/config/backups.php b/config/backups.php
index fde856215..ec9bd175e 100644
--- a/config/backups.php
+++ b/config/backups.php
@@ -33,6 +33,8 @@ return [
// backup for that server lives within that folder.
'prefix' => env('AWS_BACKUPS_BUCKET') ?? '',
+ 'endpoint' => env('AWS_ENDPOINT'),
+ 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'use_accelerate_endpoint' => env('AWS_BACKUPS_USE_ACCELERATE', false),
],
],
diff --git a/config/database.php b/config/database.php
index 32fca7581..5a4e8bc77 100644
--- a/config/database.php
+++ b/config/database.php
@@ -1,5 +1,7 @@
'utf8mb4_unicode_ci',
'prefix' => env('DB_PREFIX', ''),
'strict' => env('DB_STRICT_MODE', false),
+ 'timezone' => env('DB_TIMEZONE', Time::getMySQLTimezoneOffset(env('APP_TIMEZONE')))
],
/*
@@ -65,6 +68,7 @@ return [
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => false,
+ 'timezone' => env('DB_TIMEZONE', Time::getMySQLTimezoneOffset(env('APP_TIMEZONE')))
],
],
diff --git a/config/filesystems.php b/config/filesystems.php
index 809742bed..bffcc6514 100644
--- a/config/filesystems.php
+++ b/config/filesystems.php
@@ -58,6 +58,8 @@ return [
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
+ 'endpoint' => env('AWS_ENDPOINT'),
+ 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
],
],
];
diff --git a/config/session.php b/config/session.php
index 2007acb2e..8605db59b 100644
--- a/config/session.php
+++ b/config/session.php
@@ -188,5 +188,5 @@ return [
|
*/
- 'same_site' => null,
+ 'same_site' => env('SESSION_SAMESITE_COOKIE', 'lax'),
];
diff --git a/database/migrations/2020_10_26_194904_remove_nullable_from_schedule_name_field.php b/database/migrations/2020_10_26_194904_remove_nullable_from_schedule_name_field.php
new file mode 100644
index 000000000..fc1f01baa
--- /dev/null
+++ b/database/migrations/2020_10_26_194904_remove_nullable_from_schedule_name_field.php
@@ -0,0 +1,35 @@
+string('name')->nullable(false)->change();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('schedules', function (Blueprint $table) {
+ $table->string('name')->nullable()->change();
+ });
+ }
+}
diff --git a/database/seeds/eggs/minecraft/egg-bungeecord.json b/database/seeds/eggs/minecraft/egg-bungeecord.json
index b0c07e506..3f28d96b2 100644
--- a/database/seeds/eggs/minecraft/egg-bungeecord.json
+++ b/database/seeds/eggs/minecraft/egg-bungeecord.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2020-04-12T16:00:51-07:00",
+ "exported_at": "2020-10-19T23:22:26+00:00",
"name": "Bungeecord",
"author": "support@pterodactyl.io",
"description": "For a long time, Minecraft server owners have had a dream that encompasses a free, easy, and reliable way to connect multiple Minecraft servers together. BungeeCord is the answer to said dream. Whether you are a small server wishing to string multiple game-modes together, or the owner of the ShotBow Network, BungeeCord is the ideal solution for you. With the help of BungeeCord, you will be able to unlock your community's full potential.",
@@ -17,9 +17,9 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/ash\n# Bungeecord Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl\n\ncd \/mnt\/server\n\nif [ -z \"${BUNGEE_VERSION}\" ] || [ \"${BUNGEE_VERSION}\" == \"latest\" ]; then\n BUNGEE_VERSION=\"lastStableBuild\"\nfi\n\ncurl -o ${SERVER_JARFILE} https:\/\/ci.md-5.net\/job\/BungeeCord\/${BUNGEE_VERSION}\/artifact\/bootstrap\/target\/BungeeCord.jar",
- "container": "alpine:3.9",
- "entrypoint": "ash"
+ "script": "#!\/bin\/bash\r\n# Bungeecord Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napt update\r\napt install -y curl\r\n\r\ncd \/mnt\/server\r\n\r\nif [ -z \"${BUNGEE_VERSION}\" ] || [ \"${BUNGEE_VERSION}\" == \"latest\" ]; then\r\n BUNGEE_VERSION=\"lastStableBuild\"\r\nfi\r\n\r\ncurl -o ${SERVER_JARFILE} https:\/\/ci.md-5.net\/job\/BungeeCord\/${BUNGEE_VERSION}\/artifact\/bootstrap\/target\/BungeeCord.jar",
+ "container": "debian:buster-slim",
+ "entrypoint": "bash"
}
},
"variables": [
@@ -28,8 +28,8 @@
"description": "The version of Bungeecord to download and use.",
"env_variable": "BUNGEE_VERSION",
"default_value": "latest",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|alpha_num|between:1,6"
},
{
@@ -37,8 +37,8 @@
"description": "The name of the Jarfile to use when running Bungeecord.",
"env_variable": "SERVER_JARFILE",
"default_value": "bungeecord.jar",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|regex:\/^([\\w\\d._-]+)(\\.jar)$\/"
}
]
diff --git a/database/seeds/eggs/minecraft/egg-forge-minecraft.json b/database/seeds/eggs/minecraft/egg-forge-minecraft.json
index 96b707e51..6f404d1c7 100644
--- a/database/seeds/eggs/minecraft/egg-forge-minecraft.json
+++ b/database/seeds/eggs/minecraft/egg-forge-minecraft.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2020-05-24T12:15:13-04:00",
+ "exported_at": "2020-10-19T23:22:28+00:00",
"name": "Forge Minecraft",
"author": "support@pterodactyl.io",
"description": "Minecraft Forge Server. Minecraft Forge is a modding API (Application Programming Interface), which makes it easier to create mods, and also make sure mods are compatible with each other.",
@@ -17,7 +17,7 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/bash\r\n# Forge Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napt update\r\napt install -y curl jq\r\n\r\n#Go into main direction\r\nif [ ! -d \/mnt\/server ]; then\r\n mkdir \/mnt\/server\r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\nif [ ! -z ${FORGE_VERSION} ]; then\r\n DOWNLOAD_LINK=https:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/${FORGE_VERSION}\/forge-${FORGE_VERSION}\r\nelse\r\n JSON_DATA=$(curl -sSL https:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/promotions_slim.json)\r\n\r\n if [ \"${MC_VERSION}\" == \"latest\" ] || [ \"${MC_VERSION}\" == \"\" ] ; then\r\n echo -e \"getting latest recommended version of forge.\"\r\n MC_VERSION=$(echo -e ${JSON_DATA} | jq -r '.promos | del(.\"latest-1.7.10\") | del(.\"1.7.10-latest-1.7.10\") | to_entries[] | .key | select(contains(\"recommended\")) | split(\"-\")[0]' | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | tail -1)\r\n \tBUILD_TYPE=recommended\r\n fi\r\n\r\n if [ \"${BUILD_TYPE}\" != \"recommended\" ] && [ \"${BUILD_TYPE}\" != \"latest\" ]; then\r\n BUILD_TYPE=recommended\r\n fi\r\n\r\n echo -e \"minecraft version: ${MC_VERSION}\"\r\n echo -e \"build type: ${BUILD_TYPE}\"\r\n\r\n ## some variables for getting versions and things\r\n FILE_SITE=$(echo -e ${JSON_DATA} | jq -r '.homepage' | sed \"s\/http:\/https:\/g\")\r\n VERSION_KEY=$(echo -e ${JSON_DATA} | jq -r --arg MC_VERSION \"${MC_VERSION}\" --arg BUILD_TYPE \"${BUILD_TYPE}\" '.promos | del(.\"latest-1.7.10\") | del(.\"1.7.10-latest-1.7.10\") | to_entries[] | .key | select(contains($MC_VERSION)) | select(contains($BUILD_TYPE))')\r\n\r\n ## locating the forge version\r\n if [ \"${VERSION_KEY}\" == \"\" ] && [ \"${BUILD_TYPE}\" == \"recommended\" ]; then\r\n echo -e \"dropping back to latest from recommended due to there not being a recommended version of forge for the mc version requested.\"\r\n VERSION_KEY=$(echo -e ${JSON_DATA} | jq -r --arg MC_VERSION \"${MC_VERSION}\" '.promos | del(.\"latest-1.7.10\") | del(.\"1.7.10-latest-1.7.10\") | to_entries[] | .key | select(contains($MC_VERSION)) | select(contains(\"recommended\"))')\r\n fi\r\n\r\n ## Error if the mc version set wasn't valid.\r\n if [ \"${VERSION_KEY}\" == \"\" ] || [ \"${VERSION_KEY}\" == \"null\" ]; then\r\n \techo -e \"The install failed because there is no valid version of forge for the version on minecraft selected.\"\r\n \texit 1\r\n fi\r\n\r\n FORGE_VERSION=$(echo -e ${JSON_DATA} | jq -r --arg VERSION_KEY \"$VERSION_KEY\" '.promos | .[$VERSION_KEY]')\r\n\r\n if [ \"${MC_VERSION}\" == \"1.7.10\" ] || [ \"${MC_VERSION}\" == \"1.8.9\" ]; then\r\n DOWNLOAD_LINK=${FILE_SITE}${MC_VERSION}-${FORGE_VERSION}-${MC_VERSION}\/forge-${MC_VERSION}-${FORGE_VERSION}-${MC_VERSION}\r\n FORGE_JAR=forge-${MC_VERSION}-${FORGE_VERSION}-${MC_VERSION}.jar\r\n if [ \"${MC_VERSION}\" == \"1.7.10\" ]; then\r\n FORGE_JAR=forge-${MC_VERSION}-${FORGE_VERSION}-${MC_VERSION}-universal.jar\r\n fi\r\n else\r\n DOWNLOAD_LINK=${FILE_SITE}${MC_VERSION}-${FORGE_VERSION}\/forge-${MC_VERSION}-${FORGE_VERSION}\r\n FORGE_JAR=forge-${MC_VERSION}-${FORGE_VERSION}.jar\r\n fi\r\nfi\r\n\r\n\r\n#Adding .jar when not eding by SERVER_JARFILE\r\nif [[ ! $SERVER_JARFILE = *\\.jar ]]; then\r\n SERVER_JARFILE=\"$SERVER_JARFILE.jar\"\r\nfi\r\n\r\n#Downloading jars\r\necho -e \"Downloading forge version ${FORGE_VERSION}\"\r\nif [ ! -z \"${DOWNLOAD_LINK}\" ]; then \r\n if curl --output \/dev\/null --silent --head --fail ${DOWNLOAD_LINK}-installer.jar; then\r\n echo -e \"installer jar download link is valid.\"\r\n else\r\n echo -e \"link is invalid closing out\"\r\n exit 2\r\n fi\r\n\r\n echo -e \"no download link closing out\"\r\n exit 3\r\nfi\r\n\r\ncurl -s -o installer.jar -sS ${DOWNLOAD_LINK}-installer.jar\r\n\r\n#Checking if downloaded jars exist\r\nif [ ! -f .\/installer.jar ]; then\r\n echo \"!!! Error by downloading forge version ${FORGE_VERSION} !!!\"\r\n exit\r\nfi\r\n\r\n#Installing server\r\necho -e \"Installing forge server.\\n\"\r\njava -jar installer.jar --installServer || { echo -e \"install failed\"; exit 4; }\r\n\r\nmv $FORGE_JAR $SERVER_JARFILE\r\n\r\n#Deleting installer.jar\r\necho -e \"Deleting installer.jar file.\\n\"\r\nrm -rf installer.jar",
+ "script": "#!\/bin\/bash\r\n# Forge Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napt update\r\napt install -y curl jq\r\n\r\n#Go into main direction\r\nif [ ! -d \/mnt\/server ]; then\r\n mkdir \/mnt\/server\r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\nif [ ! -z ${FORGE_VERSION} ]; then\r\n DOWNLOAD_LINK=https:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/${FORGE_VERSION}\/forge-${FORGE_VERSION}\r\nelse\r\n JSON_DATA=$(curl -sSL https:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/promotions_slim.json)\r\n\r\n if [ \"${MC_VERSION}\" == \"latest\" ] || [ \"${MC_VERSION}\" == \"\" ] ; then\r\n echo -e \"getting latest recommended version of forge.\"\r\n MC_VERSION=$(echo -e ${JSON_DATA} | jq -r '.promos | del(.\"latest-1.7.10\") | del(.\"1.7.10-latest-1.7.10\") | to_entries[] | .key | select(contains(\"recommended\")) | split(\"-\")[0]' | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | tail -1)\r\n \tBUILD_TYPE=recommended\r\n fi\r\n\r\n if [ \"${BUILD_TYPE}\" != \"recommended\" ] && [ \"${BUILD_TYPE}\" != \"latest\" ]; then\r\n BUILD_TYPE=recommended\r\n fi\r\n\r\n echo -e \"minecraft version: ${MC_VERSION}\"\r\n echo -e \"build type: ${BUILD_TYPE}\"\r\n\r\n ## some variables for getting versions and things\r\n FILE_SITE=$(echo -e ${JSON_DATA} | jq -r '.homepage' | sed \"s\/http:\/https:\/g\")\r\n VERSION_KEY=$(echo -e ${JSON_DATA} | jq -r --arg MC_VERSION \"${MC_VERSION}\" --arg BUILD_TYPE \"${BUILD_TYPE}\" '.promos | del(.\"latest-1.7.10\") | del(.\"1.7.10-latest-1.7.10\") | to_entries[] | .key | select(contains($MC_VERSION)) | select(contains($BUILD_TYPE))')\r\n\r\n ## locating the forge version\r\n if [ \"${VERSION_KEY}\" == \"\" ] && [ \"${BUILD_TYPE}\" == \"recommended\" ]; then\r\n echo -e \"dropping back to latest from recommended due to there not being a recommended version of forge for the mc version requested.\"\r\n VERSION_KEY=$(echo -e ${JSON_DATA} | jq -r --arg MC_VERSION \"${MC_VERSION}\" '.promos | del(.\"latest-1.7.10\") | del(.\"1.7.10-latest-1.7.10\") | to_entries[] | .key | select(contains($MC_VERSION)) | select(contains(\"recommended\"))')\r\n fi\r\n\r\n ## Error if the mc version set wasn't valid.\r\n if [ \"${VERSION_KEY}\" == \"\" ] || [ \"${VERSION_KEY}\" == \"null\" ]; then\r\n \techo -e \"The install failed because there is no valid version of forge for the version on minecraft selected.\"\r\n \texit 1\r\n fi\r\n\r\n FORGE_VERSION=$(echo -e ${JSON_DATA} | jq -r --arg VERSION_KEY \"$VERSION_KEY\" '.promos | .[$VERSION_KEY]')\r\n\r\n if [ \"${MC_VERSION}\" == \"1.7.10\" ] || [ \"${MC_VERSION}\" == \"1.8.9\" ]; then\r\n DOWNLOAD_LINK=${FILE_SITE}${MC_VERSION}-${FORGE_VERSION}-${MC_VERSION}\/forge-${MC_VERSION}-${FORGE_VERSION}-${MC_VERSION}\r\n FORGE_JAR=forge-${MC_VERSION}-${FORGE_VERSION}-${MC_VERSION}.jar\r\n if [ \"${MC_VERSION}\" == \"1.7.10\" ]; then\r\n FORGE_JAR=forge-${MC_VERSION}-${FORGE_VERSION}-${MC_VERSION}-universal.jar\r\n fi\r\n else\r\n DOWNLOAD_LINK=${FILE_SITE}${MC_VERSION}-${FORGE_VERSION}\/forge-${MC_VERSION}-${FORGE_VERSION}\r\n FORGE_JAR=forge-${MC_VERSION}-${FORGE_VERSION}.jar\r\n fi\r\nfi\r\n\r\n\r\n#Adding .jar when not eding by SERVER_JARFILE\r\nif [[ ! $SERVER_JARFILE = *\\.jar ]]; then\r\n SERVER_JARFILE=\"$SERVER_JARFILE.jar\"\r\nfi\r\n\r\n#Downloading jars\r\necho -e \"Downloading forge version ${FORGE_VERSION}\"\r\necho -e \"Download link is ${DOWNLOAD_LINK}\"\r\nif [ ! -z \"${DOWNLOAD_LINK}\" ]; then \r\n if curl --output \/dev\/null --silent --head --fail ${DOWNLOAD_LINK}-installer.jar; then\r\n echo -e \"installer jar download link is valid.\"\r\n else\r\n echo -e \"link is invalid closing out\"\r\n exit 2\r\n fi\r\nelse\r\n echo -e \"no download link closing out\"\r\n exit 3\r\nfi\r\n\r\ncurl -s -o installer.jar -sS ${DOWNLOAD_LINK}-installer.jar\r\n\r\n#Checking if downloaded jars exist\r\nif [ ! -f .\/installer.jar ]; then\r\n echo \"!!! Error by downloading forge version ${FORGE_VERSION} !!!\"\r\n exit\r\nfi\r\n\r\n#Installing server\r\necho -e \"Installing forge server.\\n\"\r\njava -jar installer.jar --installServer || { echo -e \"install failed\"; exit 4; }\r\n\r\nmv $FORGE_JAR $SERVER_JARFILE\r\n\r\n#Deleting installer.jar\r\necho -e \"Deleting installer.jar file.\\n\"\r\nrm -rf installer.jar",
"container": "openjdk:8-jdk-slim",
"entrypoint": "bash"
}
@@ -28,8 +28,8 @@
"description": "The name of the Jarfile to use when running Forge Mod.",
"env_variable": "SERVER_JARFILE",
"default_value": "server.jar",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|regex:\/^([\\w\\d._-]+)(\\.jar)$\/"
},
{
@@ -37,8 +37,8 @@
"description": "The version of minecraft you want to install for.\r\n\r\nLeaving latest will install the latest recommended version.",
"env_variable": "MC_VERSION",
"default_value": "latest",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|max:9"
},
{
@@ -46,8 +46,8 @@
"description": "The type of server jar to download from forge.\r\n\r\nValid types are \"recommended\" and \"latest\".",
"env_variable": "BUILD_TYPE",
"default_value": "recommended",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|max:20"
},
{
@@ -55,8 +55,8 @@
"description": "Gets an exact version.\r\n\r\nEx. 1.15.2-31.2.4\r\n\r\nOverrides MC_VERSION and BUILD_TYPE. If it fails to download the server files it will fail to install.",
"env_variable": "FORGE_VERSION",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|max:20"
}
]
diff --git a/database/seeds/eggs/minecraft/egg-paper.json b/database/seeds/eggs/minecraft/egg-paper.json
index 60fde38e0..0cb09ffc3 100644
--- a/database/seeds/eggs/minecraft/egg-paper.json
+++ b/database/seeds/eggs/minecraft/egg-paper.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2019-08-01T04:49:37-04:00",
+ "exported_at": "2020-10-25T21:03:55+00:00",
"name": "Paper",
"author": "parker@pterodactyl.io",
"description": "High performance Spigot fork that aims to fix gameplay and mechanics inconsistencies.",
@@ -17,9 +17,9 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/ash\r\n# Paper Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napk add --no-cache --update curl jq\r\n\r\nif [ -n \"${DL_PATH}\" ]; then\r\n echo -e \"using supplied download url\"\r\n DOWNLOAD_URL=`eval echo $(echo ${DL_PATH} | sed -e 's\/{{\/${\/g' -e 's\/}}\/}\/g')`\r\nelse\r\n VER_EXISTS=`curl -s https:\/\/papermc.io\/api\/v1\/paper | jq -r --arg VERSION $MINECRAFT_VERSION '.versions[] | IN($VERSION)' | grep true`\r\n LATEST_PAPER_VERSION=`curl -s https:\/\/papermc.io\/api\/v1\/paper | jq -r '.versions' | jq -r '.[0]'`\r\n \r\n if [ \"${VER_EXISTS}\" == \"true\" ]; then\r\n echo -e \"Version is valid. Using version ${MINECRAFT_VERSION}\"\r\n else\r\n echo -e \"Using the latest paper version\"\r\n MINECRAFT_VERSION=${LATEST_PAPER_VERSION}\r\n fi\r\n \r\n BUILD_EXISTS=`curl -s https:\/\/papermc.io\/api\/v1\/paper\/${MINECRAFT_VERSION} | jq -r --arg BUILD ${BUILD_NUMBER} '.builds.all[] | IN($BUILD)' | grep true`\r\n LATEST_PAPER_BUILD=`curl -s https:\/\/papermc.io\/api\/v1\/paper\/${MINECRAFT_VERSION} | jq -r '.builds.latest'`\r\n \r\n if [ \"${BUILD_EXISTS}\" == \"true\" ] || [ ${BUILD_NUMBER} == \"latest\" ]; then\r\n echo -e \"Build is valid. Using version ${BUILD_NUMBER}\"\r\n else\r\n echo -e \"Using the latest paper build\"\r\n BUILD_NUMBER=${LATEST_PAPER_BUILD}\r\n fi\r\n \r\n echo \"Version being downloaded\"\r\n echo -e \"MC Version: ${MINECRAFT_VERSION}\"\r\n echo -e \"Build: ${BUILD_NUMBER}\"\r\n DOWNLOAD_URL=https:\/\/papermc.io\/api\/v1\/paper\/${MINECRAFT_VERSION}\/${BUILD_NUMBER}\/download \r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\necho -e \"running curl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\"\r\n\r\nif [ -f ${SERVER_JARFILE} ]; then\r\n mv ${SERVER_JARFILE} ${SERVER_JARFILE}.old\r\nfi\r\n\r\ncurl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\r\n\r\nif [ ! -f server.properties ]; then\r\n echo -e \"Downloading MC server.properties\"\r\n curl -o server.properties https:\/\/raw.githubusercontent.com\/parkervcp\/eggs\/master\/minecraft_java\/server.properties\r\nfi",
- "container": "alpine:3.9",
- "entrypoint": "ash"
+ "script": "#!\/bin\/bash\r\n# Paper Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napt update\r\napt install -y curl jq\r\n\r\nif [ -n \"${DL_PATH}\" ]; then\r\n echo -e \"using supplied download url\"\r\n DOWNLOAD_URL=`eval echo $(echo ${DL_PATH} | sed -e 's\/{{\/${\/g' -e 's\/}}\/}\/g')`\r\nelse\r\n VER_EXISTS=`curl -s https:\/\/papermc.io\/api\/v1\/paper | jq -r --arg VERSION $MINECRAFT_VERSION '.versions[] | contains($VERSION)' | grep true`\r\n LATEST_PAPER_VERSION=`curl -s https:\/\/papermc.io\/api\/v1\/paper | jq -r '.versions' | jq -r '.[0]'`\r\n \r\n if [ \"${VER_EXISTS}\" == \"true\" ]; then\r\n echo -e \"Version is valid. Using version ${MINECRAFT_VERSION}\"\r\n else\r\n echo -e \"Using the latest paper version\"\r\n MINECRAFT_VERSION=${LATEST_PAPER_VERSION}\r\n fi\r\n \r\n BUILD_EXISTS=`curl -s https:\/\/papermc.io\/api\/v1\/paper\/${MINECRAFT_VERSION} | jq -r --arg BUILD ${BUILD_NUMBER} '.builds.all[] | IN($BUILD)' | grep true`\r\n LATEST_PAPER_BUILD=`curl -s https:\/\/papermc.io\/api\/v1\/paper\/${MINECRAFT_VERSION} | jq -r '.builds.latest'`\r\n \r\n if [ \"${BUILD_EXISTS}\" == \"true\" ] || [ ${BUILD_NUMBER} == \"latest\" ]; then\r\n echo -e \"Build is valid. Using version ${BUILD_NUMBER}\"\r\n else\r\n echo -e \"Using the latest paper build\"\r\n BUILD_NUMBER=${LATEST_PAPER_BUILD}\r\n fi\r\n \r\n echo \"Version being downloaded\"\r\n echo -e \"MC Version: ${MINECRAFT_VERSION}\"\r\n echo -e \"Build: ${BUILD_NUMBER}\"\r\n DOWNLOAD_URL=https:\/\/papermc.io\/api\/v1\/paper\/${MINECRAFT_VERSION}\/${BUILD_NUMBER}\/download \r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\necho -e \"running curl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\"\r\n\r\nif [ -f ${SERVER_JARFILE} ]; then\r\n mv ${SERVER_JARFILE} ${SERVER_JARFILE}.old\r\nfi\r\n\r\ncurl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\r\n\r\nif [ ! -f server.properties ]; then\r\n echo -e \"Downloading MC server.properties\"\r\n curl -o server.properties https:\/\/raw.githubusercontent.com\/parkervcp\/eggs\/master\/minecraft\/java\/server.properties\r\nfi",
+ "container": "debian:buster-slim",
+ "entrypoint": "bash"
}
},
"variables": [
@@ -28,8 +28,8 @@
"description": "The version of minecraft to download. \r\n\r\nLeave at latest to always get the latest version. Invalid versions will default to latest.",
"env_variable": "MINECRAFT_VERSION",
"default_value": "latest",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "nullable|string|max:20"
},
{
@@ -37,8 +37,8 @@
"description": "The name of the server jarfile to run the server with.",
"env_variable": "SERVER_JARFILE",
"default_value": "server.jar",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|max:20"
},
{
@@ -46,8 +46,8 @@
"description": "A URL to use to download a server.jar rather than the ones in the install script. This is not user viewable.",
"env_variable": "DL_PATH",
"default_value": "",
- "user_viewable": 0,
- "user_editable": 0,
+ "user_viewable": false,
+ "user_editable": false,
"rules": "nullable|string"
},
{
@@ -55,8 +55,8 @@
"description": "The build number for the paper release.\r\n\r\nLeave at latest to always get the latest version. Invalid versions will default to latest.",
"env_variable": "BUILD_NUMBER",
"default_value": "latest",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|string|max:20"
}
]
diff --git a/database/seeds/eggs/minecraft/egg-sponge--sponge-vanilla.json b/database/seeds/eggs/minecraft/egg-sponge--sponge-vanilla.json
index 2bbfba23a..cf1a9396d 100644
--- a/database/seeds/eggs/minecraft/egg-sponge--sponge-vanilla.json
+++ b/database/seeds/eggs/minecraft/egg-sponge--sponge-vanilla.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2017-11-03T22:20:03-05:00",
+ "exported_at": "2020-10-19T23:26:54+00:00",
"name": "Sponge (SpongeVanilla)",
"author": "support@pterodactyl.io",
"description": "SpongeVanilla is the SpongeAPI implementation for Vanilla Minecraft.",
@@ -17,9 +17,9 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/ash\n# Sponge Installation Script\n#\n# Server Files: \/mnt\/server\n\napk update\napk add curl\n\ncd \/mnt\/server\n\ncurl -sSL \"https:\/\/repo.spongepowered.org\/maven\/org\/spongepowered\/spongevanilla\/${SPONGE_VERSION}\/spongevanilla-${SPONGE_VERSION}.jar\" -o ${SERVER_JARFILE}",
- "container": "alpine:3.9",
- "entrypoint": "ash"
+ "script": "#!\/bin\/bash\r\n# Sponge Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n\r\napt update\r\napt install -y curl\r\n\r\ncd \/mnt\/server\r\n\r\ncurl -sSL \"https:\/\/repo.spongepowered.org\/maven\/org\/spongepowered\/spongevanilla\/${SPONGE_VERSION}\/spongevanilla-${SPONGE_VERSION}.jar\" -o ${SERVER_JARFILE}",
+ "container": "debian:buster-slim",
+ "entrypoint": "bash"
}
},
"variables": [
@@ -28,8 +28,8 @@
"description": "The version of SpongeVanilla to download and use.",
"env_variable": "SPONGE_VERSION",
"default_value": "1.11.2-6.1.0-BETA-21",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|regex:\/^([a-zA-Z0-9.\\-_]+)$\/"
},
{
@@ -37,9 +37,9 @@
"description": "The name of the Jarfile to use when running SpongeVanilla.",
"env_variable": "SERVER_JARFILE",
"default_value": "server.jar",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|regex:\/^([\\w\\d._-]+)(\\.jar)$\/"
}
]
-}
+}
\ No newline at end of file
diff --git a/database/seeds/eggs/minecraft/egg-vanilla-minecraft.json b/database/seeds/eggs/minecraft/egg-vanilla-minecraft.json
index f613c8150..fadd91a4e 100644
--- a/database/seeds/eggs/minecraft/egg-vanilla-minecraft.json
+++ b/database/seeds/eggs/minecraft/egg-vanilla-minecraft.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2019-12-25T19:55:01-05:00",
+ "exported_at": "2020-10-23T23:04:17+00:00",
"name": "Vanilla Minecraft",
"author": "support@pterodactyl.io",
"description": "Minecraft is a game about placing blocks and going on adventures. Explore randomly generated worlds and build amazing things from the simplest of homes to the grandest of castles. Play in Creative Mode with unlimited resources or mine deep in Survival Mode, crafting weapons and armor to fend off dangerous mobs. Do all this alone or with friends.",
@@ -17,9 +17,9 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/ash\r\n# Vanilla MC Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napk add curl --no-cache --update jq\r\n\r\nmkdir -p \/mnt\/server\r\ncd \/mnt\/server\r\n\r\nLATEST_VERSION=`curl https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq -r '.latest.release'`\r\n\r\necho -e \"latest version is $LATEST_VERSION\"\r\n\r\nif [ -z \"$VANILLA_VERSION\" ] || [ \"$VANILLA_VERSION\" == \"latest\" ]; then\r\n MANIFEST_URL=$(curl -sSL https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq --arg VERSION $LATEST_VERSION -r '.versions | .[] | select(.id== $VERSION )|.url')\r\nelse\r\n MANIFEST_URL=$(curl -sSL https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq --arg VERSION $VANILLA_VERSION -r '.versions | .[] | select(.id== $VERSION )|.url')\r\nfi\r\n\r\nDOWNLOAD_URL=$(curl ${MANIFEST_URL} | jq .downloads.server | jq -r '. | .url')\r\n\r\necho -e \"running: curl -o ${SERVER_JARFILE} $DOWNLOAD_URL\"\r\ncurl -o ${SERVER_JARFILE} $DOWNLOAD_URL\r\n\r\necho -e \"Install Complete\"",
- "container": "alpine:3.10",
- "entrypoint": "ash"
+ "script": "#!\/bin\/bash\r\n# Vanilla MC Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napt update\r\napt install -y jq curl\r\n\r\nmkdir -p \/mnt\/server\r\ncd \/mnt\/server\r\n\r\nLATEST_VERSION=`curl https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq -r '.latest.release'`\r\n\r\necho -e \"latest version is $LATEST_VERSION\"\r\n\r\nif [ -z \"$VANILLA_VERSION\" ] || [ \"$VANILLA_VERSION\" == \"latest\" ]; then\r\n MANIFEST_URL=$(curl -sSL https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq --arg VERSION $LATEST_VERSION -r '.versions | .[] | select(.id== $VERSION )|.url')\r\nelse\r\n MANIFEST_URL=$(curl -sSL https:\/\/launchermeta.mojang.com\/mc\/game\/version_manifest.json | jq --arg VERSION $VANILLA_VERSION -r '.versions | .[] | select(.id== $VERSION )|.url')\r\nfi\r\n\r\nDOWNLOAD_URL=$(curl ${MANIFEST_URL} | jq .downloads.server | jq -r '. | .url')\r\n\r\necho -e \"running: curl -o ${SERVER_JARFILE} $DOWNLOAD_URL\"\r\ncurl -o ${SERVER_JARFILE} $DOWNLOAD_URL\r\n\r\necho -e \"Install Complete\"",
+ "container": "debian:buster-slim",
+ "entrypoint": "bash"
}
},
"variables": [
@@ -28,8 +28,8 @@
"description": "The name of the server jarfile to run the server with.",
"env_variable": "SERVER_JARFILE",
"default_value": "server.jar",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|regex:\/^([\\w\\d._-]+)(\\.jar)$\/"
},
{
@@ -37,8 +37,8 @@
"description": "The version of Minecraft Vanilla to install. Use \"latest\" to install the latest version.",
"env_variable": "VANILLA_VERSION",
"default_value": "latest",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|between:3,15"
}
]
diff --git a/database/seeds/eggs/rust/egg-rust.json b/database/seeds/eggs/rust/egg-rust.json
index 7d794cc89..d805da08f 100644
--- a/database/seeds/eggs/rust/egg-rust.json
+++ b/database/seeds/eggs/rust/egg-rust.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2018-01-21T16:58:36-06:00",
+ "exported_at": "2020-10-20T00:03:09+00:00",
"name": "Rust",
"author": "support@pterodactyl.io",
"description": "The only aim in Rust is to survive. To do this you will need to overcome struggles such as hunger, thirst and cold. Build a fire. Build a shelter. Kill animals for meat. Protect yourself from other players, and kill them for meat. Create alliances with other players and form a town. Do whatever it takes to survive.",
@@ -17,8 +17,8 @@
},
"scripts": {
"installation": {
- "script": "apt update\r\napt -y --no-install-recommends install curl unzip lib32gcc1 ca-certificates\r\ncd \/tmp\r\ncurl -sSL -o steamcmd.tar.gz http:\/\/media.steampowered.com\/installer\/steamcmd_linux.tar.gz\r\n\r\nmkdir -p \/mnt\/server\/steam\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steam\r\ncd \/mnt\/server\/steam\r\nchown -R root:root \/mnt\r\n\r\nexport HOME=\/mnt\/server\r\n.\/steamcmd.sh +login anonymous +force_install_dir \/mnt\/server +app_update 258550 +quit\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v \/mnt\/server\/steam\/linux32\/steamclient.so \/mnt\/server\/.steam\/sdk32\/steamclient.so",
- "container": "ubuntu:16.04",
+ "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'debian:buster-slim'\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\nSRCDS_APPID=258550\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n echo -e \"steam user is not set.\\n\"\r\n echo -e \"Using anonymous user.\\n\"\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nelse\r\n echo -e \"user set to ${STEAM_USER}\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} validate +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so",
+ "container": "debian:buster-slim",
"entrypoint": "bash"
}
},
@@ -28,8 +28,8 @@
"description": "The name of your server in the public server list.",
"env_variable": "HOSTNAME",
"default_value": "A Rust Server",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|max:40"
},
{
@@ -37,8 +37,8 @@
"description": "Set whether you want the server to use and auto update OxideMod or not. Valid options are \"1\" for true and \"0\" for false.",
"env_variable": "OXIDE",
"default_value": "0",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|boolean"
},
{
@@ -46,8 +46,8 @@
"description": "The world file for Rust to use.",
"env_variable": "LEVEL",
"default_value": "Procedural Map",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|max:20"
},
{
@@ -55,8 +55,8 @@
"description": "The description under your server title. Commonly used for rules & info. Use \\n for newlines.",
"env_variable": "DESCRIPTION",
"default_value": "Powered by Pterodactyl",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string"
},
{
@@ -64,8 +64,8 @@
"description": "The URL for your server. This is what comes up when clicking the \"Visit Website\" button.",
"env_variable": "SERVER_URL",
"default_value": "http:\/\/pterodactyl.io",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "nullable|url"
},
{
@@ -73,8 +73,8 @@
"description": "The world size for a procedural map.",
"env_variable": "WORLD_SIZE",
"default_value": "3000",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|integer"
},
{
@@ -82,8 +82,8 @@
"description": "The seed for a procedural map.",
"env_variable": "WORLD_SEED",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "nullable|string"
},
{
@@ -91,8 +91,8 @@
"description": "The maximum amount of players allowed in the server at once.",
"env_variable": "MAX_PLAYERS",
"default_value": "40",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|integer"
},
{
@@ -100,8 +100,8 @@
"description": "The header image for the top of your server listing.",
"env_variable": "SERVER_IMG",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "nullable|url"
},
{
@@ -109,8 +109,8 @@
"description": "Port for RCON connections.",
"env_variable": "RCON_PORT",
"default_value": "28016",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|integer"
},
{
@@ -118,17 +118,17 @@
"description": "RCON access password.",
"env_variable": "RCON_PASS",
"default_value": "CHANGEME",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|max:64"
},
{
"name": "Save Interval",
- "description": "Sets the server’s auto-save interval in seconds.",
+ "description": "Sets the server\u2019s auto-save interval in seconds.",
"env_variable": "SAVEINTERVAL",
"default_value": "60",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|integer"
},
{
@@ -136,9 +136,9 @@
"description": "Add additional startup parameters to the server.",
"env_variable": "ADDITIONAL_ARGS",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "nullable|string"
}
]
-}
+}
\ No newline at end of file
diff --git a/database/seeds/eggs/source-engine/egg-ark--survival-evolved.json b/database/seeds/eggs/source-engine/egg-ark--survival-evolved.json
index e86a89a9a..627a384a8 100644
--- a/database/seeds/eggs/source-engine/egg-ark--survival-evolved.json
+++ b/database/seeds/eggs/source-engine/egg-ark--survival-evolved.json
@@ -3,78 +3,87 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2018-10-29T20:51:32+01:00",
+ "exported_at": "2020-10-19T23:29:06+00:00",
"name": "Ark: Survival Evolved",
- "author": "support@pterodactyl.io",
+ "author": "dev@shepper.fr",
"description": "As a man or woman stranded, naked, freezing, and starving on the unforgiving shores of a mysterious island called ARK, use your skill and cunning to kill or tame and ride the plethora of leviathan dinosaurs and other primeval creatures roaming the land. Hunt, harvest resources, craft items, grow crops, research technologies, and build shelters to withstand the elements and store valuables, all while teaming up with (or preying upon) hundreds of other players to survive, dominate... and escape! \u2014 Gamepedia: ARK",
- "image": "quay.io\/pterodactyl\/core:source",
- "startup": "\"cd ShooterGame\/Binaries\/Linux && .\/ShooterGameServer {{SERVER_MAP}}?listen?SessionName='{{SESSION_NAME}}'?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}?RCONPort={{RCON_PORT}}?QueryPort={{QUERY_PORT}}?RCONEnabled={{ENABLE_RCON}} -server -log\"",
+ "image": "quay.io\/parkervcp\/pterodactyl-images:debian_source",
+ "startup": "rmv() { echo -e \"stoppping server\"; rcon -a 127.0.0.1:${RCON_PORT} -p ${ARK_ADMIN_PASSWORD} -c saveworld && rcon -a 127.0.0.1:${RCON_PORT} -p ${ARK_ADMIN_PASSWORD} -c DoExit; }; trap rmv 15; cd ShooterGame\/Binaries\/Linux && .\/ShooterGameServer {{SERVER_MAP}}?listen?SessionName=\"{{SESSION_NAME}}\"?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{SERVER_PORT}}?RCONPort={{RCON_PORT}}?QueryPort={{QUERY_PORT}}?RCONEnabled={{ENABLE_RCON}}$( [ \"$BATTLE_EYE\" == \"0\" ] || printf %s '?-NoBattlEye' ) -server -log & until echo \"waiting for rcon connection...\"; rcon -a 127.0.0.1:${RCON_PORT} -p ${ARK_ADMIN_PASSWORD}; do sleep 5; done",
"config": {
"files": "{}",
- "startup": "{\r\n \"done\": \"Setting breakpad minidump AppID = 346110\",\r\n \"userInteraction\": []\r\n}",
+ "startup": "{\r\n \"done\": \"Waiting commands for 127.0.0.1:\",\r\n \"userInteraction\": []\r\n}",
"logs": "{\r\n \"custom\": true,\r\n \"location\": \"logs\/latest.log\"\r\n}",
"stop": "^C"
},
"scripts": {
"installation": {
- "script": "#!\/bin\/bash\r\n# ARK: Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\ncd \/tmp\r\ncurl -sSL -o steamcmd.tar.gz http:\/\/media.steampowered.com\/installer\/steamcmd_linux.tar.gz\r\n\r\nmkdir -p \/mnt\/server\/steamcmd\r\nmkdir -p \/mnt\/server\/Engine\/Binaries\/ThirdParty\/SteamCMD\/Linux\r\n\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/Engine\/Binaries\/ThirdParty\/SteamCMD\/Linux\r\n\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\n\r\nexport HOME=\/mnt\/server\r\n.\/steamcmd.sh +login anonymous +force_install_dir \/mnt\/server +app_update 376030 +quit\r\n\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\ncd \/mnt\/server\/Engine\/Binaries\/ThirdParty\/SteamCMD\/Linux\r\n\r\nln -sf ..\/..\/..\/..\/..\/Steam\/steamapps steamapps\r\n\r\ncd \/mnt\/server",
- "container": "ubuntu:16.04",
+ "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'ubuntu:18.04'\r\napt -y update\r\napt -y --no-install-recommends --no-install-suggests install curl lib32gcc1 ca-certificates\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\n\r\nmkdir -p \/mnt\/server\/Engine\/Binaries\/ThirdParty\/SteamCMD\/Linux\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/Engine\/Binaries\/ThirdParty\/SteamCMD\/Linux\r\n\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so\r\n\r\n## create a symbolic link for loading mods\r\ncd \/mnt\/server\/Engine\/Binaries\/ThirdParty\/SteamCMD\/Linux\r\nln -sf ..\/..\/..\/..\/..\/Steam\/steamapps steamapps\r\ncd \/mnt\/server",
+ "container": "debian:buster-slim",
"entrypoint": "bash"
}
},
"variables": [
- {
- "name": "Server Name",
- "description": "ARK server name",
- "env_variable": "SESSION_NAME",
- "default_value": "ARK SERVER",
- "user_viewable": 1,
- "user_editable": 1,
- "rules": "required|string|max:128"
- },
{
"name": "Server Password",
"description": "If specified, players must provide this password to join the server.",
"env_variable": "ARK_PASSWORD",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "nullable|alpha_dash|between:1,100"
},
{
"name": "Admin Password",
"description": "If specified, players must provide this password (via the in-game console) to gain access to administrator commands on the server.",
"env_variable": "ARK_ADMIN_PASSWORD",
- "default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
- "rules": "nullable|alpha_dash|between:1,100"
+ "default_value": "PleaseChangeMe",
+ "user_viewable": true,
+ "user_editable": true,
+ "rules": "nullable|alpha_dash|between:1,100"
},
{
- "name": "Server Port",
- "description": "ARK server port used by client.",
- "env_variable": "PORT",
- "default_value": "7777",
- "user_viewable": 1,
- "user_editable": 1,
- "rules": "required|numeric"
+ "name": "Server Map",
+ "description": "Available Maps: TheIsland, TheCenter, Ragnarok, ScorchedEarth_P, Aberration_P, Extinction, Valguero_P, Genesis",
+ "env_variable": "SERVER_MAP",
+ "default_value": "TheIsland",
+ "user_viewable": true,
+ "user_editable": true,
+ "rules": "required|string|max:20"
+ },
+ {
+ "name": "App ID",
+ "description": "ARK steam app id for auto updates. Leave blank to avoid auto update.",
+ "env_variable": "SRCDS_APPID",
+ "default_value": "376030",
+ "user_viewable": true,
+ "user_editable": false,
+ "rules": "nullable|numeric"
+ },
+ {
+ "name": "Server Name",
+ "description": "ARK server name",
+ "env_variable": "SESSION_NAME",
+ "default_value": "A Pterodactyl Hosted ARK Server",
+ "user_viewable": true,
+ "user_editable": true,
+ "rules": "required|string|max:128"
},
{
"name": "Use Rcon",
- "description": "Enable or disable rcon system. (true or false)",
+ "description": "Enable or disable rcon system. (true or false)\r\n\r\nDefault True for the console to work.",
"env_variable": "ENABLE_RCON",
- "default_value": "false",
- "user_viewable": 1,
- "user_editable": 1,
- "rules": "required|string|max:5"
+ "default_value": "True",
+ "user_viewable": true,
+ "user_editable": false,
+ "rules": "required|string|in:True,False"
},
{
"name": "Rcon Port",
"description": "ARK rcon port used by rcon tools.",
"env_variable": "RCON_PORT",
"default_value": "27020",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|numeric"
},
{
@@ -82,36 +91,27 @@
"description": "ARK query port used by steam server browser and ark client server browser.",
"env_variable": "QUERY_PORT",
"default_value": "27015",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|numeric"
},
{
- "name": "Maximum Players",
- "description": "Specifies the maximum number of players that can play on the server simultaneously.",
- "env_variable": "SERVER_MAX_PLAYERS",
- "default_value": "20",
- "user_viewable": 1,
- "user_editable": 1,
- "rules": "required|numeric|digits_between:1,4"
+ "name": "Auto-update server",
+ "description": "This is to enable auto-updating for servers.\r\n\r\nDefault is 0. Set to 1 to update",
+ "env_variable": "AUTO_UPDATE",
+ "default_value": "0",
+ "user_viewable": true,
+ "user_editable": true,
+ "rules": "required|boolean"
},
{
- "name": "App ID",
- "description": "ARK steam app id for auto updates. Leave blank to avoid auto update.",
- "env_variable": "SRCDS_APPID",
- "default_value": "376030",
- "user_viewable": 1,
- "user_editable": 0,
- "rules": "nullable|numeric"
- },
- {
- "name": "Server Map",
- "description": "Available Maps: TheIsland, TheCenter, Ragnarok, ScorchedEarth_P, Aberration_P, Extinction",
- "env_variable": "SERVER_MAP",
- "default_value": "TheIsland",
- "user_viewable": 1,
- "user_editable": 1,
- "rules": "required|string|max:20"
+ "name": "Ballte Eye",
+ "description": "Enable BattleEye\r\n\r\n0 to disable\r\n1 to enable\r\n\r\ndefault=\"1\"",
+ "env_variable": "BATTLE_EYE",
+ "default_value": "1",
+ "user_viewable": true,
+ "user_editable": true,
+ "rules": "required|boolean"
}
]
-}
+}
\ No newline at end of file
diff --git a/database/seeds/eggs/source-engine/egg-counter--strike--global-offensive.json b/database/seeds/eggs/source-engine/egg-counter--strike--global-offensive.json
index 191aa99ed..b093aa793 100644
--- a/database/seeds/eggs/source-engine/egg-counter--strike--global-offensive.json
+++ b/database/seeds/eggs/source-engine/egg-counter--strike--global-offensive.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2019-12-08T10:52:19-05:00",
+ "exported_at": "2020-10-19T23:29:57+00:00",
"name": "Counter-Strike: Global Offensive",
"author": "support@pterodactyl.io",
"description": "Counter-Strike: Global Offensive is a multiplayer first-person shooter video game developed by Hidden Path Entertainment and Valve Corporation.",
@@ -28,8 +28,8 @@
"description": "The default map for the server.",
"env_variable": "SRCDS_MAP",
"default_value": "de_dust2",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|alpha_dash"
},
{
@@ -37,8 +37,8 @@
"description": "The Steam Account Token required for the server to be displayed publicly.",
"env_variable": "STEAM_ACC",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|alpha_num|size:32"
},
{
@@ -46,8 +46,8 @@
"description": "Required for game to update on server restart. Do not modify this.",
"env_variable": "SRCDS_APPID",
"default_value": "740",
- "user_viewable": 0,
- "user_editable": 0,
+ "user_viewable": false,
+ "user_editable": false,
"rules": "required|string|max:20"
}
]
diff --git a/database/seeds/eggs/source-engine/egg-custom-source-engine-game.json b/database/seeds/eggs/source-engine/egg-custom-source-engine-game.json
index aae3b3f35..fd6fe014c 100644
--- a/database/seeds/eggs/source-engine/egg-custom-source-engine-game.json
+++ b/database/seeds/eggs/source-engine/egg-custom-source-engine-game.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2019-12-08T10:54:26-05:00",
+ "exported_at": "2020-10-19T23:33:52+00:00",
"name": "Custom Source Engine Game",
"author": "support@pterodactyl.io",
"description": "This option allows modifying the startup arguments and other details to run a custom SRCDS based game on the panel.",
@@ -17,8 +17,8 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'ubuntu:18.04'\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so",
- "container": "ubuntu:18.04",
+ "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'debian:buster-slim'\r\n\r\n##\r\n#\r\n# Variables\r\n# STEAM_USER, STEAM_PASS, STEAM_AUTH - Steam user setup. If a user has 2fa enabled it will most likely fail due to timeout. Leave blank for anon install.\r\n# WINDOWS_INSTALL - if it's a windows server you want to install set to 1\r\n# SRCDS_APPID - steam app id ffound here - https:\/\/developer.valvesoftware.com\/wiki\/Dedicated_Servers_List\r\n# EXTRA_FLAGS - when a server has extra glas for things like beta installs or updates.\r\n#\r\n##\r\n\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n echo -e \"steam user is not set.\\n\"\r\n echo -e \"Using anonymous user.\\n\"\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nelse\r\n echo -e \"user set to ${STEAM_USER}\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} $( [[ \"${WINDOWS_INSTALL}\" == \"1\" ]] && printf %s '+@sSteamCmdForcePlatformType windows' ) +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} validate +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so",
+ "container": "debian:buster-slim",
"entrypoint": "bash"
}
},
@@ -28,8 +28,8 @@
"description": "The ID corresponding to the game to download and run using SRCDS.",
"env_variable": "SRCDS_APPID",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|numeric|digits_between:1,6"
},
{
@@ -37,8 +37,8 @@
"description": "The name corresponding to the game to download and run using SRCDS.",
"env_variable": "SRCDS_GAME",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|alpha_dash|between:1,100"
},
{
@@ -46,8 +46,8 @@
"description": "The default map for the server.",
"env_variable": "SRCDS_MAP",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|alpha_dash"
}
]
diff --git a/database/seeds/eggs/source-engine/egg-garrys-mod.json b/database/seeds/eggs/source-engine/egg-garrys-mod.json
index 17940e8fb..d2201a6c3 100644
--- a/database/seeds/eggs/source-engine/egg-garrys-mod.json
+++ b/database/seeds/eggs/source-engine/egg-garrys-mod.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2019-12-08T10:56:42-05:00",
+ "exported_at": "2020-10-19T23:34:44+00:00",
"name": "Garrys Mod",
"author": "support@pterodactyl.io",
"description": "Garrys Mod, is a sandbox physics game created by Garry Newman, and developed by his company, Facepunch Studios.",
@@ -17,8 +17,8 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'ubuntu:18.04'\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so\r\n\r\n# Creating needed default files for the game\r\ncd \/mnt\/server\/garrysmod\/lua\/autorun\/server\r\necho '\r\n-- Docs: https:\/\/wiki.garrysmod.com\/page\/resource\/AddWorkshop\r\n-- Place the ID of the workshop addon you want to be downloaded to people who join your server, not the collection ID\r\n-- Use https:\/\/beta.configcreator.com\/create\/gmod\/resources.lua to easily create a list based on your collection ID\r\n\r\nresource.AddWorkshop( \"\" )\r\n' > workshop.lua\r\n\r\ncd \/mnt\/server\/garrysmod\/cfg\r\necho '\r\n\/\/ Please do not set RCon in here, use the startup parameters.\r\n\r\nhostname\t\t\"New Gmod Server\"\r\nsv_password\t\t\"\"\r\nsv_loadingurl \"\"\r\n\r\n\/\/ Steam Server List Settings\r\nsv_region \"255\"\r\nsv_lan \"0\"\r\nsv_max_queries_sec_global \"30000\"\r\nsv_max_queries_window \"45\"\r\nsv_max_queries_sec \"5\"\r\n\r\n\/\/ Server Limits\r\nsbox_maxprops\t\t100\r\nsbox_maxragdolls\t5\r\nsbox_maxnpcs\t\t10\r\nsbox_maxballoons\t10\r\nsbox_maxeffects\t\t10\r\nsbox_maxdynamite\t10\r\nsbox_maxlamps\t\t10\r\nsbox_maxthrusters\t10\r\nsbox_maxwheels\t\t10\r\nsbox_maxhoverballs\t10\r\nsbox_maxvehicles\t20\r\nsbox_maxbuttons\t\t10\r\nsbox_maxsents\t\t20\r\nsbox_maxemitters\t5\r\nsbox_godmode\t\t0\r\nsbox_noclip\t\t 0\r\n\r\n\/\/ Network Settings - Please keep these set to default.\r\n\r\nsv_minrate\t\t75000\r\nsv_maxrate\t\t0\r\ngmod_physiterations\t2\r\nnet_splitpacket_maxrate\t45000\r\ndecalfrequency\t\t12 \r\n\r\n\/\/ Execute Ban Files - Please do not edit\r\nexec banned_ip.cfg \r\nexec banned_user.cfg \r\n\r\n\/\/ Add custom lines under here\r\n' > server.cfg",
- "container": "ubuntu:18.04",
+ "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'debian:buster-slim'\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n echo -e \"steam user is not set.\\n\"\r\n echo -e \"Using anonymous user.\\n\"\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nelse\r\n echo -e \"user set to ${STEAM_USER}\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} $( [[ \"${WINDOWS_INSTALL}\" == \"1\" ]] && printf %s '+@sSteamCmdForcePlatformType windows' ) +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} validate +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so\r\n\r\n# Creating needed default files for the game\r\ncd \/mnt\/server\/garrysmod\/lua\/autorun\/server\r\necho '\r\n-- Docs: https:\/\/wiki.garrysmod.com\/page\/resource\/AddWorkshop\r\n-- Place the ID of the workshop addon you want to be downloaded to people who join your server, not the collection ID\r\n-- Use https:\/\/beta.configcreator.com\/create\/gmod\/resources.lua to easily create a list based on your collection ID\r\n\r\nresource.AddWorkshop( \"\" )\r\n' > workshop.lua\r\n\r\ncd \/mnt\/server\/garrysmod\/cfg\r\necho '\r\n\/\/ Please do not set RCon in here, use the startup parameters.\r\n\r\nhostname\t\t\"New Gmod Server\"\r\nsv_password\t\t\"\"\r\nsv_loadingurl \"\"\r\n\r\n\/\/ Steam Server List Settings\r\nsv_region \"255\"\r\nsv_lan \"0\"\r\nsv_max_queries_sec_global \"30000\"\r\nsv_max_queries_window \"45\"\r\nsv_max_queries_sec \"5\"\r\n\r\n\/\/ Server Limits\r\nsbox_maxprops\t\t100\r\nsbox_maxragdolls\t5\r\nsbox_maxnpcs\t\t10\r\nsbox_maxballoons\t10\r\nsbox_maxeffects\t\t10\r\nsbox_maxdynamite\t10\r\nsbox_maxlamps\t\t10\r\nsbox_maxthrusters\t10\r\nsbox_maxwheels\t\t10\r\nsbox_maxhoverballs\t10\r\nsbox_maxvehicles\t20\r\nsbox_maxbuttons\t\t10\r\nsbox_maxsents\t\t20\r\nsbox_maxemitters\t5\r\nsbox_godmode\t\t0\r\nsbox_noclip\t\t 0\r\n\r\n\/\/ Network Settings - Please keep these set to default.\r\n\r\nsv_minrate\t\t75000\r\nsv_maxrate\t\t0\r\ngmod_physiterations\t2\r\nnet_splitpacket_maxrate\t45000\r\ndecalfrequency\t\t12 \r\n\r\n\/\/ Execute Ban Files - Please do not edit\r\nexec banned_ip.cfg \r\nexec banned_user.cfg \r\n\r\n\/\/ Add custom lines under here\r\n' > server.cfg",
+ "container": "debian:buster-slim",
"entrypoint": "bash"
}
},
@@ -28,8 +28,8 @@
"description": "The default map for the server.",
"env_variable": "SRCDS_MAP",
"default_value": "gm_flatgrass",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|alpha_dash"
},
{
@@ -37,8 +37,8 @@
"description": "The Steam Account Token required for the server to be displayed publicly.",
"env_variable": "STEAM_ACC",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "nullable|string|alpha_num|size:32"
},
{
@@ -46,8 +46,8 @@
"description": "Required for game to update on server restart. Do not modify this.",
"env_variable": "SRCDS_APPID",
"default_value": "4020",
- "user_viewable": 0,
- "user_editable": 0,
+ "user_viewable": false,
+ "user_editable": false,
"rules": "required|string|max:20"
},
{
@@ -55,8 +55,8 @@
"description": "The ID of your workshop collection (the numbers at the end of the URL)",
"env_variable": "WORKSHOP_ID",
"default_value": "",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "nullable|integer"
},
{
@@ -64,8 +64,8 @@
"description": "The gamemode of your server.",
"env_variable": "GAMEMODE",
"default_value": "sandbox",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string"
},
{
@@ -73,8 +73,8 @@
"description": "The maximum amount of players allowed on your game server.",
"env_variable": "MAX_PLAYERS",
"default_value": "32",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|integer|max:128"
},
{
@@ -82,8 +82,8 @@
"description": "The tickrate defines how fast the server will update each entities location.",
"env_variable": "TICKRATE",
"default_value": "22",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|integer|max:100"
}
]
diff --git a/database/seeds/eggs/source-engine/egg-insurgency.json b/database/seeds/eggs/source-engine/egg-insurgency.json
index 7f0c76be2..3103ac244 100644
--- a/database/seeds/eggs/source-engine/egg-insurgency.json
+++ b/database/seeds/eggs/source-engine/egg-insurgency.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2019-12-08T10:57:32-05:00",
+ "exported_at": "2020-10-19T23:35:42+00:00",
"name": "Insurgency",
"author": "support@pterodactyl.io",
"description": "Take to the streets for intense close quarters combat, where a team's survival depends upon securing crucial strongholds and destroying enemy supply in this multiplayer and cooperative Source Engine based experience.",
@@ -17,8 +17,8 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'ubuntu:18.04'\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so",
- "container": "ubuntu:18.04",
+ "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'debian:buster-slim'\r\n\r\n##\r\n#\r\n# Variables\r\n# STEAM_USER, STEAM_PASS, STEAM_AUTH - Steam user setup. If a user has 2fa enabled it will most likely fail due to timeout. Leave blank for anon install.\r\n# WINDOWS_INSTALL - if it's a windows server you want to install set to 1\r\n# SRCDS_APPID - steam app id ffound here - https:\/\/developer.valvesoftware.com\/wiki\/Dedicated_Servers_List\r\n# EXTRA_FLAGS - when a server has extra glas for things like beta installs or updates.\r\n#\r\n##\r\n\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n echo -e \"steam user is not set.\\n\"\r\n echo -e \"Using anonymous user.\\n\"\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nelse\r\n echo -e \"user set to ${STEAM_USER}\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} $( [[ \"${WINDOWS_INSTALL}\" == \"1\" ]] && printf %s '+@sSteamCmdForcePlatformType windows' ) +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} validate +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so",
+ "container": "debian:buster-slim",
"entrypoint": "bash"
}
},
@@ -28,8 +28,8 @@
"description": "The ID corresponding to the game to download and run using SRCDS.",
"env_variable": "SRCDS_APPID",
"default_value": "237410",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|regex:\/^(237410)$\/"
},
{
@@ -37,8 +37,8 @@
"description": "The name corresponding to the game to download and run using SRCDS.",
"env_variable": "SRCDS_GAME",
"default_value": "insurgency",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|regex:\/^(insurgency)$\/"
},
{
@@ -46,8 +46,8 @@
"description": "The default map to use when starting the server.",
"env_variable": "SRCDS_MAP",
"default_value": "sinjar",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|regex:\/^(\\w{1,20})$\/"
}
]
diff --git a/database/seeds/eggs/source-engine/egg-team-fortress2.json b/database/seeds/eggs/source-engine/egg-team-fortress2.json
index 159e7bf9b..8b619642f 100644
--- a/database/seeds/eggs/source-engine/egg-team-fortress2.json
+++ b/database/seeds/eggs/source-engine/egg-team-fortress2.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2019-12-08T10:58:48-05:00",
+ "exported_at": "2020-10-19T23:36:44+00:00",
"name": "Team Fortress 2",
"author": "support@pterodactyl.io",
"description": "Team Fortress 2 is a team-based first-person shooter multiplayer video game developed and published by Valve Corporation. It is the sequel to the 1996 mod Team Fortress for Quake and its 1999 remake.",
@@ -17,8 +17,8 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'ubuntu:18.04'\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so",
- "container": "ubuntu:18.04",
+ "script": "#!\/bin\/bash\r\n# steamcmd Base Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\n# Image to install with is 'debian:buster-slim'\r\n\r\n##\r\n#\r\n# Variables\r\n# STEAM_USER, STEAM_PASS, STEAM_AUTH - Steam user setup. If a user has 2fa enabled it will most likely fail due to timeout. Leave blank for anon install.\r\n# WINDOWS_INSTALL - if it's a windows server you want to install set to 1\r\n# SRCDS_APPID - steam app id ffound here - https:\/\/developer.valvesoftware.com\/wiki\/Dedicated_Servers_List\r\n# EXTRA_FLAGS - when a server has extra glas for things like beta installs or updates.\r\n#\r\n##\r\n\r\napt -y update\r\napt -y --no-install-recommends install curl lib32gcc1 ca-certificates\r\n\r\n## just in case someone removed the defaults.\r\nif [ \"${STEAM_USER}\" == \"\" ]; then\r\n echo -e \"steam user is not set.\\n\"\r\n echo -e \"Using anonymous user.\\n\"\r\n STEAM_USER=anonymous\r\n STEAM_PASS=\"\"\r\n STEAM_AUTH=\"\"\r\nelse\r\n echo -e \"user set to ${STEAM_USER}\"\r\nfi\r\n\r\n## download and install steamcmd\r\ncd \/tmp\r\nmkdir -p \/mnt\/server\/steamcmd\r\ncurl -sSL -o steamcmd.tar.gz https:\/\/steamcdn-a.akamaihd.net\/client\/installer\/steamcmd_linux.tar.gz\r\ntar -xzvf steamcmd.tar.gz -C \/mnt\/server\/steamcmd\r\ncd \/mnt\/server\/steamcmd\r\n\r\n# SteamCMD fails otherwise for some reason, even running as root.\r\n# This is changed at the end of the install process anyways.\r\nchown -R root:root \/mnt\r\nexport HOME=\/mnt\/server\r\n\r\n## install game using steamcmd\r\n.\/steamcmd.sh +login ${STEAM_USER} ${STEAM_PASS} ${STEAM_AUTH} $( [[ \"${WINDOWS_INSTALL}\" == \"1\" ]] && printf %s '+@sSteamCmdForcePlatformType windows' ) +force_install_dir \/mnt\/server +app_update ${SRCDS_APPID} ${EXTRA_FLAGS} validate +quit ## other flags may be needed depending on install. looking at you cs 1.6\r\n\r\n## set up 32 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk32\r\ncp -v linux32\/steamclient.so ..\/.steam\/sdk32\/steamclient.so\r\n\r\n## set up 64 bit libraries\r\nmkdir -p \/mnt\/server\/.steam\/sdk64\r\ncp -v linux64\/steamclient.so ..\/.steam\/sdk64\/steamclient.so",
+ "container": "debian:buster-slim",
"entrypoint": "bash"
}
},
@@ -28,8 +28,8 @@
"description": "The ID corresponding to the game to download and run using SRCDS.",
"env_variable": "SRCDS_APPID",
"default_value": "232250",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|regex:\/^(232250)$\/"
},
{
@@ -37,8 +37,8 @@
"description": "The name corresponding to the game to download and run using SRCDS.",
"env_variable": "SRCDS_GAME",
"default_value": "tf",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|regex:\/^(tf)$\/"
},
{
@@ -46,8 +46,8 @@
"description": "The default map to use when starting the server.",
"env_variable": "SRCDS_MAP",
"default_value": "cp_dustbowl",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|regex:\/^(\\w{1,20})$\/"
}
]
diff --git a/database/seeds/eggs/terraria/egg-terraria-server--t-shock.json b/database/seeds/eggs/terraria/egg-terraria-server--t-shock.json
deleted file mode 100644
index 9381890d1..000000000
--- a/database/seeds/eggs/terraria/egg-terraria-server--t-shock.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO",
- "meta": {
- "version": "PTDL_v1"
- },
- "exported_at": "2018-01-21T17:01:31-06:00",
- "name": "Terraria Server (TShock)",
- "author": "support@pterodactyl.io",
- "description": "TShock is a server modification for Terraria, written in C#, and based upon the Terraria Server API. It uses JSON for configuration management, and offers several features not present in the Terraria Server normally.",
- "image": "quay.io\/pterodactyl\/core:mono",
- "startup": null,
- "config": {
- "files": "{\"tshock\/config.json\":{\"parser\": \"json\", \"find\":{\"ServerPort\": \"{{server.build.default.port}}\", \"MaxSlots\": \"{{server.build.env.MAX_SLOTS}}\"}}}",
- "startup": "{\"done\": \"Type 'help' for a list of commands\", \"userInteraction\": []}",
- "logs": "{\"custom\": false, \"location\": \"ServerLog.txt\"}",
- "stop": "exit"
- },
- "scripts": {
- "installation": {
- "script": "#!\/bin\/ash\n# TShock Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl unzip\n\ncd \/tmp\n\ncurl -sSLO https:\/\/github.com\/NyxStudios\/TShock\/releases\/download\/v${T_VERSION}\/tshock_${T_VERSION}.zip\n\nunzip -o tshock_${T_VERSION}.zip -d \/mnt\/server",
- "container": "alpine:3.9",
- "entrypoint": "ash"
- }
- },
- "variables": [
- {
- "name": "TShock Version",
- "description": "Which version of TShock to install and use.",
- "env_variable": "T_VERSION",
- "default_value": "4.3.22",
- "user_viewable": 1,
- "user_editable": 1,
- "rules": "required|regex:\/^([0-9_\\.-]{5,10})$\/"
- },
- {
- "name": "Maximum Slots",
- "description": "Total number of slots to allow on the server.",
- "env_variable": "MAX_SLOTS",
- "default_value": "20",
- "user_viewable": 1,
- "user_editable": 0,
- "rules": "required|numeric|digits_between:1,3"
- }
- ]
-}
diff --git a/database/seeds/eggs/voice-servers/egg-mumble-server.json b/database/seeds/eggs/voice-servers/egg-mumble-server.json
index 00c87d21e..4f3acf7df 100644
--- a/database/seeds/eggs/voice-servers/egg-mumble-server.json
+++ b/database/seeds/eggs/voice-servers/egg-mumble-server.json
@@ -3,7 +3,7 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2018-01-21T17:01:44-06:00",
+ "exported_at": "2020-10-25T22:34:06+00:00",
"name": "Mumble Server",
"author": "support@pterodactyl.io",
"description": "Mumble is an open source, low-latency, high quality voice chat software primarily intended for use while gaming.",
@@ -17,9 +17,9 @@
},
"scripts": {
"installation": {
- "script": "#!\/bin\/ash\n# Mumble Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add tar curl\n\ncd \/tmp\n\ncurl -sSLO https:\/\/github.com\/mumble-voip\/mumble\/releases\/download\/${MUMBLE_VERSION}\/murmur-static_x86-${MUMBLE_VERSION}.tar.bz2\n\ntar -xjvf murmur-static_x86-${MUMBLE_VERSION}.tar.bz2\ncp -r murmur-static_x86-${MUMBLE_VERSION}\/* \/mnt\/server",
- "container": "alpine:3.9",
- "entrypoint": "ash"
+ "script": "#!\/bin\/bash\r\n# Mumble Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\nGITHUB_PACKAGE=mumble-voip\/mumble\r\nMATCH=murmur-static\r\n\r\napt update\r\napt install -y tar curl jq bzip2\r\n\r\nif [ ! -d \/mnt\/server\/ ]; then\r\n mkdir \/mnt\/server\/\r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\nif [ -z \"${GITHUB_USER}\" ] && [ -z \"${GITHUB_OAUTH_TOKEN}\" ] ; then\r\n echo -e \"using anon api call\"\r\nelse\r\n echo -e \"user and oauth token set\"\r\n alias curl='curl -u ${GITHUB_USER}:${GITHUB_OAUTH_TOKEN} '\r\nfi\r\n\r\n## get release info and download links\r\nLATEST_JSON=$(curl --silent \"https:\/\/api.github.com\/repos\/${GITHUB_PACKAGE}\/releases\/latest\")\r\nRELEASES=$(curl --silent \"https:\/\/api.github.com\/repos\/${GITHUB_PACKAGE}\/releases\")\r\n\r\nif [ -z \"${VERSION}\" ] || [ \"${VERSION}\" == \"latest\" ]; then\r\n DOWNLOAD_LINK=$(echo ${LATEST_JSON} | jq .assets | jq -r .[].browser_download_url | grep -m 1 -i ${MATCH})\r\nelse\r\n VERSION_CHECK=$(echo ${RELEASES} | jq -r --arg VERSION \"${VERSION}\" '.[] | select(.tag_name==$VERSION) | .tag_name')\r\n if [ \"${VERSION}\" == \"${VERSION_CHECK}\" ]; then\r\n DOWNLOAD_LINK=$(echo ${RELEASES} | jq -r --arg VERSION \"${VERSION}\" '.[] | select(.tag_name==$VERSION) | .assets[].browser_download_url' | grep -m 1 -i ${MATCH})\r\n else\r\n echo -e \"defaulting to latest release\"\r\n DOWNLOAD_LINK=$(echo ${LATEST_JSON} | jq .assets | jq -r .[].browser_download_url)\r\n fi\r\nfi\r\n\r\ncurl -L ${DOWNLOAD_LINK} | tar xjv --strip-components=1",
+ "container": "debian:buster-slim",
+ "entrypoint": "bash"
}
},
"variables": [
@@ -28,18 +28,18 @@
"description": "Maximum concurrent users on the mumble server.",
"env_variable": "MAX_USERS",
"default_value": "100",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|numeric|digits_between:1,5"
},
{
"name": "Server Version",
"description": "Version of Mumble Server to download and use.",
"env_variable": "MUMBLE_VERSION",
- "default_value": "1.3.1",
- "user_viewable": 1,
- "user_editable": 1,
+ "default_value": "latest",
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|regex:\/^([0-9_\\.-]{5,8})$\/"
}
]
-}
+}
\ No newline at end of file
diff --git a/database/seeds/eggs/voice-servers/egg-teamspeak3-server.json b/database/seeds/eggs/voice-servers/egg-teamspeak3-server.json
index d3d889bc0..d14d8eea9 100644
--- a/database/seeds/eggs/voice-servers/egg-teamspeak3-server.json
+++ b/database/seeds/eggs/voice-servers/egg-teamspeak3-server.json
@@ -3,23 +3,23 @@
"meta": {
"version": "PTDL_v1"
},
- "exported_at": "2019-07-05T11:59:29-04:00",
+ "exported_at": "2020-10-25T22:24:15+00:00",
"name": "Teamspeak3 Server",
"author": "support@pterodactyl.io",
"description": "VoIP software designed with security in mind, featuring crystal clear voice quality, endless customization options, and scalabilty up to thousands of simultaneous users.",
- "image": "quay.io/parkervcp/pterodactyl-images:base_debian",
- "startup": "./ts3server default_voice_port={{SERVER_PORT}} query_port={{SERVER_PORT}} filetransfer_ip=0.0.0.0 filetransfer_port={{FILE_TRANSFER}} license_accepted=1",
+ "image": "quay.io\/parkervcp\/pterodactyl-images:base_debian",
+ "startup": ".\/ts3server default_voice_port={{SERVER_PORT}} query_port={{SERVER_PORT}} filetransfer_ip=0.0.0.0 filetransfer_port={{FILE_TRANSFER}} license_accepted=1",
"config": {
"files": "{}",
"startup": "{\r\n \"done\": \"listening on 0.0.0.0:\",\r\n \"userInteraction\": []\r\n}",
- "logs": "{\r\n \"custom\": true,\r\n \"location\": \"logs/ts3.log\"\r\n}",
+ "logs": "{\r\n \"custom\": true,\r\n \"location\": \"logs\/ts3.log\"\r\n}",
"stop": "^C"
},
"scripts": {
"installation": {
- "script": "#!/bin/ash\r\n# TS3 Installation Script\r\n#\r\n# Server Files: /mnt/server\r\napk add --no-cache tar curl jq\r\n\r\nif [ -z ${TS_VERSION} ] || [ ${TS_VERSION} == latest ]; then\r\n TS_VERSION=$(wget https://teamspeak.com/versions/server.json -qO - | jq -r '.linux.x86_64.version')\r\nfi\r\n\r\ncd /mnt/server\r\n\r\n\r\necho -e \"getting files from http://files.teamspeak-services.com/releases/server/${TS_VERSION}/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\"\r\ncurl http://files.teamspeak-services.com/releases/server/${TS_VERSION}/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2 | tar xj --strip-components=1",
- "container": "alpine:3.9",
- "entrypoint": "ash"
+ "script": "#!\/bin\/bash\r\n# TS3 Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napt update\r\napt install -y tar curl jq bzip2\r\n\r\nif [ -z ${TS_VERSION} ] || [ ${TS_VERSION} == latest ]; then\r\n TS_VERSION=$(curl -sSL https:\/\/teamspeak.com\/versions\/server.json | jq -r '.linux.x86_64.version')\r\nfi\r\n\r\ncd \/mnt\/server\r\n\r\necho -e \"getting files from http:\/\/files.teamspeak-services.com\/releases\/server\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\" \r\ncurl -L http:\/\/files.teamspeak-services.com\/releases\/server\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2 | tar -xvj --strip-components=1\r\n\r\nrm teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2",
+ "container": "debian:buster-slim",
+ "entrypoint": "bash"
}
},
"variables": [
@@ -28,8 +28,8 @@
"description": "The version of Teamspeak 3 to use when running the server.",
"env_variable": "TS_VERSION",
"default_value": "latest",
- "user_viewable": 1,
- "user_editable": 1,
+ "user_viewable": true,
+ "user_editable": true,
"rules": "required|string|max:6"
},
{
@@ -37,9 +37,9 @@
"description": "The Teamspeak file transfer port",
"env_variable": "FILE_TRANSFER",
"default_value": "30033",
- "user_viewable": 1,
- "user_editable": 0,
+ "user_viewable": true,
+ "user_editable": false,
"rules": "required|integer|between:1,65535"
}
]
-}
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 15e96c4bd..2f947b532 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,10 @@
{
"name": "pterodactyl-panel",
"dependencies": {
- "@fortawesome/fontawesome-svg-core": "1.2.19",
- "@fortawesome/free-solid-svg-icons": "^5.9.0",
- "@fortawesome/react-fontawesome": "0.1.4",
+ "@fortawesome/fontawesome-svg-core": "^1.2.32",
+ "@fortawesome/free-solid-svg-icons": "^5.15.1",
+ "@fortawesome/react-fontawesome": "^0.1.11",
+ "@types/react-copy-to-clipboard": "^4.3.0",
"axios": "^0.19.2",
"chart.js": "^2.8.0",
"codemirror": "^5.57.0",
@@ -21,11 +22,12 @@
"path": "^0.12.7",
"query-string": "^6.7.0",
"react": "^16.13.1",
+ "react-copy-to-clipboard": "^5.0.2",
"react-dom": "npm:@hot-loader/react-dom",
"react-fast-compare": "^3.2.0",
+ "react-ga": "^3.1.2",
"react-google-recaptcha": "^2.0.1",
"react-helmet": "^6.1.0",
- "react-ga": "^3.1.2",
"react-hot-loader": "^4.12.21",
"react-i18next": "^11.2.1",
"react-redux": "^7.1.0",
@@ -37,29 +39,31 @@
"styled-components-breakpoint": "^3.0.0-preview.20",
"swr": "^0.2.3",
"uuid": "^3.3.2",
- "xterm": "^3.14.4",
- "xterm-addon-attach": "^0.1.0",
- "xterm-addon-fit": "^0.1.0",
+ "xterm": "^4.9.0",
+ "xterm-addon-attach": "^0.6.0",
+ "xterm-addon-fit": "^0.4.0",
+ "xterm-addon-search": "^0.7.0",
+ "xterm-addon-search-bar": "^0.2.0",
"yup": "^0.29.1"
},
"devDependencies": {
- "@babel/core": "^7.7.5",
- "@babel/plugin-proposal-class-properties": "^7.7.4",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
- "@babel/plugin-proposal-object-rest-spread": "^7.7.4",
- "@babel/plugin-proposal-optional-chaining": "^7.8.3",
- "@babel/plugin-syntax-dynamic-import": "^7.7.4",
- "@babel/plugin-transform-react-jsx": "^7.10.4",
- "@babel/plugin-transform-runtime": "^7.7.5",
- "@babel/preset-env": "^7.7.5",
- "@babel/preset-react": "^7.7.4",
- "@babel/preset-typescript": "^7.7.4",
- "@babel/runtime": "^7.7.5",
+ "@babel/core": "^7.12.1",
+ "@babel/plugin-proposal-class-properties": "^7.12.1",
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
+ "@babel/plugin-proposal-object-rest-spread": "^7.12.1",
+ "@babel/plugin-proposal-optional-chaining": "^7.12.1",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.3",
+ "@babel/plugin-transform-react-jsx": "^7.12.1",
+ "@babel/plugin-transform-runtime": "^7.12.1",
+ "@babel/preset-env": "^7.12.1",
+ "@babel/preset-react": "^7.12.1",
+ "@babel/preset-typescript": "^7.12.1",
+ "@babel/runtime": "^7.12.1",
"@types/chart.js": "^2.8.5",
"@types/codemirror": "^0.0.98",
"@types/debounce": "^1.2.0",
"@types/events": "^3.0.0",
- "@types/node": "^12.6.9",
+ "@types/node": "^14.11.10",
"@types/query-string": "^6.3.0",
"@types/react": "^16.9.41",
"@types/react-dom": "^16.9.8",
@@ -91,9 +95,9 @@
"source-map-loader": "^1.0.1",
"style-loader": "^1.2.1",
"svg-url-loader": "^6.0.0",
- "tailwindcss": "^1.4.6",
+ "tailwindcss": "^1.9.4",
"terser-webpack-plugin": "^3.0.6",
- "twin.macro": "^1.4.1",
+ "twin.macro": "^1.10.0",
"typescript": "^3.9.6",
"typescript-plugin-tw-template": "^2.0.1",
"webpack": "^4.43.0",
diff --git a/resources/lang/en/command/messages.php b/resources/lang/en/command/messages.php
index 71731a2d0..002c699bb 100644
--- a/resources/lang/en/command/messages.php
+++ b/resources/lang/en/command/messages.php
@@ -14,7 +14,7 @@ return [
'deleted' => 'Successfully deleted the requested location.',
],
'user' => [
- 'search_users' => 'Enter a Username, UUID, or Email Address',
+ 'search_users' => 'Enter a Username, User ID, or Email Address',
'select_search_user' => 'ID of user to delete (Enter \'0\' to re-search)',
'deleted' => 'User successfully deleted from the Panel.',
'confirm_delete' => 'Are you sure you want to delete this user from the Panel?',
diff --git a/resources/scripts/api/getServers.ts b/resources/scripts/api/getServers.ts
index 63329bfa7..6094b1706 100644
--- a/resources/scripts/api/getServers.ts
+++ b/resources/scripts/api/getServers.ts
@@ -4,16 +4,15 @@ import http, { getPaginationSet, PaginatedResult } from '@/api/http';
interface QueryParams {
query?: string;
page?: number;
- onlyAdmin?: boolean;
+ type?: string;
}
-export default ({ query, page = 1, onlyAdmin = false }: QueryParams): Promise
Copied "{text}" to clipboard.
++ An error was encountered by the application while rendering this view. Try refreshing the page. +
+
diff --git a/resources/scripts/components/server/files/FileManagerBreadcrumbs.tsx b/resources/scripts/components/server/files/FileManagerBreadcrumbs.tsx
index ba43dbd61..968a651db 100644
--- a/resources/scripts/components/server/files/FileManagerBreadcrumbs.tsx
+++ b/resources/scripts/components/server/files/FileManagerBreadcrumbs.tsx
@@ -33,10 +33,10 @@ export default ({ withinFileEditor, isNewFile }: Props) => {
.filter(directory => !!directory)
.map((directory, index, dirs) => {
if (!withinFileEditor && index === dirs.length - 1) {
- return { name: decodeURIComponent(directory) };
+ return { name: decodeURIComponent(encodeURIComponent(directory)) };
}
- return { name: decodeURIComponent(directory), path: `/${dirs.slice(0, index + 1).join('/')}` };
+ return { name: decodeURIComponent(encodeURIComponent(directory)), path: `/${dirs.slice(0, index + 1).join('/')}` };
});
const onSelectAllClick = (e: React.ChangeEvent
{allocation.alias || allocation.ip}
-
+ {allocation.alias ? {allocation.alias}
{allocation.ip}
{allocation.port}
diff --git a/resources/scripts/components/server/schedules/DeleteScheduleButton.tsx b/resources/scripts/components/server/schedules/DeleteScheduleButton.tsx
index 198060388..463202dce 100644
--- a/resources/scripts/components/server/schedules/DeleteScheduleButton.tsx
+++ b/resources/scripts/components/server/schedules/DeleteScheduleButton.tsx
@@ -49,7 +49,7 @@ export default ({ scheduleId, onDeleted }: Props) => {
Are you sure you want to delete this schedule? All tasks will be removed and any running processes
will be terminated.
- {cron.minute}
+Minute
+{cron.hour}
+Hour
+{cron.dayOfMonth}
+Day (Month)
+*
+Month
+{cron.dayOfWeek}
+Day (Week)
+{title}
+{value}
++ Last run at: + {schedule.lastRunAt ? format(schedule.lastRunAt, 'MMM do \'at\' h:mma') : 'never'} +
+- Task delays are relative to the previous task in the listing. -
- } - > - : -- There are no tasks configured for this schedule. -
- } -{schedule.cron.minute}
-Minute
-{schedule.cron.hour}
-Hour
-{schedule.cron.dayOfMonth}
-Day (Month)
-*
-Month
-{schedule.cron.dayOfWeek}
-Day (Week)
-- {schedule.isActive ? 'Active' : 'Inactive'} + {schedule.isProcessing ? + 'Processing' + : + schedule.isActive ? 'Active' : 'Inactive' + }
+
{title}
{task.payload && @@ -87,36 +88,36 @@ export default ({ schedule, task }: Props) => {- {task.timeOffset}s -
-- Delay Run By -
+{permission}
- {isEditable && - values.permissions.includes(p))} - onChange={onCheckboxClicked} - /> - } -- Only permissions which your account is currently assigned may be selected when creating or - modifying other users. -
-- {permissions[key].description} -
- {Object.keys(permissions[key].keys).map(pkey => ( -- {permissions[key].keys[pkey]} -
- } -+ Only permissions which your account is currently assigned may be selected when creating or + modifying other users. +
++ {permissions[key].description} +
+ {Object.keys(permissions[key].keys).map(pkey => ( ++ {permissions[key].keys[pkey]} +
+ } +{title}
+ {isEditable && + value.includes(p))} + onChange={onCheckboxClicked} + /> + } +
@@ -64,6 +64,6 @@ export default () => {
(modalProps?: ExtendedModalProps | ((props: P this.state = { render: props.visible, visible: props.visible, - modalProps: typeof modalProps === 'function' ? modalProps(this.props) : modalProps, + showSpinnerOverlay: undefined, + }; + } + + get modalProps () { + return { + ...(typeof modalProps === 'function' ? modalProps(this.props) : modalProps), + showSpinnerOverlay: this.state.showSpinnerOverlay, }; } componentDidUpdate (prevProps: Readonly
) { - const mapped = typeof modalProps === 'function' ? modalProps(this.props) : modalProps; - if (!isEqual(this.state.modalProps, mapped)) { - // noinspection JSPotentiallyInvalidUsageOfThis - this.setState({ modalProps: mapped }); - } - if (prevProps.visible && !this.props.visible) { // noinspection JSPotentiallyInvalidUsageOfThis this.setState({ visible: false }); @@ -52,39 +52,32 @@ function asModal
(modalProps?: ExtendedModalProps | ((props: P
dismiss = () => this.setState({ visible: false });
- toggleSpinner = (value?: boolean) => this.setState(s => ({
- modalProps: {
- ...s.modalProps,
- showSpinnerOverlay: value || false,
- },
- }));
+ toggleSpinner = (value?: boolean) => this.setState({ showSpinnerOverlay: value });
render () {
return (
-