Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
75b5908
fix!: use `POST` instead of `DELETE` when disabling 2FA
matthewpi Oct 24, 2024
15e9e13
ci: use `GITHUB_TOKEN` for authenticating against ghcr.io
matthewpi Oct 24, 2024
a366785
Update CHANGELOG.md
matthewpi Oct 27, 2024
4152150
chore: update composer dependencies
matthewpi Nov 15, 2024
4785c5d
Update CHANGELOG.md
matthewpi Nov 15, 2024
79dc5ee
chore: update to php 8.2 minimum
matthewpi Nov 15, 2024
07eb320
ci: switch to `ubuntu-24.04` runner
matthewpi Jun 12, 2025
24c82b0
fix: add additional input validation
matthewpi Jun 16, 2025
ac16af6
Update CHANGELOG.md
matthewpi Jun 18, 2025
bd9fe10
ci(release): bump version
Jun 18, 2025
5600854
Initial commit
yowaitaminute Jun 6, 2025
86c6a3d
first commit
yowaitaminute Jun 6, 2025
62083fe
update
yowaitaminute Jun 7, 2025
d0251b3
update
yowaitaminute Jun 8, 2025
4767301
Update
yowaitaminute Jun 9, 2025
2d1081c
Clean up Formik helper usage in EditHookModal field updates.
yowaitaminute Jun 9, 2025
35feebb
Fix UI value binding in Hook form for action config.
yowaitaminute Jun 9, 2025
c1e8948
Fix action label rendering bug in dropdown display.
yowaitaminute Jun 9, 2025
b93335a
Convert trigger/action relationship creation to separate handlers.
yowaitaminute Jun 18, 2025
32f0c24
Convert trigger/action relationship creation to separate handlers.
yowaitaminute Jun 9, 2025
a970818
Refactor schedule ID config to use proper select component input.
yowaitaminute Jun 9, 2025
253b653
Cleanup HookExecutionService constructor and switch logic.
yowaitaminute Jun 9, 2025
928aa40
Fix edit modal close behavior when hook config changes.
yowaitaminute Jun 9, 2025
bb7d1e1
Ensure action config renders even when values are null.
yowaitaminute Jun 9, 2025
37ac135
Bind hook selection events in UI more consistently.
yowaitaminute Jun 9, 2025
cfa8017
Improve hook creation defaults for users with no existing config.
yowaitaminute Jun 9, 2025
4adc4a2
Allow empty state in dropdowns and handle unselected values.
yowaitaminute Jun 9, 2025
2cce2d5
Fix hook config rendering for optional fields in action schema.
yowaitaminute Jun 9, 2025
3de9872
Add dynamic error mapping for nested hook config fields.
yowaitaminute Jun 9, 2025
72a7487
Improve accessibility of dropdown fields in hook editor.
yowaitaminute Jun 9, 2025
1f4891c
Fix UI layout spacing for dropdowns in EditHookModal.
yowaitaminute Jun 9, 2025
21d3e5d
Update hook creation modal to support optional actions.
yowaitaminute Jun 9, 2025
4b449ef
Ensure action schema renders with labels and default values.
yowaitaminute Jun 9, 2025
170a173
Fix label binding for action dropdowns in dynamic form fields.
yowaitaminute Jun 9, 2025
87dc164
Improve HookRow display logic for null or missing actions.
yowaitaminute Jun 9, 2025
9a05234
Add missing options to dropdown select in hook config UI.
yowaitaminute Jun 9, 2025
4016631
Reorganize EditHookModal logic to reduce prop drilling.
yowaitaminute Jun 9, 2025
a0fb6d4
Add early returns for missing hook actions in execution service.
yowaitaminute Jun 9, 2025
6cacdec
Ensure trigger definitions are set before rendering EditHookModal.
yowaitaminute Jun 9, 2025
cd9be27
Fix schedule dropdown value population from existing hook config.
yowaitaminute Jun 9, 2025
59e3962
Fix display logic for hook action dropdowns; improve field naming.
yowaitaminute Jun 9, 2025
5ce5f26
Hook form now shows contextual descriptions based on selected action.
yowaitaminute Jun 9, 2025
bf13ac3
Add support for schedule input types in hook config form.
yowaitaminute Jun 9, 2025
914a5b8
Default to empty option in dropdowns for better UX.
yowaitaminute Jun 9, 2025
d9b97fd
Make hook rows clickable and render triggers/actions more clearly.
yowaitaminute Jun 10, 2025
a7a3153
Fix server hook lookup using UUID in Remote HookController.
yowaitaminute Jun 10, 2025
e515da9
Fix inconsistent type hints in Hook services and validators.
yowaitaminute Jun 10, 2025
aae2a73
Add transformer based hook syncing with Fractal integration.
yowaitaminute Jun 10, 2025
7ed0e08
Add transformer based hook syncing with Fractal integration.
yowaitaminute Jun 10, 2025
6339ddf
Update trigger regex validation to use clearer error messages.
yowaitaminute Jun 10, 2025
c8e4f80
Add transformer based hook syncing with Fractal integration.
yowaitaminute Jun 10, 2025
906cffc
Simplify HookUpdateService error merging and validation exceptions.
yowaitaminute Jun 10, 2025
7640ef5
Fix broken bindings in dropdowns for actions and triggers.
yowaitaminute Jun 10, 2025
f646611
Add null checks in HookRow and improve rendering safety.
yowaitaminute Jun 10, 2025
47c05fc
Clean up error handling for hook creation; show user friendly messages.
yowaitaminute Jun 10, 2025
54ba189
Improve hook config form layout and bind selected action values.
yowaitaminute Jun 10, 2025
3e67d77
Enable UI triggered hook execution with schedule lookup and validation.
yowaitaminute Jun 11, 2025
b43e706
Fix action and trigger schema keys in API request validation and UI.
yowaitaminute Jun 11, 2025
242c26a
Enhance hook execution with better validation and exception handling.…
yowaitaminute Jun 11, 2025
c76f5f2
Introduce custom exceptions for hook actions and triggers. Also added…
yowaitaminute Jun 11, 2025
ddeac4d
Refactor EditHookModal to support dynamic dropdowns and better valida…
yowaitaminute Jun 11, 2025
7828c98
Add support for executing and deleting hooks in the UI. Updated EditH…
yowaitaminute Jun 11, 2025
4c9368a
Remove unused event listeners and old stats tracking logic.
yowaitaminute Jun 11, 2025
9fa7664
Split and clean up Hook execution logic into job-based architecture a…
yowaitaminute Jun 12, 2025
c3e05c7
Restructure HookSyncService and HookUpdateService to include validati…
yowaitaminute Jun 12, 2025
4758f78
Fix broken route order in api-remote.php for hooks and install endpoi…
yowaitaminute Jun 13, 2025
1dd3f9f
Fix hook lookup in HookController::index by resolving server ID via U…
yowaitaminute Jun 13, 2025
a603912
Dispatch SyncHooksJob after hook deletion to synchronize remote state.
yowaitaminute Jun 13, 2025
965f095
Restore HookSyncService to use Fractal transformer and include trigge…
yowaitaminute Jun 13, 2025
e41788f
Re-enable SyncHooksJob exception logging for debugging purposes.
yowaitaminute Jun 13, 2025
976c708
Simplify SyncHooksJob error handling and remove logging noise.
yowaitaminute Jun 13, 2025
60ea7dc
Add DaemonHookRepository and refactor HookSyncService to send hooks t…
yowaitaminute Jun 17, 2025
2a19e04
Add HookExecutionService and validation for remote hook triggering. I…
yowaitaminute Jun 17, 2025
f322453
Remove debug logging and correct CPU usage option in TriggerDefinitio…
yowaitaminute Jun 17, 2025
8b3b1f9
Implement rate limiting for discord_webhook and send_email actions in…
yowaitaminute Jun 17, 2025
eb88754
Merge branch '1.0-develop' into lukas
Linux123123 Jun 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ 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.11

