Skip to content

Commit aad3019

Browse files
Merge branch 'develop' into subusers
2 parents 0f09dfe + 31ad238 commit aad3019

File tree

71 files changed

+1375
-753
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1375
-753
lines changed

CHANGELOG.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,43 @@ This file is a running track of new features and fixes to each version of the pa
33

44
This project follows [Semantic Versioning](http://semver.org) guidelines.
55

6+
## v1.0.3
7+
### Fixed
8+
* Fixes bug causing subusers to not be creatable or editable via the frontend for servers.
9+
* 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.
10+
* Fixes listing servers owned by a user in the admin area to actually list their servers.
11+
12+
### Changed
13+
* Adds SameSite `lax` attribute for cookies generated by the Panel.
14+
* Adds better filtering for searching servers in the admin area to better key off name, uuid, or owner username/email.
15+
16+
## v1.0.2
17+
### Added
18+
* Adds support for searching inside the file editor.
19+
* Adds support for manually executing a schedule regardless of if it is currently queued or not.
20+
* Adds an indicator to the schedule UI to show when a schedule is currently processing.
21+
* Adds support for setting the `backup_limit` of a server via the API.
22+
* **[Security]** Adds login throttling to the 2FA verification endpoint.
23+
24+
### Fixed
25+
* Fixes subuser page title missing server name.
26+
* Fixes schedule task `sequence_id` not properly being reset when a schedule's task is deleted.
27+
* Fixes misc. UI bugs throughout the frontend when long text overflows its bounds.
28+
* Fixes user deletion command to properly handle email & ID searching.
29+
* Fixes color issues in the terminal causing certain text & background combinations to be illegible.
30+
* Fixes reCAPTCHA not properly resetting on login failure.
31+
* Fixes error messages not properly resetting between login screens.
32+
* Fixes a UI crash when attempting to create or view a directory or file that contained the `%` somewhere in the name.
33+
34+
### Changed
35+
* Updated the search modal to close itself when the ESC key is pressed.
36+
* Updates the schedule view and editing UI to better display information to users.
37+
* Changed logic powering server searching on the frontend to return more accurate results and return all servers when executing the query as an admin.
38+
* Admin CP link no longer opens in a new tab.
39+
* 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.
40+
* Cleaned up assorted server build modification code.
41+
* Updates default eggs to have improved install scripts and more consistent container usage.
42+
643
## v1.0.1
744
### Fixed
845
* Fixes 500 error when mounting a mount to a server, and other related errors when handling mounts.

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Stop settling for less. Make game servers a first class citizen on your platform
1515
![Image](https://cdn.pterodactyl.io/site-assets/pterodactyl_v1_demo.gif)
1616

1717
## Sponsors
18-
I would like to extend my sincere thanks to the following sponsors for helping find Pterodactyl's developement.
18+
I would like to extend my sincere thanks to the following sponsors for helping fund Pterodactyl's developement.
1919
[Interested in becoming a sponsor?](https://github.com/sponsors/DaneEveritt)
2020

2121
| Company | About |
@@ -26,8 +26,10 @@ I would like to extend my sincere thanks to the following sponsors for helping f
2626
| [**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. |
2727
| [**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! |
2828
| [**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. |
29-
| [**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. |
30-
| [**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. |
29+
| [**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. |
30+
| [**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. |
31+
| [**DeinServerHost**](https://deinserverhost.de/) | DeinServerHost offers Dedicated, vps and Gameservers for many popular Games like Minecraft and Rust in Germany since 2013. |
32+
| [**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. |
3133

3234
## Documentation
3335
* [Panel Documentation](https://pterodactyl.io/panel/1.0/getting_started.html)

app/Console/Commands/Environment/AppSettingsCommand.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ public function handle()
144144
$this->variables['APP_ENVIRONMENT_ONLY'] = $this->confirm(trans('command/messages.environment.app.settings'), true) ? 'false' : 'true';
145145
}
146146

147+
// Make sure session cookies are set as "secure" when using HTTPS
148+
if (strpos($this->variables['APP_URL'], 'https://') === 0) {
149+
$this->variables['SESSION_SECURE_COOKIE'] = 'true';
150+
}
151+
147152
$this->checkForRedis();
148153
$this->writeToEnvironment($this->variables);
149154

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,79 @@
11
<?php
2-
/**
3-
* Pterodactyl - Panel
4-
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
5-
*
6-
* This software is licensed under the terms of the MIT license.
7-
* https://opensource.org/licenses/MIT
8-
*/
92

103
namespace Pterodactyl\Console\Commands\Schedule;
114

12-
use Cake\Chronos\Chronos;
5+
use Throwable;
6+
use Exception;
137
use Illuminate\Console\Command;
14-
use Illuminate\Support\Collection;
8+
use Pterodactyl\Models\Schedule;
9+
use Illuminate\Support\Facades\Log;
1510
use Pterodactyl\Services\Schedules\ProcessScheduleService;
16-
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
1711

1812
class ProcessRunnableCommand extends Command
1913
{
20-
/**
21-
* @var string
22-
*/
23-
protected $description = 'Process schedules in the database and determine which are ready to run.';
24-
25-
/**
26-
* @var \Pterodactyl\Services\Schedules\ProcessScheduleService
27-
*/
28-
protected $processScheduleService;
29-
30-
/**
31-
* @var \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface
32-
*/
33-
protected $repository;
34-
3514
/**
3615
* @var string
3716
*/
3817
protected $signature = 'p:schedule:process';
3918

4019
/**
41-
* ProcessRunnableCommand constructor.
42-
*
43-
* @param \Pterodactyl\Services\Schedules\ProcessScheduleService $processScheduleService
44-
* @param \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface $repository
20+
* @var string
4521
*/
46-
public function __construct(ProcessScheduleService $processScheduleService, ScheduleRepositoryInterface $repository)
47-
{
48-
parent::__construct();
49-
50-
$this->processScheduleService = $processScheduleService;
51-
$this->repository = $repository;
52-
}
22+
protected $description = 'Process schedules in the database and determine which are ready to run.';
5323

5424
/**
5525
* Handle command execution.
5626
*/
5727
public function handle()
5828
{
59-
$schedules = $this->repository->getSchedulesToProcess(Chronos::now()->toAtomString());
29+
$schedules = Schedule::query()->with('tasks')
30+
->where('is_active', true)
31+
->where('is_processing', false)
32+
->whereRaw('next_run_at <= NOW()')
33+
->get();
34+
6035
if ($schedules->count() < 1) {
6136
$this->line('There are no scheduled tasks for servers that need to be run.');
6237

6338
return;
6439
}
6540

6641
$bar = $this->output->createProgressBar(count($schedules));
67-
$schedules->each(function ($schedule) use ($bar) {
68-
if ($schedule->tasks instanceof Collection && count($schedule->tasks) > 0) {
69-
$this->processScheduleService->handle($schedule);
70-
71-
if ($this->input->isInteractive()) {
72-
$bar->clear();
73-
$this->line(trans('command/messages.schedule.output_line', [
74-
'schedule' => $schedule->name,
75-
'hash' => $schedule->hashid,
76-
]));
77-
}
78-
}
79-
42+
foreach ($schedules as $schedule) {
43+
$bar->clear();
44+
$this->processSchedule($schedule);
8045
$bar->advance();
8146
$bar->display();
82-
});
47+
}
8348

8449
$this->line('');
8550
}
51+
52+
/**
53+
* Processes a given schedule and logs and errors encountered the console output. This should
54+
* never throw an exception out, otherwise you'll end up killing the entire run group causing
55+
* any other schedules to not process correctly.
56+
*
57+
* @param \Pterodactyl\Models\Schedule $schedule
58+
* @see https://github.com/pterodactyl/panel/issues/2609
59+
*/
60+
protected function processSchedule(Schedule $schedule)
61+
{
62+
if ($schedule->tasks->isEmpty()) {
63+
return;
64+
}
65+
66+
try {
67+
$this->getLaravel()->make(ProcessScheduleService::class)->handle($schedule);
68+
69+
$this->line(trans('command/messages.schedule.output_line', [
70+
'schedule' => $schedule->name,
71+
'hash' => $schedule->hashid,
72+
]));
73+
} catch (Throwable | Exception $exception) {
74+
Log::error($exception, ['schedule_id' => $schedule->id]);
75+
76+
$this->error("An error was encountered while processing Schedule #{$schedule->id}: " . $exception->getMessage());
77+
}
78+
}
8679
}

app/Contracts/Repository/ScheduleRepositoryInterface.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,4 @@ public function findServerSchedules(int $server): Collection;
2424
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
2525
*/
2626
public function getScheduleWithTasks(int $schedule): Schedule;
27-
28-
/**
29-
* Return all of the schedules that should be processed.
30-
*
31-
* @param string $timestamp
32-
* @return \Illuminate\Support\Collection
33-
*/
34-
public function getSchedulesToProcess(string $timestamp): Collection;
3527
}

app/Contracts/Repository/ServerRepositoryInterface.php

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,4 @@ public function getSuspendedServersCount(): int;
139139
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
140140
*/
141141
public function loadAllServersForNode(int $node, int $limit): LengthAwarePaginator;
142-
143-
/**
144-
* Returns every server that exists for a given node.
145-
*
146-
* This is different from {@see loadAllServersForNode} because
147-
* it does not paginate the response.
148-
*
149-
* @param int $node
150-
*
151-
* @return \Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
152-
*/
153-
public function loadEveryServerForNode(int $node);
154142
}

app/Helpers/Time.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Pterodactyl\Helpers;
4+
5+
use Carbon\CarbonImmutable;
6+
7+
final class Time
8+
{
9+
/**
10+
* Gets the time offset from the provided timezone relative to UTC as a number. This
11+
* is used in the database configuration since we can't always rely on there being support
12+
* for named timezones in MySQL.
13+
*
14+
* Returns the timezone as a string like +08:00 or -05:00 depending on the app timezone.
15+
*
16+
* @param string $timezone
17+
* @return string
18+
*/
19+
public static function getMySQLTimezoneOffset(string $timezone): string
20+
{
21+
$offset = round(CarbonImmutable::now($timezone)->getTimezone()->getOffset(CarbonImmutable::now('UTC')) / 3600);
22+
23+
return sprintf('%s%s:00', $offset > 0 ? '+' : '-', str_pad(abs($offset), 2, '0', STR_PAD_LEFT));
24+
}
25+
}

app/Helpers/Utilities.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ public static function getScheduleNextRunDate(string $minute, string $hour, stri
5252
)->getNextRunDate());
5353
}
5454

55-
public static function checked($name, $default)
55+
/**
56+
* @param string $name
57+
* @param mixed $default
58+
* @return string
59+
*/
60+
public static function checked(string $name, $default)
5661
{
5762
$errors = session('errors');
5863

app/Http/Controllers/Admin/Servers/ServerController.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
use Pterodactyl\Models\Server;
77
use Spatie\QueryBuilder\QueryBuilder;
88
use Illuminate\Contracts\View\Factory;
9+
use Spatie\QueryBuilder\AllowedFilter;
910
use Pterodactyl\Http\Controllers\Controller;
11+
use Pterodactyl\Models\Filters\AdminServerFilter;
1012
use Pterodactyl\Repositories\Eloquent\ServerRepository;
1113

1214
class ServerController extends Controller
@@ -45,8 +47,10 @@ public function __construct(
4547
public function index(Request $request)
4648
{
4749
$servers = QueryBuilder::for(Server::query()->with('node', 'user', 'allocation'))
48-
->allowedFilters(['uuid', 'name', 'image'])
49-
->allowedSorts(['id', 'uuid'])
50+
->allowedFilters([
51+
AllowedFilter::exact('owner_id'),
52+
AllowedFilter::custom('*', new AdminServerFilter),
53+
])
5054
->paginate(config()->get('pterodactyl.paginate.admin.servers'));
5155

5256
return $this->view->make('admin.servers.index', ['servers' => $servers]);

app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ public function store(StoreTaskRequest $request, Server $server, Schedule $sched
5656
);
5757
}
5858

59-
$lastTask = $schedule->tasks->last();
59+
/** @var \Pterodactyl\Models\Task|null $lastTask */
60+
$lastTask = $schedule->tasks()->orderByDesc('sequence_id')->first();
6061

6162
/** @var \Pterodactyl\Models\Task $task */
6263
$task = $this->repository->create([
@@ -102,13 +103,16 @@ public function update(StoreTaskRequest $request, Server $server, Schedule $sche
102103
}
103104

104105
/**
105-
* Determines if a user can delete the task for a given server.
106+
* Delete a given task for a schedule. If there are subsequent tasks stored in the database
107+
* for this schedule their sequence IDs are decremented properly.
106108
*
107109
* @param \Pterodactyl\Http\Requests\Api\Client\ClientApiRequest $request
108110
* @param \Pterodactyl\Models\Server $server
109111
* @param \Pterodactyl\Models\Schedule $schedule
110112
* @param \Pterodactyl\Models\Task $task
111113
* @return \Illuminate\Http\JsonResponse
114+
*
115+
* @throws \Exception
112116
*/
113117
public function delete(ClientApiRequest $request, Server $server, Schedule $schedule, Task $task)
114118
{
@@ -120,8 +124,12 @@ public function delete(ClientApiRequest $request, Server $server, Schedule $sche
120124
throw new HttpForbiddenException('You do not have permission to perform this action.');
121125
}
122126

123-
$this->repository->delete($task->id);
127+
$schedule->tasks()->where('sequence_id', '>', $task->sequence_id)->update([
128+
'sequence_id' => $schedule->tasks()->getConnection()->raw('(sequence_id - 1)'),
129+
]);
130+
131+
$task->delete();
124132

125-
return JsonResponse::create(null, Response::HTTP_NO_CONTENT);
133+
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
126134
}
127135
}

0 commit comments

Comments
 (0)