Skip to content

Commit

Permalink
Merge branch '1.0-develop' into fix/4897
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewpi authored May 4, 2024
2 parents 7ce0254 + 7bfc265 commit 18c03e1
Show file tree
Hide file tree
Showing 16 changed files with 95 additions and 38 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ 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.11.6

### Changed

* Better node ownership checks for internal backup endpoints
* Improved validation rules on `docker_image` fields to prevent invalid inputs

### Fixed

* Multiple XSS vulnerabilities in the admin area ([GHSA-384w-wffr-x63q](https://github.com/pterodactyl/panel/security/advisories/GHSA-384w-wffr-x63q))

## v1.11.5
### Fixed
* Rust egg using the wrong Docker image, breaking Rust modding frameworks.
Expand Down
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ Stop settling for less. Make game servers a first class citizen on your platform
I would like to extend my sincere thanks to the following sponsors for helping fund Pterodactyl's development.
[Interested in becoming a sponsor?](https://github.com/sponsors/matthewpi)

| Company | About |
|-----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [**Aussie Server Hosts**](https://aussieserverhosts.com/) | No frills Australian Owned and operated High Performance Server hosting for some of the most demanding games serving Australia and New Zealand. |
| [**BisectHosting**](https://www.bisecthosting.com/) | BisectHosting provides Minecraft, Valheim and other server hosting services with the highest reliability and lightning fast support since 2012. |
| [**MineStrator**](https://minestrator.com/) | Looking for the most highend French hosting company for your minecraft server? More than 24,000 members on our discord trust us. Give us a try! |
| [**VibeGAMES**](https://vibegames.net/) | VibeGAMES is a game server provider that specializes in DDOS protection for the games we offer. We have multiple locations in the US, Brazil, France, Germany, Singapore, Australia and South Africa. |
| [**HostEZ**](https://hostez.io) | US & EU Rust & Minecraft Hosting. DDoS Protected bare metal, VPS and colocation with low latency, high uptime and maximum availability. EZ! |
| [**Blueprint**](https://blueprint.zip/?pterodactyl=true) | Create and install Pterodactyl addons and themes with the growing Blueprint framework - the package-manager for Pterodactyl. Use multiple modifications at once without worrying about conflicts and make use of the large extension ecosystem. |
| Company | About |
|--------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [**Aussie Server Hosts**](https://aussieserverhosts.com/) | No frills Australian Owned and operated High Performance Server hosting for some of the most demanding games serving Australia and New Zealand. |
| [**BisectHosting**](https://www.bisecthosting.com/) | BisectHosting provides Minecraft, Valheim and other server hosting services with the highest reliability and lightning fast support since 2012. |
| [**MineStrator**](https://minestrator.com/) | Looking for the most highend French hosting company for your minecraft server? More than 24,000 members on our discord trust us. Give us a try! |
| [**VibeGAMES**](https://vibegames.net/) | VibeGAMES is a game server provider that specializes in DDOS protection for the games we offer. We have multiple locations in the US, Brazil, France, Germany, Singapore, Australia and South Africa. |
| [**HostEZ**](https://hostez.io) | US & EU Rust & Minecraft Hosting. DDoS Protected bare metal, VPS and colocation with low latency, high uptime and maximum availability. EZ! |
| [**Blueprint**](https://blueprint.zip/?pterodactyl=true) | Create and install Pterodactyl addons and themes with the growing Blueprint framework - the package-manager for Pterodactyl. Use multiple modifications at once without worrying about conflicts and make use of the large extension ecosystem. |
| [**indifferent broccoli**](https://indifferentbroccoli.com/) | indifferent broccoli is a game server hosting and rental company. With us, you get top-notch computer power for your gaming sessions. We destroy lag, latency, and complexity--letting you focus on the fun stuff. |

### Supported Games

Expand Down
1 change: 0 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ The following versions of Pterodactyl are receiving active support and maintenan

| Panel | Daemon | Supported |
|--------|--------------|--------------------|
| 1.10.x | [email protected] | :white_check_mark: |
| 1.11.x | [email protected] | :white_check_mark: |
| 0.7.x | [email protected] | :x: |

Expand Down
4 changes: 2 additions & 2 deletions app/Http/Controllers/Admin/Nests/EggVariableController.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public function update(EggVariableFormRequest $request, Egg $egg, EggVariable $v
{
$this->updateService->handle($variable, $request->normalize());
$this->alert->success(trans('admin/nests.variables.notices.variable_updated', [
'variable' => $variable->name,
'variable' => htmlspecialchars($variable->name),
]))->flash();

return redirect()->route('admin.nests.egg.variables', $egg->id);
Expand All @@ -82,7 +82,7 @@ public function destroy(int $egg, EggVariable $variable): RedirectResponse
{
$this->variableRepository->delete($variable->id);
$this->alert->success(trans('admin/nests.variables.notices.variable_deleted', [
'variable' => $variable->name,
'variable' => htmlspecialchars($variable->name),
]))->flash();

return redirect()->route('admin.nests.egg.variables', $egg);
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Admin/Nests/NestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function create(): View
public function store(StoreNestFormRequest $request): RedirectResponse
{
$nest = $this->nestCreationService->handle($request->normalize());
$this->alert->success(trans('admin/nests.notices.created', ['name' => $nest->name]))->flash();
$this->alert->success(trans('admin/nests.notices.created', ['name' => htmlspecialchars($nest->name)]))->flash();

return redirect()->route('admin.nests.view', $nest->id);
}
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Admin/NodesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public function allocationRemoveBlock(Request $request, int $node): RedirectResp
['ip', '=', $request->input('ip')],
]);

$this->alert->success(trans('admin/node.notices.unallocated_deleted', ['ip' => $request->input('ip')]))
$this->alert->success(trans('admin/node.notices.unallocated_deleted', ['ip' => htmlspecialchars($request->input('ip'))]))
->flash();

return redirect()->route('admin.nodes.view.allocation', $node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,32 @@ public function __construct(private BackupManager $backupManager)
*/
public function __invoke(Request $request, string $backup): JsonResponse
{
// Get the node associated with the request.
/** @var \Pterodactyl\Models\Node $node */
$node = $request->attributes->get('node');

// Get the size query parameter.
$size = (int) $request->query('size');
if (empty($size)) {
throw new BadRequestHttpException('A non-empty "size" query parameter must be provided.');
}

/** @var \Pterodactyl\Models\Backup $backup */
$backup = Backup::query()->where('uuid', $backup)->firstOrFail();
/** @var \Pterodactyl\Models\Backup $model */
$model = Backup::query()
->where('uuid', $backup)
->firstOrFail();

// Check that the backup is "owned" by the node making the request. This avoids other nodes
// from messing with backups that they don't own.
/** @var \Pterodactyl\Models\Server $server */
$server = $model->server;
if ($server->node_id !== $node->id) {
throw new HttpForbiddenException('You do not have permission to access that backup.');
}

// Prevent backups that have already been completed from trying to
// be uploaded again.
if (!is_null($backup->completed_at)) {
if (!is_null($model->completed_at)) {
throw new ConflictHttpException('This backup is already in a completed state.');
}

Expand All @@ -54,7 +68,7 @@ public function __invoke(Request $request, string $backup): JsonResponse
}

// The path where backup will be uploaded to
$path = sprintf('%s/%s.tar.gz', $backup->server->uuid, $backup->uuid);
$path = sprintf('%s/%s.tar.gz', $model->server->uuid, $model->uuid);

// Get the S3 client
$client = $adapter->getClient();
Expand Down Expand Up @@ -92,7 +106,7 @@ public function __invoke(Request $request, string $backup): JsonResponse
}

// Set the upload_id on the backup in the database.
$backup->update(['upload_id' => $params['UploadId']]);
$model->update(['upload_id' => $params['UploadId']]);

return new JsonResponse([
'parts' => $parts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,22 @@ public function __construct(private BackupManager $backupManager)
*/
public function index(ReportBackupCompleteRequest $request, string $backup): JsonResponse
{
// Get the node associated with the request.
/** @var \Pterodactyl\Models\Node $node */
$node = $request->attributes->get('node');

/** @var \Pterodactyl\Models\Backup $model */
$model = Backup::query()->where('uuid', $backup)->firstOrFail();
$model = Backup::query()
->where('uuid', $backup)
->firstOrFail();

// Check that the backup is "owned" by the node making the request. This avoids other nodes
// from messing with backups that they don't own.
/** @var \Pterodactyl\Models\Server $server */
$server = $model->server;
if ($server->node_id !== $node->id) {
throw new HttpForbiddenException('You do not have permission to access that backup.');
}

if ($model->is_successful) {
throw new BadRequestHttpException('Cannot update the status of a backup that is already marked as completed.');
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Requests/Admin/Egg/EggFormRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public function rules(): array
$rules = [
'name' => 'required|string|max:191',
'description' => 'nullable|string',
'docker_images' => 'required|string',
'docker_images' => ['required', 'string', 'regex:/^[\w#\.\/\- ]*\|*[\w\.\/\-:@ ]*$/im'],
'force_outgoing_ip' => 'sometimes|boolean',
'file_denylist' => 'array',
'startup' => 'required|string',
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Requests/Admin/Nest/StoreNestFormRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class StoreNestFormRequest extends AdminFormRequest
public function rules(): array
{
return [
'name' => 'required|string|min:1|max:191',
'name' => 'required|string|min:1|max:191|regex:/^[\w\- ]+$/',
'description' => 'string|nullable',
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function rules(): array
Assert::isInstanceOf($server, Server::class);

return [
'docker_image' => ['required', 'string', Rule::in(array_values($server->egg->docker_images))],
'docker_image' => ['required', 'string', 'max:191', 'regex:/^[\w#\.\/\- ]*\|*[\w\.\/\-:@ ]*$/', Rule::in(array_values($server->egg->docker_images))],
];
}
}
2 changes: 1 addition & 1 deletion app/Models/Egg.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class Egg extends Model
'file_denylist' => 'array|nullable',
'file_denylist.*' => 'string',
'docker_images' => 'required|array|min:1',
'docker_images.*' => 'required|string',
'docker_images.*' => ['required', 'string', 'max:191', 'regex:/^[\w#\.\/\- ]*\|*[\w\.\/\-:@ ]*$/'],
'startup' => 'required|nullable|string',
'config_from' => 'sometimes|bail|nullable|numeric|exists:eggs,id',
'config_stop' => 'required_without:config_from|nullable|string|max:191',
Expand Down
2 changes: 1 addition & 1 deletion app/Models/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class Server extends Model
'egg_id' => 'required|exists:eggs,id',
'startup' => 'required|string',
'skip_scripts' => 'sometimes|boolean',
'image' => 'required|string|max:191',
'image' => ['required', 'string', 'max:191', 'regex:/^[\w\.\/\-:@ ]*$/'],
'database_limit' => 'present|nullable|integer|min:0',
'allocation_limit' => 'sometimes|nullable|integer|min:0',
'backup_limit' => 'present|nullable|integer|min:0',
Expand Down
18 changes: 12 additions & 6 deletions public/themes/pterodactyl/js/admin/new-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ $('#pEggId').on('change', function (event) {
for (let i = 0; i < keys.length; i++) {
let opt = document.createElement('option');
opt.value = images[keys[i]];
opt.innerHTML = keys[i] + " (" + images[keys[i]] + ")";
opt.innerText = keys[i] + " (" + images[keys[i]] + ")";
$('#pDefaultContainer').append(opt);
}

Expand All @@ -109,6 +109,12 @@ $('#pEggId').on('change', function (event) {
),
});

function escapeHtml(str) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}

const variableIds = {};
$('#appendVariablesTo').html('');
$.each(_.get(objectChain, 'variables', []), function (i, item) {
Expand All @@ -117,11 +123,11 @@ $('#pEggId').on('change', function (event) {
let isRequired = (item.required === 1) ? '<span class="label label-danger">Required</span> ' : '';
let dataAppend = ' \
<div class="form-group col-sm-6"> \
<label for="var_ref_' + item.id + '" class="control-label">' + isRequired + item.name + '</label> \
<input type="text" id="var_ref_' + item.id + '" autocomplete="off" name="environment[' + item.env_variable + ']" class="form-control" value="' + item.default_value + '" /> \
<p class="text-muted small">' + item.description + '<br /> \
<strong>Access in Startup:</strong> <code>{{' + item.env_variable + '}}</code><br /> \
<strong>Validation Rules:</strong> <code>' + item.rules + '</code></small></p> \
<label for="var_ref_' + escapeHtml(item.id) + '" class="control-label">' + isRequired + escapeHtml(item.name) + '</label> \
<input type="text" id="var_ref_' + escapeHtml(item.id) + '" autocomplete="off" name="environment[' + escapeHtml(item.env_variable) + ']" class="form-control" value="' + escapeHtml(item.default_value) + '" /> \
<p class="text-muted small">' + escapeHtml(item.description) + '<br /> \
<strong>Access in Startup:</strong> <code>{{' + escapeHtml(item.env_variable) + '}}</code><br /> \
<strong>Validation Rules:</strong> <code>' + escapeHtml(item.rules) + '</code></small></p> \
</div> \
';
$('#appendVariablesTo').append(dataAppend);
Expand Down
10 changes: 8 additions & 2 deletions resources/views/admin/nodes/view/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,20 @@
@section('footer-scripts')
@parent
<script>
function escapeHtml(str) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
(function getInformation() {
$.ajax({
method: 'GET',
url: '/admin/nodes/view/{{ $node->id }}/system-information',
timeout: 5000,
}).done(function (data) {
$('[data-attr="info-version"]').html(data.version);
$('[data-attr="info-system"]').html(data.system.type + ' (' + data.system.arch + ') <code>' + data.system.release + '</code>');
$('[data-attr="info-version"]').html(escapeHtml(data.version));
$('[data-attr="info-system"]').html(escapeHtml(data.system.type) + ' (' + escapeHtml(data.system.arch) + ') <code>' + escapeHtml(data.system.release) + '</code>');
$('[data-attr="info-cpus"]').html(data.system.cpus);
}).fail(function (jqXHR) {
Expand Down
Loading

0 comments on commit 18c03e1

Please sign in to comment.