### Fixed

* Fixed CVE-2025-49132

## v1.11.10

### BREAKING
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@ and there are plenty more games available provided by the community. Some of the
Pterodactyl® Copyright © 2015 - 2022 Dane Everitt and contributors.

Code released under the [MIT License](./LICENSE.md).
# Pterodactyl-S
21 changes: 21 additions & 0 deletions app/Contracts/Repository/HookRepositoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Pterodactyl\Contracts\Repository;

use Pterodactyl\Models\Hook;
use Illuminate\Support\Collection;

interface HookRepositoryInterface extends RepositoryInterface
{
/**
* Return all the hooks for a given server.
*/
public function findServerHooks(int $server): Collection;

/**
* Return a hook model with the associated trigger and action as a relationship.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getHookWithTriggerAndAction(int $schedule): Hook;
}
19 changes: 19 additions & 0 deletions app/Exceptions/ActionExecutionException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Pterodactyl\Exceptions;

class ActionExecutionException extends DisplayException
{
protected array $errors;

public function __construct(string $message, array $errors, \Throwable $previous = null)
{
parent::__construct($message, $previous);
$this->errors = $errors;
}

public function getErrors(): array
{
return $this->errors;
}
}
19 changes: 19 additions & 0 deletions app/Exceptions/HookActionValidationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Pterodactyl\Exceptions;

class HookActionValidationException extends DisplayException
{
protected array $errors;

public function __construct(string $message, array $errors, \Throwable $previous = null)
{
parent::__construct($message, $previous);
$this->errors = $errors;
}

public function getErrors(): array
{
return $this->errors;
}
}
19 changes: 19 additions & 0 deletions app/Exceptions/HookTriggerValidationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Pterodactyl\Exceptions;

class HookTriggerValidationException extends DisplayException
{
protected array $errors;

public function __construct(string $message, array $errors, \Throwable $previous = null)
{
parent::__construct($message, $previous);
$this->errors = $errors;
}

public function getErrors(): array
{
return $this->errors;
}
}
19 changes: 19 additions & 0 deletions app/Exceptions/TriggerExecutionException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Pterodactyl\Exceptions;

class TriggerExecutionException extends DisplayException
{
protected array $errors;

public function __construct(string $message, array $errors, \Throwable $previous = null)
{
parent::__construct($message, $previous);
$this->errors = $errors;
}

public function getErrors(): array
{
return $this->errors;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Pterodactyl\Http\Controllers\Api\Client\Servers;

use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Http\Requests\Api\Client\Servers\Hooks\ViewHooksRequest;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\ActionDefinition;

class ActionDefinitionController extends Controller
{
public function index(ViewHooksRequest $request, Server $server) {
return response()->json(["data"=>ActionDefinition::all()]);
}

}
95 changes: 95 additions & 0 deletions app/Http/Controllers/Api/Client/Servers/HookController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace Pterodactyl\Http\Controllers\Api\Client\Servers;

use Illuminate\Support\Facades\Log;
use Pterodactyl\Exceptions\HookActionValidationException;
use Pterodactyl\Exceptions\HookTriggerValidationException;
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Http\Requests\Api\Client\Servers\Hooks\DeleteHookRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Hooks\StoreHookRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Hooks\TriggerHookRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Hooks\UpdateHookRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Hooks\ViewHooksRequest;
use Pterodactyl\Models\Hook;
use Pterodactyl\Models\Server;
use Pterodactyl\Repositories\Eloquent\HookRepository;
use Pterodactyl\Services\Hooks\HookCreationService;
use Pterodactyl\Services\Hooks\HookDeletionService;
use Pterodactyl\Services\Hooks\HookExecutionService;
use Pterodactyl\Services\Hooks\HookUpdateService;
use Pterodactyl\Transformers\Api\Client\HookTransformer;

class HookController extends ClientApiController
{
public function __construct(
private HookCreationService $creationService,
private HookDeletionService $deletionService,
private HookUpdateService $updateService,
private HookExecutionService $executionService,
private HookRepository $repository,
) {
parent::__construct();
}
public function index(ViewHooksRequest $request, Server $server): array {
return $this->fractal->collection(
$this->repository->findServerHooks($server->id)
)->transformWith($this->getTransformer(HookTransformer::class))->toArray();
}

public function view(ViewHooksRequest $request, Server $server) {
return response()->json([
"data"=> Hook::where('server_id', $server->id)->get()
]);
}

public function execute(TriggerHookRequest $request, Server $server, Hook $hook) {
$this->executionService->handle($hook);
return response()->json([
"status" => "success",
]);
}

public function store(StoreHookRequest $request, Server $server) {
$validated = $request->validated();
try {
$hook = $this->creationService->handle($server, $validated);
return $this->fractal->item(
$hook
)->transformWith($this->getTransformer(HookTransformer::class))->toArray();
} catch (HookTriggerValidationException | HookActionValidationException $e) {
return response()->json([
'message' => $e instanceof HookTriggerValidationException
? 'One or more triggers are invalid'
: 'One or more actions are invalid',
'errors' => $e->getErrors(),
], 422);
}
}

public function update(UpdateHookRequest $request, Server $server, Hook $hook) {
$validated = $request->validated();
try {
$hook = $this->updateService->handle($hook, $validated);
return $this->fractal->item(
$hook->fresh(['trigger', 'action'])
)->transformWith($this->getTransformer(HookTransformer::class))->toArray();
} catch (HookTriggerValidationException $e) {
return response()->json([
'message' => 'One or more triggers are invalid',
'errors' => $e->getErrors(),
], 422);
} catch (HookActionValidationException $e) {
return response()->json([
'message' => 'One or more actions are invalid',
'errors' => $e->getErrors(),
], 422);
}
}

public function delete(DeleteHookRequest $request, Server $server, Hook $hook) {
$this->deletionService->handle($hook);
return response()->noContent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Pterodactyl\Http\Controllers\Api\Client\Servers;

use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Http\Requests\Api\Client\Servers\Hooks\ViewHooksRequest;
use Pterodactyl\Models\Hook;
use Pterodactyl\Models\Server;
use Pterodactyl\Models\TriggerDefinition;

class TriggerDefinitionController extends Controller
{
public function index(ViewHooksRequest $request, Server $server) {
return response()->json(["data"=>TriggerDefinition::all()]);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;

use Carbon\CarbonImmutable;
use Illuminate\Support\Facades\Log;
use Pterodactyl\Models\Server;
use Illuminate\Http\JsonResponse;
use Pterodactyl\Models\Permission;
Expand Down
46 changes: 46 additions & 0 deletions app/Http/Controllers/Api/Remote/Servers/HookController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace Pterodactyl\Http\Controllers\Api\Remote\Servers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Pterodactyl\Models\Hook;
use Pterodactyl\Repositories\Eloquent\HookRepository;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Services\Hooks\HookExecutionService;
use Pterodactyl\Transformers\Api\Application\HookTransformer;
use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController;

class HookController extends ApplicationApiController
{
/**
* HookController constructor.
*/
public function __construct(
private HookRepository $hookRepository,
private HookExecutionService $executionService,
private ServerRepository $repository
)
{
parent::__construct();
}

/**
* Return all the hooks that currently exist on the server.
*/
public function index(Request $request, $uuid): array
{
$server = $this->repository->getByUuid($uuid);

return $this->fractal->collection($this->hookRepository->findServerHooks($server->id))
->transformWith($this->getTransformer(HookTransformer::class))
->toArray();
}

public function trigger(Request $request, $uuid): JsonResponse
{
$this->executionService->handle(Hook::where('id', '=', $request->input('id'))->first());
return response()->json(["status"=>"success"]);
}
}
29 changes: 29 additions & 0 deletions app/Http/Requests/Api/Client/Servers/Hooks/DeleteHookRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Pterodactyl\Http\Requests\Api\Client\Servers\Hooks;

use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
use Pterodactyl\Models\Permission;

class DeleteHookRequest extends ClientApiRequest
{
/**
* Determine if the user is authorized to make this request.
*/

public function permission(): string
{
// ACTION_HOOKS_READ,ACTION_HOOKS_CREATE,ACTION_HOOKS_UPDATE,ACTION_HOOKS_DELETE
return Permission::ACTION_HOOKS_DELETE;
}

/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [];
}
}
33 changes: 33 additions & 0 deletions app/Http/Requests/Api/Client/Servers/Hooks/StoreHookRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Pterodactyl\Http\Requests\Api\Client\Servers\Hooks;

use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
use Pterodactyl\Models\Permission;

class StoreHookRequest extends ClientApiRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function permission(): string
{
// ACTION_HOOKS_READ,ACTION_HOOKS_CREATE,ACTION_HOOKS_UPDATE,ACTION_HOOKS_DELETE
return Permission::ACTION_HOOKS_CREATE;
}

/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => 'required|string',
'enabled' => 'nullable|boolean',
'trigger' => 'required|array',
'action' => 'required|array',
];
}
}
Loading
Loading