Compare commits

...

129 Commits

Author SHA1 Message Date
Dane Everitt
d648a63e13
Update i18n to resolve issues rendering unclosed div tags (#5547) 2026-02-01 13:19:41 -08:00
Dawid Jaworski
a1f7d287ac
feat: Auth Required modal for hytale (#5526)
This PR add modal related to requiring auth to download or update hytale
server.

Egg feature to use: `hytale_oauth`

Preview:


https://github.com/user-attachments/assets/77bd4f16-ba5b-4652-88b1-7abfd4ab45b8
2026-01-12 12:22:49 -06:00
cesarmr-github
676b64562f
Remove <strong> tags in admin area notifications (#5520) 2026-01-10 16:39:10 -08:00
AndyIsHereBoi
232ccce061
Update node/view/servers title to be consistent (#5514) 2026-01-10 10:02:54 -08:00
Sam Schumacher
d4580076c2
Cast presigned URL lifespan to integer (#5515) 2026-01-10 10:01:57 -08:00
DaneEveritt
5f1bfd109d
Don't include v in the version identifier 2026-01-05 17:18:54 -08:00
Всеволод Мельник
09caa0d499
Merge commit from fork
* Add throttling to resource creation endpoints

* Fix middleware registration for the throttlers

* Lock the server's resource models when adding new ones

* Throttle subusers even more

---------

Co-authored-by: DaneEveritt <dane@daneeveritt.com>
2026-01-05 16:05:38 -08:00
DaneEveritt
82f22cd7ab
update release.yaml for testing 2026-01-04 17:28:44 -08:00
Gio
3dd206ccf7
Clear allocation notes on server deletion (#5157) 2026-01-04 16:44:46 -08:00
Dane Everitt
5e2e827d48
Update CHANGELOG.md (#5502) 2026-01-04 16:32:01 -08:00
Alan Escarcha
ace4c025e9
Update Docker container for Forge installation script (#5424) 2026-01-04 15:49:24 -08:00
Mackenzie Molloy
238d371352
Feature: Sort Users on Admin/Users by Administrators first (#5098) 2026-01-04 11:12:55 -08:00
Mackenzie Molloy
38b7b4bee8
Cast old() returned value to an Integer (#5163) 2026-01-04 11:12:23 -08:00
Dane Everitt
d2949eabd6
Cleanup issues template (#5490) 2026-01-04 11:08:17 -08:00
Anthony
14d666de65
Update contact email for reporting vulnerabilities (#5489) 2026-01-04 12:31:46 -06:00
Dane Everitt
032bf076d9
Ensure that TOTP tokens cannot be reused (#5481) 2025-12-30 12:27:11 -08:00
Dane Everitt
1570ff2509
Don't render raw HTML returned by the alert bag (#5475)
ref: https://github.com/pterodactyl/panel/security/advisories/GHSA-mgr9-6c2j-jxrq
2025-12-26 18:27:23 -08:00
Dane Everitt
2bd9d8badd
Disconnect SFTP/Websocket when a user is removed as a subuser (#5472) 2025-12-26 17:51:25 -08:00
Dane Everitt
ca4e123c25
Fix missing evt parameter in websocket logic (#5470) 2025-12-26 13:08:06 -08:00
Dane Everitt
1fdaf008b4
don't endlessly poll websocket when disconnected due to suspension (#5464) 2025-12-26 09:51:54 -08:00
cesarmr-github
8c1d1b12a5
Fix admin server manage boxes misalignment when suspending a server (#5461) 2025-12-26 09:51:42 -08:00
Dane Everitt
e9558328dd
Use local certs for webpack serve (#5460) 2025-12-24 17:39:26 -08:00
Dane Everitt
bbb1294267
Support zero-byte file uploads (#5459) 2025-12-24 17:32:53 -08:00
Dane Everitt
a215f6d534
Don't be strict about upload size, so long as it is a positive integer (#5458) 2025-12-24 16:45:48 -08:00
Dane Everitt
895adb6e6f
Ensure that a node description can be set, add additional test coverage (#5457) 2025-12-24 16:43:00 -08:00
Dane Everitt
0917e60a3b
Return correct error message when deleting self, add test coverage (#5456) 2025-12-24 16:13:31 -08:00
Sergey Serpichenko
a7c1882edf
FIX: Renamed 'batch_uuid' field to 'batch' in ActivityLogService (#5396)
The field was renamed to match the column name in the database and to maintain consistency across the codebase.
2025-12-24 14:27:38 -08:00
Dane Everitt
4b97363d35
Update build workflows (#5449) 2025-12-20 16:43:23 -08:00
Dane Everitt
ab093344e7
Don't delete the initial content when using "Ctrl+Z" to undo (#5448)
Resolves https://github.com/pterodactyl/panel/issues/5263
2025-12-20 16:38:10 -08:00
Dane Everitt
f1ea7ec90d
Load IBM Plex Sans from code and export as part of bundle (#5447)
Removes the need to load any external resources for fonts. Resolves https://github.com/pterodactyl/panel/issues/5343
2025-12-20 16:37:54 -08:00
Anthony
8c62e90143
Fix sponsor link in README.md 2025-12-20 18:03:15 -06:00
Anthony
3a5e69ddd7
Update FUNDING.yml 2025-12-20 17:56:13 -06:00
Dane Everitt
a264791fd4
Update PHP and JS dependencies to latest versions and modernize codebase (#5446) 2025-12-20 15:55:13 -08:00
Fallen_Breath
9b703fb40f
fix: timezone issue in Schedule::getNextRunDate (#5381) 2025-11-08 23:32:06 -07:00
Matthew Penner
01fd763fe9
fix: add additional input validation
Signed-off-by: Matthew Penner <me@matthewp.io>
2025-06-18 12:21:26 -06:00
Daniel Barton
370820a477
docker: switch to PHP 8.3 (#5173) 2025-06-13 11:07:46 -06:00
Matthew Penner
30af8e6220
ci: switch to ubuntu-24.04 runner
Signed-off-by: Matthew Penner <me@matthewp.io>
2025-06-12 12:03:19 -06:00
Red Banana
043c02c69c
eggs: update Ark Survival Evolved (#5361) 2025-06-12 11:55:25 -06:00
Daniel Barton
79d99c4ed5
chore: update link to additional eggs in README (#5316) 2025-03-23 19:18:56 -06:00
Matthew Penner
81bccc4645
chore: allow overriding Laravel storage path using $APP_STORAGE_PATH
Signed-off-by: Matthew Penner <me@matthewp.io>
2025-03-10 00:56:05 -06:00
Matthew Penner
0fa09a675a
nix: add yarn to devShell
Signed-off-by: Matthew Penner <me@matthewp.io>
2025-03-09 19:10:08 -06:00
Matthew Penner
871ef0c564
fix: EnvironmentWriterTrait not allowing null values
Fixes https://github.com/pterodactyl/panel/issues/5108

Signed-off-by: Matthew Penner <me@matthewp.io>
2025-02-14 13:22:59 -07:00
Matthew Penner
bc07f8e1b1
nix: update flake.lock
Flake lock file updates:

• Updated input 'flake-parts':
    'github:hercules-ci/flake-parts/b905f6fc23a9051a6e1b741e1438dbfc0634c6de?narHash=sha256-%2Bhu54pAoLDEZT9pjHlqL9DNzWz0NbUn8NEAHP7PQPzU%3D' (2025-01-06)
  → 'github:hercules-ci/flake-parts/32ea77a06711b758da0ad9bd6a844c5740a87abd?narHash=sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm%2BzmZ7vxbJdo%3D' (2025-02-01)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/130595eba61081acde9001f43de3248d8888ac4a?narHash=sha256-Xb8mke6UCYjge9kPR9o4P1nVrhk7QBbKv3xQ9cj7h2s%3D' (2025-01-10)
  → 'github:NixOS/nixpkgs/2ff53fe64443980e139eaa286017f53f88336dd0?narHash=sha256-%2B/bYK3DbPxMIvSL4zArkMX0LQvS7rzBKXnDXLfKyRVc%3D' (2025-02-13)
2025-02-14 13:21:00 -07:00
Matthew Penner
d1dd5b1f02
fix: db schema dump not importing on older MariaDB versions
Signed-off-by: Matthew Penner <me@matthewp.io>
2025-02-14 13:20:40 -07:00
Matthew Penner
9cac00cd55
nix: update flake.lock
Flake lock file updates:

• Updated input 'flake-parts':
    'github:hercules-ci/flake-parts/bcef6817a8b2aa20a5a6dbb19b43e63c5bf8619a?narHash=sha256-HO4zgY0ekfwO5bX0QH/3kJ/h4KvUDFZg8YpkNwIbg1U%3D' (2024-09-12)
  → 'github:hercules-ci/flake-parts/b905f6fc23a9051a6e1b741e1438dbfc0634c6de?narHash=sha256-%2Bhu54pAoLDEZT9pjHlqL9DNzWz0NbUn8NEAHP7PQPzU%3D' (2025-01-06)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/99dc8785f6a0adac95f5e2ab05cc2e1bf666d172?narHash=sha256-gI9kkaH0ZjakJOKrdjaI/VbaMEo9qBbSUl93DnU7f4c%3D' (2024-09-16)
  → 'github:NixOS/nixpkgs/130595eba61081acde9001f43de3248d8888ac4a?narHash=sha256-Xb8mke6UCYjge9kPR9o4P1nVrhk7QBbKv3xQ9cj7h2s%3D' (2025-01-10)
2025-01-12 14:56:50 -07:00
Matthew Penner
90ae588721
Update CHANGELOG.md
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-11-14 19:26:24 -07:00
Matthew Penner
955dd2796d
chore: update laravel 11.28.1 -> 11.31.0
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-11-14 19:03:51 -07:00
Matthew Penner
de3b1efb69
Update CHANGELOG.md
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-10-27 13:50:37 -06:00
Matthew Penner
706db62c64
ci: use GITHUB_TOKEN for authenticating against ghcr.io
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-10-24 12:04:30 -06:00
Matthew Penner
caab056256
fix: TwoFactorControllerTest, again
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-10-24 11:42:25 -06:00
Matthew Penner
abd36ad982
fix: TwoFactorControllerTest
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-10-24 11:36:19 -06:00
Matthew Penner
1d056c1652
Update CHANGELOG.md
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-10-24 11:32:43 -06:00
Matthew Penner
8be2b892c3
fix!: use POST instead of DELETE when disabling 2FA
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-10-24 11:27:42 -06:00
Matthew Penner
8ca098940a
chore: update composer dependencies (#5198)
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-10-21 19:18:20 -06:00
Matthew Penner
fbc24d27ee
Update README.md
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-10-21 19:11:17 -06:00
Matthew Penner
f9efaa86b1
chore: add laravel database schema dump
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-10-21 17:21:12 -06:00
Matthew Penner
acaa6c9ac4
chore: update SPONSORS.md
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-08-28 19:26:39 -06:00
Dawid Jaworski
2dcd39c9c7
fix: nullable egg features (#5135) 2024-07-05 13:22:47 -06:00
Dawid Jaworski
8ae76c3889
feat: add egg features editor in Admin UI (#5130) 2024-06-29 12:59:05 -06:00
Daniel Barton
953575ff5c
fix: remove special handling for ^C stop command (#5132) 2024-06-29 12:31:10 -06:00
Daniel Barton
2611cdf426
egg(teamspeak): add server admin password variable (#5099)
Co-authored-by: Panda260 <Panda260@NeverStopGaming.net>
2024-06-29 12:24:43 -06:00
Daniel Barton
844537df38
fix: CIDR_MAX_BITS restricting to /27 instead of /25 (#5111) 2024-06-29 12:24:10 -06:00
BeastGamer81
466dd61856
chore: fix "Manager User" typo in admin page title (#5114) 2024-06-29 12:22:11 -06:00
Ivy
512cfad6bf
chore: change "Github" to "GitHub" for consistency (#4946) 2024-06-29 12:20:35 -06:00
Matthew Penner
c86564042c
Update README.md
Signed-off-by: Matthew Penner <me@matthewp.io>
2024-06-22 19:18:54 -06:00
Daniel Barton
371c7a671d
api: fix docker_image validation for local images (#5103) 2024-05-21 13:29:31 -06:00
Daniel Barton
37055fe5b4
ui(admin): fix maintenance mode defaulting to the wrong value (#4927) 2024-05-21 13:08:01 -06:00
Matthew Penner
f8dfef04c4
api(remote): fix oops in BackupStatusController, yet again 2024-05-08 18:08:18 -06:00
Matthew Penner
3a0b7d13a9
Update CHANGELOG.md 2024-05-07 22:13:13 -06:00
Matthew Penner
a96d87cf23
Update README.md 2024-05-07 22:12:15 -06:00
Daniel Barton
049ad838e3
egg(minecraft): add Java 21 to image list (#5093) 2024-05-07 21:52:33 -06:00
Daniel Barton
dbd7f31c41
Update Minecraft Eula link (#5090)
Co-authored-by: Alan Escarcha <alanescarcha11@gmail.com>
2024-05-06 18:50:06 -06:00
Daniel Barton
2ffe019675
ui(server): support for decompressing .7z files (#5016) 2024-05-04 17:16:00 -06:00
Matthew Penner
7bfc265a7e
api(remote): fix use of missing node_id field
Fixes #5088
2024-05-04 16:06:13 -06:00
Matthew Penner
b7b2413f3d
Update CHANGELOG.md 2024-05-02 13:37:18 -06:00
Matthew Penner
96e6c66040
Update README.md 2024-05-02 13:22:31 -06:00
Matthew Penner
6dc85c731e
chore: update SECURITY.md
ref; https://github.com/pterodactyl/panel/pull/5074 which targets the
wrong branch
2024-04-16 15:17:36 -06:00
Matthew Penner
0dad4c5a48
ui(admin): better handling of manual HTML rendering 2024-04-11 10:47:00 -06:00
Matthew Penner
b1fa3927c1
api(remote): fix oops in BackupStatusController 2024-04-11 10:42:18 -06:00
Matthew Penner
f671046947
admin: tweaks to validation and rendering 2024-04-10 18:13:25 -06:00
Matthew Penner
319ca683f8
api(remote): ensure requesting node is checked 2024-04-10 17:38:09 -06:00
Matthew Penner
1172d71d31
app: improve docker_image validation 2024-04-10 17:22:29 -06:00
Matthew Penner
2497819ca7
Update README.md 2024-03-16 14:02:07 -06:00
Matthew Penner
787bf34a59
nix: update to php 8.2 2024-03-16 14:01:51 -06:00
Matthew Penner
f0489f677b
Update README.md 2023-12-29 22:09:21 -07:00
Matthew Penner
8abf2d8106
ui(server): fix defaultValue not being used with VariableBox select 2023-10-20 19:30:25 -06:00
Matthew Penner
341eda7855
egg(rust): change ordering of mod frameworks 2023-10-20 19:29:21 -06:00
Matthew Penner
742e352c67
Update CHANGELOG.md 2023-10-12 13:55:53 -06:00
Matthew Penner
a62e8b1a67
egg(rust): use yolk image instead of the deprecated one 2023-10-12 13:54:42 -06:00
Matthew Penner
35159b3715
Update CHANGELOG.md 2023-10-10 13:13:00 -06:00
Matthew Penner
7fa0c26d80
Update README.md 2023-10-02 17:06:05 -06:00
Boy132
5a417e9adb
app(setup): replace mail with sendmail driver (#4750) 2023-08-22 19:18:05 -06:00
Boy132
51cee7688a
app: update prune-backup command description (#4754) 2023-08-22 19:17:18 -06:00
Boy132
67b2d944a6
ui(client): allow MassActionBar to be clicked through (#4753) 2023-08-22 19:12:57 -06:00
Matthew Penner
57d27293d2
github(template): update paste domain (#4757)
Switch from `bin.ptdl.co` to `pteropaste.com`
2023-08-22 15:08:14 -10:00
Boy132
1af200c464 Replace bin.ptdl.co with pteropaste.com
ptdl.co always has cert issues. pteropaste is used anywhere else (e.g. in Discord bot commands)
Also increased the line number to 150.
2023-08-22 15:05:55 -10:00
Matthew Penner
97049f48c3
ui(server): hide sensitive information in copy-on-click notifications (#4761) 2023-08-22 15:04:35 -10:00
Vadym
2d4071ca25 do not show strings with password in notification text 2023-08-22 15:03:47 -10:00
Matthew Penner
5cd2697be3
api(client): allow setting empty server description
Closes https://github.com/pterodactyl/panel/issues/4752
2023-08-22 15:02:56 -10:00
Robert Nisipeanu
85f1259709 fix(4752): check if description field present on request 2023-08-22 15:01:49 -10:00
Matthew Penner
bf1768406b
ui(server): fix permissions check on file manager (#4793) 2023-08-22 15:01:14 -10:00
Boy132
a83058668f only files check for "read-content", check folders for "read"
fixes #4792
2023-08-22 15:00:25 -10:00
Matthew Penner
987440c8ca
app: fix formatting 2023-08-22 18:59:34 -06:00
Matthew Penner
341fa0a52d
docker: fix log directory (#4839) 2023-08-22 14:59:12 -10:00
Michael Parker
aa2f797f6f fix panel log folder
resolves #4838

Fixes an issue with the log symlink as well
2023-08-22 14:57:45 -10:00
Matthew Penner
04d83edd36
app: fix getMySQLTimezoneOffset() truncating seconds
Previously the `getMySQLTimezoneOffset()` function would truncate the
seconds part of a time offset (returning `+9:00` instead of `+9:30`) for
example. This only affects timezones with offsets that contain minutes.

Closes https://github.com/pterodactyl/panel/issues/4821
Superseeds https://github.com/pterodactyl/panel/pull/4827

Co-authored-by: danny6167 <daniel@barteck.com.au>
2023-08-22 18:54:59 -06:00
Matthew Penner
15860613b6
Update README.md 2023-08-22 18:50:11 -06:00
Matthew Penner
3cd15d6f21
ci(docker): skip login on pull requests 2023-07-11 20:52:09 -06:00
Matthew Penner
29783ed240
egg(rust): add support for Carbon
Rebased version of #4734 to 1.0-develop
2023-07-11 20:37:14 -06:00
Matthew Penner
7c8bdfc4d8
Update README.md 2023-06-28 20:23:53 -06:00
Matthew Penner
b23f3114e4
Update README.md 2023-05-12 23:08:43 -06:00
Matthew Penner
8bfcffc477
Update README.md 2023-03-11 14:11:34 -07:00
Matthew Penner
1d38b4f0e2
Laravel 10 (#4706) 2023-02-23 12:30:16 -07:00
Matthew Penner
ad4ddc6300
nix: update flake 2023-02-23 12:24:47 -07:00
Devonte W
b746c3ead1
fix(api/client): add validation for backup request body (#4704) 2023-02-23 12:23:12 -07:00
Devonte W
aea5c474db
fix(resources/api): allow svg xml format (#4705) 2023-02-23 12:19:58 -07:00
Matthew Penner
2a7833ca17
Update README.md 2023-02-06 10:22:21 -07:00
Alex
9b47403e00
egg(rust): add server.queryport option (#4681) 2023-02-04 14:42:04 -07:00
Matthew Penner
43f7c10617
Update CHANGELOG.md 2023-01-27 12:24:55 -07:00
Matthew Penner
866b6df4b0
api(task): ensure sequence_id always starts at 1 2023-01-24 16:19:34 -07:00
Matthew Penner
2b14e46eec
api: fix sequence_id being ignored in server task API
Closes #4434
2023-01-24 15:57:24 -07:00
Matthew Penner
20f23a0b27
db: add uuid column to failed_jobs table
Refer to
<https://laravel.com/docs/8.x/upgrade#failed-jobs-table-batch-support>
for more information regarding this change.

Closes #4652
2023-01-24 14:02:41 -07:00
Matthew Penner
a27ea3d1bc
config(queue): default to redis driver
Updates the default `QUEUE_CONNECTION` value to be `redis`
instead of `sync`.  This can cause problems if users skip
the initial setup or select the prefilled options rather
than the recommended ones.

Closes #4660
2023-01-24 13:48:34 -07:00
Matthew Penner
fbdac5b63f
ui(server): fix reinstall_failed conflict state 2023-01-17 15:21:31 -07:00
Jelco
c74314d2ab
Fix file repository not catching 404 responses (#4637) 2023-01-17 15:12:22 -07:00
Matthew Penner
dd595437e6
Update README.md, fix CI status badge 2023-01-17 15:06:56 -07:00
Boy132
2ed7f1c912
Fix MAIL_FROM_ADDRESS in EmailSettingsCommand (#4648) 2023-01-17 15:01:53 -07:00
Matthew Penner
a2fb319ff5
Update README.md sponsors 2023-01-01 15:26:38 -07:00
Omar Kamel
e43da311fe
api(client): keep existing server description when empty (#4619) 2022-12-14 14:19:45 -07:00
634 changed files with 13486 additions and 10626 deletions

View File

@ -23,7 +23,7 @@ REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
QUEUE_CONNECTION=redis
SESSION_DRIVER=file
HASHIDS_SALT=

View File

@ -47,5 +47,6 @@ module.exports = {
'@typescript-eslint/no-use-before-define': 'warn',
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
'@typescript-eslint/ban-ts-comment': ['error', { 'ts-expect-error': 'allow-with-description' }],
'react/no-unknown-property': ['error', { ignore: ['css'] }],
},
};

2
.github/FUNDING.yml vendored
View File

@ -1 +1 @@
github: [matthewpi]
github: [pterodactyl]

82
.github/ISSUE_TEMPLATE/1-bug-report.yml vendored Normal file
View File

@ -0,0 +1,82 @@
name: Bug Reports
description: For reporting known and reproducible issues with the software.
body:
- type: markdown
attributes:
value: |
Bug reports should only be used for reporting issues with how the software works. For assistance installing this software, as well as debugging issues with dependencies, please use our [Discord server](https://discord.gg/pterodactyl).
- type: textarea
attributes:
label: Current Behavior
description: Please provide a clear & concise description of the issue.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: Please describe what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps to Reproduce
description: Please be as detailed as possible when providing steps to reproduce, failure to provide steps will result in this issue being closed.
validations:
required: true
- type: input
id: panel-version
attributes:
label: Panel Version
description: Version number of your Panel (latest is not a version)
placeholder: 1.4.0
validations:
required: true
- type: input
id: wings-version
attributes:
label: Wings Version
description: Version number of your Wings (latest is not a version)
placeholder: 1.4.2
validations:
required: true
- type: input
id: egg-details
attributes:
label: Games and/or Eggs Affected
description: Please include the specific game(s) or egg(s) you are running into this bug with.
placeholder: Minecraft (Paper), Minecraft (Forge)
- type: input
id: docker-image
attributes:
label: Docker Image
description: The specific Docker image you are using for the game(s) above.
placeholder: ghcr.io/pterodactyl/yolks:java_17
- type: textarea
id: panel-logs
attributes:
label: Error Logs
description: |
Run the following command to collect logs on your system.
Wings: `sudo wings diagnostics`
Panel: `tail -n 150 /var/www/pterodactyl/storage/logs/laravel-$(date +%F).log | nc pteropaste.com 99`
placeholder: "https://pteropaste.com/a1h6z"
render: bash
validations:
required: false
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please [search here](https://github.com/pterodactyl/panel/issues) to see if an issue already exists for your problem.
options:
- label: I have searched the existing issues before opening this issue. I understand that maintainers may close this issue without communication if I have not provided sufficient information.
required: true

18
.github/ISSUE_TEMPLATE/2-approved.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: Pre-Discussed and Approved Topics
description: For topics already previously discussed and approved in the GitHub Discussions section.
body:
- type: markdown
attributes:
value: |
**DO NOT** open a new issue for feature requests _without prior maintainer approval_ and corresponding
thread in the discussions section. You MUST link to the corresponding discussion thread when opening
this feature request issue or it will be closed without further consideration.
- type: textarea
attributes:
label: The Feature Request
- type: input
attributes:
label: GitHub Discussion Link
description: Link to the GitHub Discussions thread where the feature was previously discussed and approved.
validations:
required: true

View File

@ -1,87 +0,0 @@
name: Bug Report
description: Something isn't working quite right in the software.
labels: [not confirmed]
body:
- type: markdown
attributes:
value: |
Bug reports should only be used for reporting issues with how the software works. For assistance installing this software, as well as debugging issues with dependencies, please use our [Discord server](https://discord.gg/pterodactyl).
- type: textarea
attributes:
label: Current Behavior
description: Please provide a clear & concise description of the issue.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: Please describe what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps to Reproduce
description: Please be as detailed as possible when providing steps to reproduce, failure to provide steps will result in this issue being closed.
validations:
required: true
- type: input
id: panel-version
attributes:
label: Panel Version
description: Version number of your Panel (latest is not a version)
placeholder: 1.4.0
validations:
required: true
- type: input
id: wings-version
attributes:
label: Wings Version
description: Version number of your Wings (latest is not a version)
placeholder: 1.4.2
validations:
required: true
- type: input
id: egg-details
attributes:
label: Games and/or Eggs Affected
description: Please include the specific game(s) or egg(s) you are running into this bug with.
placeholder: Minecraft (Paper), Minecraft (Forge)
- type: input
id: docker-image
attributes:
label: Docker Image
description: The specific Docker image you are using for the game(s) above.
placeholder: ghcr.io/pterodactyl/yolks:java_17
- type: textarea
id: panel-logs
attributes:
label: Error Logs
description: |
Run the following command to collect logs on your system.
Wings: `sudo wings diagnostics`
Panel: `tail -n 100 /var/www/pterodactyl/storage/logs/laravel-$(date +%F).log | nc bin.ptdl.co 99`
placeholder: "https://bin.ptdl.co/a1h6z"
render: bash
validations:
required: false
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please [search here](https://github.com/pterodactyl/panel/issues) to see if an issue already exists for your problem.
options:
- label: I have searched the existing issues before opening this issue.
required: true
- label: I have provided all relevant details, including the specific game and Docker images I am using if this issue is related to running a server.
required: true
- label: I have checked in the Discord server and believe this is a bug with the software, and not a configuration issue with my specific system.
required: true

View File

@ -1,8 +1,8 @@
blank_issues_enabled: true
blank_issues_enabled: false
contact_links:
- name: Installation Help
- name: Features, Help, or Questions
url: https://github.com/orgs/pterodactyl/discussions/categories/feature-requests
about: The preferred method for getting help with Pterodactyl or seeking new features for the software.
- name: Discord
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.
about: For quicker support with installations issues or running ideas by the community.

View File

@ -1,32 +0,0 @@
name: Feature Request
description: Suggest a new feature or improvement for the software.
labels: [feature request]
body:
- type: checkboxes
attributes:
label: Is there an existing feature request for this?
description: Please [search here](https://github.com/pterodactyl/panel/issues?q=is%3Aissue) to see if someone else has already suggested this.
options:
- label: I have searched the existing issues before opening this feature request.
required: true
- type: textarea
attributes:
label: Describe the feature you would like to see.
description: "A clear & concise description of the feature you'd like to have added, and what issues it would solve."
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like.
description: "You must explain how you'd like to see this feature implemented. Technical implementation details are not necessary, rather an idea of how you'd like to see this feature used."
validations:
required: true
- type: textarea
attributes:
label: Additional context to this request.
description: "Add any other context or screenshots about the feature request."
validations:
required: false

View File

@ -3,7 +3,7 @@ cd /app
mkdir -p /var/log/panel/logs/ /var/log/supervisord/ /var/log/nginx/ /var/log/php7/ \
&& chmod 777 /var/log/panel/logs/ \
&& ln -s /var/log/panel/logs/ /app/storage/logs/
&& ln -s /app/storage/logs/ /var/log/panel/
## check for .env file and generate app keys if missing
if [ -f /app/var/.env ]; then

View File

@ -1,35 +1,32 @@
name: Build
on:
push:
branches:
- "develop"
- "1.0-develop"
pull_request:
branches:
- "develop"
- "1.0-develop"
jobs:
ui:
name: UI
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
permissions:
contents: read
strategy:
fail-fast: false
matrix:
node-version: [16]
node-version: [ 22 ]
steps:
- name: Code Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
cache: yarn
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build
run: yarn build:production
- run: yarn tsc
- run: yarn lint
- run: yarn build:production

View File

@ -1,24 +1,27 @@
name: Tests
on:
push:
branches:
- "develop"
- "1.0-develop"
pull_request:
branches:
- "develop"
- "1.0-develop"
jobs:
tests:
name: Tests
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
permissions:
contents: read
strategy:
fail-fast: false
matrix:
php: [8.0, 8.1]
database: ["mariadb:10.2", "mysql:8"]
php:
- 8.2
- 8.3
database:
- mariadb:10
- mariadb:11
- mysql:8
- mysql:9
services:
database:
image: ${{ matrix.database }}
@ -27,46 +30,30 @@ jobs:
MYSQL_DATABASE: testing
ports:
- 3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Code Checkout
uses: actions/checkout@v3
- name: Get cache directory
id: composer-cache
- uses: actions/checkout@v4
- id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache
uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-${{ matrix.php }}-
- name: Setup PHP
uses: shivammathur/setup-php@v2
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: bcmath, cli, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
- name: Setup .env
run: cp .env.ci .env
- name: Install dependencies
run: composer install --no-interaction --no-progress --no-suggest --prefer-dist
- name: Unit tests
run: vendor/bin/phpunit --bootstrap vendor/autoload.php tests/Unit
if: ${{ always() }}
- run: cp .env.ci .env
- run: composer install --no-interaction --no-progress --no-suggest --prefer-dist
- run: vendor/bin/php-cs-fixer fix --dry-run --diff
- run: vendor/bin/phpunit --bootstrap vendor/autoload.php tests/Unit
env:
DB_HOST: UNIT_NO_DB
- name: Integration tests
run: vendor/bin/phpunit tests/Integration
- run: vendor/bin/phpunit tests/Integration
env:
DB_PORT: ${{ job.services.database.ports[3306] }}
DB_USERNAME: root

View File

@ -3,11 +3,6 @@ name: Docker
on:
push:
branches:
- develop
- 1.0-develop
pull_request:
branches:
- develop
- 1.0-develop
release:
types:
@ -16,15 +11,18 @@ on:
jobs:
push:
name: Push
runs-on: ubuntu-20.04
if: "!contains(github.ref, 'develop') || (!contains(github.event.head_commit.message, 'skip docker') && !contains(github.event.head_commit.message, 'docker skip'))"
runs-on: ubuntu-24.04
if: "!contains(github.event.head_commit.message, 'skip docker') && !contains(github.event.head_commit.message, 'docker skip')"
permissions:
contents: read
packages: write
steps:
- name: Code checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Docker metadata
id: docker_meta
uses: docker/metadata-action@v4
uses: docker/metadata-action@v5
with:
images: ghcr.io/pterodactyl/panel
flavor: |
@ -35,17 +33,18 @@ jobs:
type=ref,event=branch
- name: Setup QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
uses: docker/login-action@v3
if: "github.event_name != 'pull_request'"
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.REGISTRY_TOKEN }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Update version
if: "github.event_name == 'release' && github.event.action == 'published'"
@ -55,7 +54,7 @@ jobs:
sed -i "s/ 'version' => 'canary',/ 'version' => '${REF:1}',/" config/app.php
- name: Build and Push
uses: docker/build-push-action@v3
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile

View File

@ -1,36 +0,0 @@
name: Lint
on:
push:
branches:
- "develop"
- "1.0-develop"
pull_request:
branches:
- "develop"
- "1.0-develop"
jobs:
lint:
name: Lint
runs-on: ubuntu-20.04
steps:
- name: Code Checkout
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.1"
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
- name: Setup .env
run: cp .env.ci .env
- name: Install dependencies
run: composer install --no-interaction --no-progress --no-suggest --prefer-dist
- name: PHP CS Fixer
run: vendor/bin/php-cs-fixer fix --dry-run --diff

View File

@ -1,89 +1,49 @@
name: Release
on:
push:
tags:
- "v*"
jobs:
release:
name: Release
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Code checkout
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 16
cache: "yarn"
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build
run: yarn build:production
- name: Create release branch and bump version
node-version: 22
cache: yarn
- run: yarn install --frozen-lockfile
- run: yarn tsc
- run: yarn build:production
- name: create release branch and bump version
env:
REF: ${{ github.ref }}
VERSION: ${{ github.ref_name }}
run: |
BRANCH=release/${REF:10}
git config --local user.email "ci@pterodactyl.io"
git config --local user.name "Pterodactyl CI"
git checkout -b $BRANCH
git push -u origin $BRANCH
sed -i "s/ 'version' => 'canary',/ 'version' => '${REF:11}',/" config/app.php
BRANCH=release/${{ env.VERSION }}
git config --local user.email 'ci@pterodactyl.io'
git config --local user.name 'Pterodactyl CI'
git checkout -b "$BRANCH"
git push -u origin "$BRANCH"
sed -i "s/'canary'/'${VERSION:1}'/" config/app.php
git add config/app.php
git commit -m "ci(release): bump version"
git commit -m 'ci(release): bump version'
git push
- name: Create release archive
- name: create release archive
run: |
rm -rf node_modules tests CODE_OF_CONDUCT.md CONTRIBUTING.md flake.lock flake.nix phpunit.xml shell.nix
rm -rf node_modules tests CONTRIBUTING.md flake.lock flake.nix phpunit.xml shell.nix
tar -czf panel.tar.gz * .editorconfig .env.example .eslintignore .eslintrc.js .gitignore .prettierrc.json
- name: Extract changelog
env:
REF: ${{ github.ref }}
- name: write changelog
run: |
sed -n "/^## ${REF:10}/,/^## /{/^## /b;p}" CHANGELOG.md > ./RELEASE_CHANGELOG
- name: Create checksum and add to changelog
run: |
SUM=`sha256sum panel.tar.gz`
echo -e "\n#### SHA256 Checksum\n\n\`\`\`\n$SUM\n\`\`\`\n" >> ./RELEASE_CHANGELOG
echo $SUM > checksum.txt
- name: Create release
id: create_release
uses: softprops/action-gh-release@v1
sed -n "/^## ${{ github.ref_name }}/,/^## /{/^## /b;p}" CHANGELOG.md > ./RELEASE_CHANGELOG
- uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
draft: true
prerelease: ${{ contains(github.ref, 'rc') || contains(github.ref, 'beta') || contains(github.ref, 'alpha') }}
prerelease: ${{ contains(github.ref_name, 'rc') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'alpha') }}
body_path: ./RELEASE_CHANGELOG
- name: Upload release archive
id: upload-release-archive
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: panel.tar.gz
asset_name: panel.tar.gz
asset_content_type: application/gzip
- name: Upload release checksum
id: upload-release-checksum
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./checksum.txt
asset_name: checksum.txt
asset_content_type: text/plain
files: |
panel.tar.gz

5
.gitignore vendored
View File

@ -21,7 +21,9 @@ public/assets/manifest.json
# For local development with docker
# Remove if we ever put the Dockerfile in the repo
.dockerignore
docker-compose.yml
docker-compose.*
!docker-compose.example.yml
!docker-compose.example.yaml
# for image related files
misc
@ -33,4 +35,3 @@ resources/lang/locales.js
/public/build
/public/hot
result
docker-compose.yaml

View File

@ -2,20 +2,25 @@
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
$finder = (new Finder())
->in(__DIR__)
->exclude([
'vendor',
'node_modules',
'storage',
'bootstrap/cache',
])
->notName(['_ide_helper*']);
->name('*.php')
->ignoreVCSIgnored(true)
->exclude([__DIR__ . '/bootstrap/cache'])
->in([
__DIR__ . '/app',
__DIR__ . '/bootstrap',
__DIR__ . '/config',
__DIR__ . '/database',
__DIR__ . '/routes',
__DIR__ . '/tests',
]);
return (new Config())
->setRiskyAllowed(true)
->setFinder($finder)
->setUsingCache(true)
->setParallelConfig(ParallelConfigFactory::detect())
->setRules([
'@Symfony' => true,
'@PSR1' => true,
@ -25,8 +30,8 @@ return (new Config())
'combine_consecutive_unsets' => true,
'concat_space' => ['spacing' => 'one'],
'heredoc_to_nowdoc' => true,
'no_alias_functions' => true,
'no_unreachable_default_argument_value' => true,
// 'no_alias_functions' => true,
// 'no_unreachable_default_argument_value' => true,
'no_useless_return' => true,
'ordered_imports' => [
'sort_algorithm' => 'length',
@ -42,7 +47,7 @@ return (new Config())
'var',
],
],
'random_api_migration' => true,
// 'random_api_migration' => true,
'ternary_to_null_coalescing' => true,
'yoda_style' => [
'equal' => false,

View File

@ -3,6 +3,99 @@ 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.12.0
### Fixed
* [CVE-2025-68954](https://github.com/pterodactyl/panel/security/advisories/GHSA-8c39-xppg-479c)
* [CVE-2025-69197](https://github.com/pterodactyl/panel/security/advisories/GHSA-rgmp-4873-r683)
* [CVE-2025-69198](https://github.com/pterodactyl/panel/security/advisories/GHSA-jw2v-cq5x-q68g)
* Fixes a self-XSS issue when entering random data into boxes while creating a new database host.
* Fixes missing `HttpForbiddenException` import in the backup status controller.
* Fixes issue where scheduled tasks would execute every minute regardless of their configured cron syntax.
* Pressing `Ctrl+Z` to undo while editing a file no longer deletes the initial file content.
* Fixed incorrect error message being returned when attempting to delete your own account as an admin.
* Fixes node description not being settable via the API.
* Fixes 0-bytes files returning an error when attempting to upload.
* Fixes nodes displaying the first available location even when that field was not edited and the node has a different value set.
* Fixes allocation notes not being reset when a server is deleted. ([#5157](https://github.com/pterodactyl/panel/pull/5157))
### Changed
* Minimum NodeJS version updated to 22 for building.
* Updated all JS and PHP dependencies to their latest versions (where feasible).
* The endpoint for disabling 2FA on an account using the client API changed from `DELETE /api/client/account/two-factor` to `POST /api/client/account/two-factor/disable`
* `^C` in an egg's stop configuration no longer rewrites itself into the default stop configuration.
* `IBM Plex Sans` font is now bundled with the local assets instead of loading from Google CDNs.
* Upload size on nodes is no longer restricted to a max of 1024MB, any positive integer value can be used.
* Administrators are now listed first when viewing a list of all users on the system.
* Websocket no longer endlessly polls when connection issues are encountered, or when Wings disconnects the user for a reason that should not be re-attempted.
## v1.11.10
### Fixed
* Update Laravel to address [CVE-2024-52301](https://github.com/advisories/GHSA-gv7v-rgg6-548h)
### Changed
* Minimum PHP version is now 8.2 due to Laravel upgrade!
## v1.11.9
### Fixed
* Fixed issue with CI not pushing Docker image
## v1.11.8
### Fixed
* Fixed an issue where a `DELETE` request was used instead of a `POST`, potentially logging user passwords in plain text if they disable 2FA.
## v1.11.7
### Added
* Java 21 to Minecraft eggs
### Changed
* Updated Minecraft EULA link
### Fixed
* Fixed backups not ever being marked as completed (#5088)
* Fixed `.7z` files not being detected as a compressed file (#5016)
## 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.
## v1.11.4
### Added
* Added support for the `server.queryport` option on the Rust egg.
* Added support for the Carbon modding framework to the Rust egg.
### Changed
* Upgraded to Laravel 10.
* Sensitive data is no longer shown in the CopyOnClick toast notification.
### Fixed
* Allow SVGs to be edited in the server's file manager.
* Properly validate the request body when creating a backup.
* Fixed issue with schedules running at the wrong time when the panel utilized a timezone with non-hour offsets (such as `Australia/Darwin`).
* Fixes the log directory when running the Panel in a container.
* Fixes the permission name used to check if a user has permission to read files/folders.
* Fixes the ability to unset a server's description through the client API.
* Fixed the MassActionBar on the server's file manager blocking elements below it, preventing them from being interacted with.
## v1.11.3
### Changed
* When updating a server's description through the client API, if no value is specified, the description will now remain unchanged.
* When installing the Panel for the first time, the queue driver will now all default to `redis` instead of `sync`.
### Fixed
* `php artisan p:environment:mail` not correctly setting the right variable for `MAIL_FROM_ADDRESS`.
* Fixed the conflict state rendering on the UI for a server showing `reinstall_failed` as `restoring_backup`.
* Fixed the unknown column `uuid` error when jobs fail, causing them not to get stored correctly.
* Fixed the server task endpoints in the client API not allowing `sequence_id` and `continue_on_failure` to be set.
## v1.11.2
### Changed
* Telemetry no longer sends a map of Egg and Nest UUIDs to the number of servers using them.

View File

@ -1,74 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at support@pterodactyl.io. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -1,31 +1,33 @@
# Contributing
Pterodactyl does not accept Pull Requests (PRs) _for new functionality_ from users that are not currently part of the
core project team. It has become overwhelming to try and give the proper time and attention that such complicated PRs
tend to require — and deserve. As a result, it is in the project's best interest to limit the scope of work on
new functionality to work done within the core project team.
**Pterodactyl does not accept Pull Requests (PRs) _for new functionality_** that was not previously approved by project
maintainers on GitHub discussions. It has become overwhelming to try and give the proper time and attention that such
complicated PRs tend to require. As a result, it is in the project's best interest to limit the scope of work on new
functionality to work done within the core project team.
PRs that address existing _bugs_ with a corresponding issue opened in our issue tracker will continue to be accepted
and reviewed. Their scope is often significantly more targeted, and simply improving upon existing and well defined
logic.
PRs that address existing bugs or features **with a corresponding issue opened in our issue tracker** will continue to
be accepted and reviewed. Their scope is often significantly more targeted, and simply improving upon existing and well
defined logic.
### Responsible Disclosure
## AI Assistance
This is a fairly in-depth project and makes use of a lot of parts. We strive to keep everything as secure as possible
If you use any type of AI assistance while developing for Pterodactyl **it must be disclosed** within the
corresponding review PR and you must identify what it was used for. All interaction with the community must be written
by a human. **You MUST NOT use AI to compose any PR titles, descriptions, or comments**, and must not use AI to
interact with the GitHub Discussions community.
## Responsible Disclosure
This is an in-depth project making use of many moving pieces. While we strive to keep everything as secure as possible
and welcome you to take a look at the code provided in this project yourself. We do ask that you be considerate of
others who are using the software and not publicly disclose security issues without contacting us first by email.
others who are using the software and not publicly disclose security issues. Please see [`SECURITY.md`](/SECURITY.md)
for information on how to report security issues to the team.
We'll make a deal with you: if you contact us by email, and we fail to respond to you within a week you are welcome to
publicly disclose whatever issue you have found. We understand how frustrating it is when you find something big and
no one will respond to you. This holds us to a standard of providing prompt attention to any issues that arise and
keeping this community safe.
If you've found what you believe is a security issue please email `matthew@pterodactyl.io`. Please check
[SECURITY.md](/SECURITY.md) for additional details.
### Contact Us
## Contact Us
You can find us in a couple places online. First and foremost, we're active right here on GitHub. If you encounter a
bug or other problems, open an issue on here for us to take a look at it. We also accept feature requests here as well.
bug or other problems, open an issue on here for us to take a look at it. Please make use of
our [GitHub Discussions](https://github.com/orgs/pterodactyl/discussions/categories/feature-requests)
for any feature requests, general questions, or help with the software.
You can also find us on [Discord](https://discord.gg/pterodactyl).

View File

@ -2,7 +2,7 @@
# Build the assets that are needed for the frontend. This build stage is then discarded
# since we won't need NodeJS anymore in the future. This Docker image ships a final production
# level distribution of Pterodactyl.
FROM --platform=$TARGETOS/$TARGETARCH mhart/alpine-node:14
FROM --platform=$TARGETOS/$TARGETARCH node:22-alpine
WORKDIR /app
COPY . ./
RUN yarn install --frozen-lockfile \
@ -10,7 +10,7 @@ RUN yarn install --frozen-lockfile \
# Stage 1:
# Build the actual container with all of the needed PHP dependencies that will run the application.
FROM --platform=$TARGETOS/$TARGETARCH php:8.1-fpm-alpine
FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine
WORKDIR /app
COPY . ./
COPY --from=0 /app/public/assets ./public/assets
@ -23,6 +23,7 @@ RUN apk add --no-cache --update ca-certificates dcron curl git supervisor tar un
&& chmod 777 -R bootstrap storage \
&& composer install --no-dev --optimize-autoloader \
&& rm -rf .env bootstrap/cache/*.php \
&& mkdir -p /app/storage/logs/ \
&& chown -R nginx:nginx .
RUN rm /usr/local/etc/php-fpm.conf \

View File

@ -1,13 +1,13 @@
[![Logo Image](https://cdn.pterodactyl.io/logos/new/pterodactyl_logo.png)](https://pterodactyl.io)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/pterodactyl/panel/tests?label=Tests&style=for-the-badge)
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/pterodactyl/panel/ci.yaml?label=Tests&style=for-the-badge&branch=1.0-develop)
![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 contributors](https://img.shields.io/github/contributors/pterodactyl/panel?style=for-the-badge)
# Pterodactyl Panel
Pterodactyl® is a free, open-source game server management panel built with PHP, React, and Go. Designed with security
Pterodactyl® is a free, open-source game server management panel built with PHP, React, and Go. Designed with security
in mind, Pterodactyl runs all game servers in isolated Docker containers while exposing a beautiful and intuitive
UI to end users.
@ -24,21 +24,17 @@ Stop settling for less. Make game servers a first class citizen on your platform
## Sponsors
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/matthewpi)
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/pterodactyl)
| Company | About |
|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [**WISP**](https://wisp.gg) | Extra features. |
| [**Fragnet**](https://fragnet.net) | Providing low latency, high-end game hosting solutions to gamers, game studios and eSports platforms. |
| [**RocketNode**](https://rocketnode.com/) | Innovative game server hosting combined with a straightforward control panel, affordable prices, and Rocket-Fast support. |
| [**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! |
| [**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! |
| [**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. |
| [**Pterodactyl Market**](https://pterodactylmarket.com/) | Pterodactyl Market is a one-and-stop shop for Pterodactyl. In our market, you can find Add-ons, Themes, Eggs, and more for Pterodactyl. |
| [**UltraServers**](https://ultraservers.com/) | Deploy premium games hosting with the click of a button. Manage and swap games with ease and let us take care of the rest. We currently support Minecraft, Rust, ARK, 7 Days to Die, Garys MOD, CS:GO, Satisfactory and others. |
| 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! |
| [**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/?utm_source=pterodactyl&utm_medium=sponsor) | 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
@ -67,7 +63,7 @@ and there are plenty more games available provided by the community. Some of the
* Xonotic
* Starmade
* Discord ATLBot, and most other Node.js/Python discord bots
* [and many more...](https://github.com/parkervcp/eggs)
* [and many more...](https://pterodactyleggs.com)
## License

View File

@ -2,19 +2,23 @@
## Supported Versions
The following versions of Pterodactyl are receiving active support and maintenance. Any security vulnerabilities discovered must be reproducible in supported versions.
| Panel | Daemon | Supported |
|--------|--------------|--------------------|
| 1.10.x | wings@1.7.x | :white_check_mark: |
| 1.11.x | wings@1.11.x | :white_check_mark: |
| 0.7.x | daemon@0.6.x | :x: |
Pterodactyl only provides security support for the latest `major.minor` versions of the Panel and Wings software.
If a security vulnerability is found in an older version but cannot be reproduced on a supported version it will
not be considered. Additionally, security issues found in unreleased code will be addressed, but do not warrant a
security advisory.
For example, if the latest version of the Panel is `1.2.5` then we only support security reports for issues that
occur on `>= 1.2.x` versions of the Panel software. The Panel and Wings have their own versions, but they generally
follow eachother.
## Reporting a Vulnerability
Please reach out directly to any project team member on Discord when reporting a security vulnerability, or you can email `matthew@pterodactyl.io`.
Please use our GitHub Security reporting meachnism to quickly alert the team to any security issues you come across,
or send an email to `security@pterodactyl.io` with the details of your report.
We make every effort to respond as soon as possible, although it may take a day or two for us to sync internally and determine the severity of the report and its impact. Please, _do not_ use a public facing channel or GitHub issues to report sensitive security issues.
We make every effort to respond as soon as possible, although it may take a day or two for us to sync internally and
determine the severity of the report and its impact. Please, _do not_ use a public facing channel or GitHub issues to
report sensitive security issues.
As part of our process, we will create a security advisory for the affected versions and disclose it publicly, usually two to four weeks after a releasing a version that addresses it.
As part of our process, we will create a security advisory for the affected versions and disclose it publicly, usually
two to four weeks after a releasing a version that addresses it.

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Console\Commands\Environment;
use DateTimeZone;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel;
use Pterodactyl\Traits\Commands\EnvironmentWriterTrait;
@ -89,7 +88,7 @@ class AppSettingsCommand extends Command
$this->output->comment('The timezone should match one of PHP\'s supported timezones. If you are unsure, please reference https://php.net/manual/en/timezones.php.');
$this->variables['APP_TIMEZONE'] = $this->option('timezone') ?? $this->anticipate(
'Application Timezone',
DateTimeZone::listIdentifiers(),
\DateTimeZone::listIdentifiers(),
config('app.timezone')
);

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Console\Commands\Environment;
use PDOException;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Database\DatabaseManager;
@ -72,7 +71,7 @@ class DatabaseSettingsCommand extends Command
try {
$this->testMySQLConnection();
} catch (PDOException $exception) {
} catch (\PDOException $exception) {
$this->output->error(sprintf('Unable to connect to the MySQL server using the provided credentials. The error returned was "%s".', $exception->getMessage()));
$this->output->error('Your connection credentials have NOT been saved. You will need to provide valid connection information before proceeding.');

View File

@ -44,7 +44,7 @@ class EmailSettingsCommand extends Command
trans('command/messages.environment.mail.ask_driver'),
[
'smtp' => 'SMTP Server',
'mail' => 'PHP\'s Internal Mail Function',
'sendmail' => 'sendmail Binary',
'mailgun' => 'Mailgun Transactional Email',
'mandrill' => 'Mandrill Transactional Email',
'postmark' => 'Postmark Transactional Email',
@ -57,7 +57,7 @@ class EmailSettingsCommand extends Command
$this->{$method}();
}
$this->variables['MAIL_FROM'] = $this->option('email') ?? $this->ask(
$this->variables['MAIL_FROM_ADDRESS'] = $this->option('email') ?? $this->ask(
trans('command/messages.environment.mail.ask_mail_from'),
$this->config->get('mail.from.address')
);

View File

@ -20,7 +20,7 @@ class DeleteLocationCommand extends Command
*/
public function __construct(
private LocationDeletionService $deletionService,
private LocationRepositoryInterface $repository
private LocationRepositoryInterface $repository,
) {
parent::__construct();
}

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Console\Commands\Maintenance;
use SplFileInfo;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Contracts\Filesystem\Filesystem;
@ -35,9 +34,9 @@ class CleanServiceBackupFilesCommand extends Command
{
$files = $this->disk->files('services/.bak');
collect($files)->each(function (SplFileInfo $file) {
collect($files)->each(function (\SplFileInfo $file) {
$lastModified = Carbon::createFromTimestamp($this->disk->lastModified($file->getPath()));
if ($lastModified->diffInMinutes(Carbon::now()) > self::BACKUP_THRESHOLD_MINUTES) {
if ((int) $lastModified->diffInMinutes(Carbon::now()) > self::BACKUP_THRESHOLD_MINUTES) {
$this->disk->delete($file->getPath());
$this->info(trans('command/messages.maintenance.deleting_service_backup', ['file' => $file->getFilename()]));
}

View File

@ -3,7 +3,6 @@
namespace Pterodactyl\Console\Commands\Maintenance;
use Carbon\CarbonImmutable;
use InvalidArgumentException;
use Illuminate\Console\Command;
use Pterodactyl\Repositories\Eloquent\BackupRepository;
@ -11,7 +10,7 @@ class PruneOrphanedBackupsCommand extends Command
{
protected $signature = 'p:maintenance:prune-backups {--prune-age=}';
protected $description = 'Marks all backups that have not completed in the last "n" minutes as being failed.';
protected $description = 'Marks all backups older than "n" minutes that have not yet completed as being failed.';
/**
* PruneOrphanedBackupsCommand constructor.
@ -25,7 +24,7 @@ class PruneOrphanedBackupsCommand extends Command
{
$since = $this->option('prune-age') ?? config('backups.prune_age', 360);
if (!$since || !is_digit($since)) {
throw new InvalidArgumentException('The "--prune-age" argument must be a value greater than 0.');
throw new \InvalidArgumentException('The "--prune-age" argument must be a value greater than 0.');
}
$query = $this->backupRepository->getBuilder()
@ -39,7 +38,7 @@ class PruneOrphanedBackupsCommand extends Command
return;
}
$this->warn("Marking $count backups that have not been marked as completed in the last $since minutes as failed.");
$this->warn("Marking $count uncompleted backups that are older than $since minutes as failed.");
$query->update([
'is_successful' => false,

View File

@ -17,7 +17,7 @@ class NodeConfigurationCommand extends Command
{
$column = ctype_digit((string) $this->argument('node')) ? 'id' : 'uuid';
/** @var \Pterodactyl\Models\Node $node */
/** @var Node $node */
$node = Node::query()->where($column, $this->argument('node'))->firstOr(function () {
$this->error('The selected node does not exist.');

View File

@ -21,6 +21,6 @@ class UpCommand extends BaseUpCommand
return 1;
}
return parent::handle() ?? 0;
return parent::handle();
}
}

View File

@ -2,8 +2,6 @@
namespace Pterodactyl\Console\Commands\Schedule;
use Exception;
use Throwable;
use Illuminate\Console\Command;
use Pterodactyl\Models\Schedule;
use Illuminate\Support\Facades\Log;
@ -68,7 +66,7 @@ class ProcessRunnableCommand extends Command
'schedule' => $schedule->name,
'hash' => $schedule->hashid,
]));
} catch (Throwable|Exception $exception) {
} catch (\Throwable $exception) {
Log::error($exception, ['schedule_id' => $schedule->id]);
$this->error("An error was encountered while processing Schedule #$schedule->id: " . $exception->getMessage());

View File

@ -30,7 +30,7 @@ class BulkPowerActionCommand extends Command
/**
* Handle the bulk power request.
*
* @throws \Illuminate\Validation\ValidationException
* @throws ValidationException
*/
public function handle()
{
@ -97,7 +97,7 @@ class BulkPowerActionCommand extends Command
$instance->whereIn('id', $servers)->orWhereIn('node_id', $nodes);
} elseif (empty($nodes) && !empty($servers)) {
$instance->whereIn('id', $servers);
} elseif (!empty($nodes) && empty($servers)) {
} elseif (!empty($nodes) && empty($servers)) { // @phpstan-ignore empty.variable
$instance->whereIn('node_id', $nodes);
}

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Console\Commands;
use Closure;
use Illuminate\Console\Command;
use Pterodactyl\Console\Kernel;
use Symfony\Component\Process\Process;
@ -40,8 +39,8 @@ class UpgradeCommand extends Command
$this->line($this->getUrl());
}
if (version_compare(PHP_VERSION, '7.4.0') < 0) {
$this->error('Cannot execute self-upgrade process. The minimum required PHP version required is 7.4.0, you have [' . PHP_VERSION . '].');
if (version_compare(PHP_VERSION, '8.2.0', '<')) {
$this->error('Cannot execute self-upgrade process. The minimum required PHP version required is 8.2.0, you have [' . PHP_VERSION . '].');
}
$user = 'www-data';
@ -134,7 +133,7 @@ class UpgradeCommand extends Command
/** @var \Illuminate\Foundation\Application $app */
$app = require __DIR__ . '/../../../bootstrap/app.php';
/** @var \Pterodactyl\Console\Kernel $kernel */
/** @var Kernel $kernel */
$kernel = $app->make(Kernel::class);
$kernel->bootstrap();
$this->setLaravel($app);
@ -177,7 +176,7 @@ class UpgradeCommand extends Command
$this->info('Panel has been successfully upgraded. Please ensure you also update any Wings instances: https://pterodactyl.io/wings/1.0/upgrading.html');
}
protected function withProgress(ProgressBar $bar, Closure $callback)
protected function withProgress(ProgressBar $bar, \Closure $callback)
{
$bar->clear();
$callback();

View File

@ -18,7 +18,7 @@ class Kernel extends ConsoleKernel
/**
* Register the commands for the application.
*/
protected function commands()
protected function commands(): void
{
$this->load(__DIR__ . '/Commands');
}
@ -26,8 +26,11 @@ class Kernel extends ConsoleKernel
/**
* Define the application's command schedule.
*/
protected function schedule(Schedule $schedule)
protected function schedule(Schedule $schedule): void
{
// https://laravel.com/docs/10.x/upgrade#redis-cache-tags
$schedule->command('cache:prune-stale-tags')->hourly();
// Execute scheduled commands for servers every minute, as if there was a normal cron running.
$schedule->command(ProcessRunnableCommand::class)->everyMinute()->withoutOverlapping();
$schedule->command(CleanServiceBackupFilesCommand::class)->daily();

View File

@ -11,5 +11,5 @@ interface HashidsInterface extends VendorHashidsInterface
*
* @throws \InvalidArgumentException
*/
public function decodeFirst(string $encoded, string $default = null): mixed;
public function decodeFirst(string $encoded, ?string $default = null): mixed;
}

View File

@ -12,14 +12,14 @@ interface NestRepositoryInterface extends RepositoryInterface
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithEggs(int $id = null): Collection|Nest;
public function getWithEggs(?int $id = null): Collection|Nest;
/**
* Return a nest or all nests and the count of eggs and servers for that nest.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithCounts(int $id = null): Collection|Nest;
public function getWithCounts(?int $id = null): Collection|Nest;
/**
* Return a nest along with its associated eggs and the servers relation on those eggs.

View File

@ -16,12 +16,12 @@ interface ServerRepositoryInterface extends RepositoryInterface
/**
* Return a collection of servers with their associated data for rebuild operations.
*/
public function getDataForRebuild(int $server = null, int $node = null): Collection;
public function getDataForRebuild(?int $server = null, ?int $node = null): Collection;
/**
* Return a collection of servers with their associated data for reinstall operations.
*/
public function getDataForReinstall(int $server = null, int $node = null): Collection;
public function getDataForReinstall(?int $server = null, ?int $node = null): Collection;
/**
* Return a server model and all variables associated with the server.

View File

@ -10,7 +10,7 @@ interface SettingsRepositoryInterface extends RepositoryInterface
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function set(string $key, string $value = null);
public function set(string $key, ?string $value = null);
/**
* Retrieve a persistent setting from the database.

View File

@ -0,0 +1,65 @@
<?php
namespace Pterodactyl\Enum;
use Illuminate\Http\Request;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\Server;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Routing\Middleware\ThrottleRequests;
/**
* A basic resource throttler for individual servers. This is applied in addition
* to existing rate limits and allows the code to slow down speedy users that might
* be creating resources a little too quickly for comfort. This throttle generally
* only applies to creation flows, and not general view/edit/delete flows.
*/
enum ResourceLimit
{
case Allocation;
case Backup;
case Database;
case Schedule;
case Subuser;
case Websocket;
case FilePull;
public function throttleKey(): string
{
return mb_strtolower("api.client:server-resource:{$this->name}");
}
/**
* Returns a middleware that will throttle the specific resource by server. This
* throttle applies to any user making changes to that resource on the specific
* server, it is NOT per-user.
*/
public function middleware(): string
{
return ThrottleRequests::using($this->throttleKey());
}
public function limit(): Limit
{
return match($this) {
self::Backup => Limit::perMinutes(15, 3),
self::Database => Limit::perMinute(2),
self::FilePull => Limit::perMinutes(10, 5),
self::Subuser => Limit::perMinutes(15, 10),
self::Websocket => Limit::perMinute(5),
default => Limit::perMinute(2),
};
}
public static function boot(): void
{
foreach (self::cases() as $case) {
RateLimiter::for($case->throttleKey(), function (Request $request) use ($case) {
Assert::isInstanceOf($server = $request->route()->parameter('server'), Server::class);
return $case->limit()->by($server->uuid);
});
}
}
}

View File

@ -2,8 +2,6 @@
namespace Pterodactyl\Exceptions;
use Exception;
class AccountNotFoundException extends Exception
class AccountNotFoundException extends \Exception
{
}

View File

@ -2,8 +2,6 @@
namespace Pterodactyl\Exceptions;
use Exception;
class AutoDeploymentException extends Exception
class AutoDeploymentException extends \Exception
{
}

View File

@ -3,7 +3,6 @@
namespace Pterodactyl\Exceptions;
use Exception;
use Throwable;
use Illuminate\Http\Request;
use Psr\Log\LoggerInterface;
use Illuminate\Http\Response;
@ -23,7 +22,7 @@ class DisplayException extends PterodactylException implements HttpExceptionInte
/**
* DisplayException constructor.
*/
public function __construct(string $message, ?Throwable $previous = null, protected string $level = self::LEVEL_ERROR, int $code = 0)
public function __construct(string $message, ?\Throwable $previous = null, protected string $level = self::LEVEL_ERROR, int $code = 0)
{
parent::__construct($message, $code, $previous);
}
@ -67,13 +66,13 @@ class DisplayException extends PterodactylException implements HttpExceptionInte
*/
public function report()
{
if (!$this->getPrevious() instanceof Exception || !Handler::isReportable($this->getPrevious())) {
if (!$this->getPrevious() instanceof \Exception || !Handler::isReportable($this->getPrevious())) {
return null;
}
try {
$logger = Container::getInstance()->make(LoggerInterface::class);
} catch (Exception) {
} catch (\Exception) {
throw $this->getPrevious();
}

View File

@ -3,8 +3,6 @@
namespace Pterodactyl\Exceptions;
use Exception;
use Throwable;
use PDOException;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Http\JsonResponse;
@ -75,13 +73,13 @@ class Handler extends ExceptionHandler
*
* @noinspection PhpUnusedLocalVariableInspection
*/
public function register()
public function register(): void
{
if (config('app.exceptions.report_all', false)) {
$this->dontReport = [];
}
$this->reportable(function (PDOException $ex) {
$this->reportable(function (\PDOException $ex) {
$ex = $this->generateCleanedExceptionStack($ex);
});
@ -90,7 +88,7 @@ class Handler extends ExceptionHandler
});
}
private function generateCleanedExceptionStack(Throwable $exception): string
private function generateCleanedExceptionStack(\Throwable $exception): string
{
$cleanedStack = '';
foreach ($exception->getTrace() as $index => $item) {
@ -123,7 +121,7 @@ class Handler extends ExceptionHandler
*
* @throws \Throwable
*/
public function render($request, Throwable $e): Response
public function render($request, \Throwable $e): Response
{
$connections = $this->container->make(Connection::class);
@ -189,7 +187,7 @@ class Handler extends ExceptionHandler
/**
* Return the exception as a JSONAPI representation for use on API requests.
*/
protected function convertExceptionToArray(Throwable $e, array $override = []): array
protected function convertExceptionToArray(\Throwable $e, array $override = []): array
{
$match = self::$exceptionResponseCodes[get_class($e)] ?? null;
@ -235,9 +233,9 @@ class Handler extends ExceptionHandler
/**
* Return an array of exceptions that should not be reported.
*/
public static function isReportable(Exception $exception): bool
public static function isReportable(\Exception $exception): bool
{
return (new static(Container::getInstance()))->shouldReport($exception);
return (new self(Container::getInstance()))->shouldReport($exception);
}
/**
@ -260,11 +258,11 @@ class Handler extends ExceptionHandler
*
* @return \Throwable[]
*/
protected function extractPrevious(Throwable $e): array
protected function extractPrevious(\Throwable $e): array
{
$previous = [];
while ($value = $e->getPrevious()) {
if (!$value instanceof Throwable) {
if (!$value instanceof \Throwable) { // @phpstan-ignore instanceof.alwaysTrue
break;
}
$previous[] = $value;
@ -278,7 +276,7 @@ class Handler extends ExceptionHandler
* Helper method to allow reaching into the handler to convert an exception
* into the expected array response type.
*/
public static function toArray(Throwable $e): array
public static function toArray(\Throwable $e): array
{
return (new self(app()))->convertExceptionToArray($e);
}

View File

@ -10,7 +10,7 @@ class HttpForbiddenException extends HttpException
/**
* HttpForbiddenException constructor.
*/
public function __construct(string $message = null, \Throwable $previous = null)
public function __construct(?string $message = null, ?\Throwable $previous = null)
{
parent::__construct(Response::HTTP_FORBIDDEN, $message, $previous);
}

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Exceptions\Http\Server;
use Throwable;
use Pterodactyl\Models\Server;
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
@ -12,7 +11,7 @@ class ServerStateConflictException extends ConflictHttpException
* Exception thrown when the server is in an unsupported state for API access or
* certain operations within the codebase.
*/
public function __construct(Server $server, Throwable $previous = null)
public function __construct(Server $server, ?\Throwable $previous = null)
{
$message = 'This server is currently in an unsupported state, please try again later.';
if ($server->isSuspended()) {

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Exceptions\Http;
use Throwable;
use Illuminate\Http\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
@ -12,7 +11,7 @@ class TwoFactorAuthRequiredException extends HttpException implements HttpExcept
/**
* TwoFactorAuthRequiredException constructor.
*/
public function __construct(Throwable $previous = null)
public function __construct(?\Throwable $previous = null)
{
parent::__construct(Response::HTTP_BAD_REQUEST, 'Two-factor authentication is required on this account in order to access this endpoint.', $previous);
}

View File

@ -2,11 +2,10 @@
namespace Pterodactyl\Exceptions;
use Exception;
use Spatie\Ignition\Contracts\Solution;
use Spatie\Ignition\Contracts\ProvidesSolution;
class ManifestDoesNotExistException extends Exception implements ProvidesSolution
class ManifestDoesNotExistException extends \Exception implements ProvidesSolution
{
public function getSolution(): Solution
{

View File

@ -2,8 +2,6 @@
namespace Pterodactyl\Exceptions;
use Exception;
class PterodactylException extends Exception
class PterodactylException extends \Exception
{
}

View File

@ -2,8 +2,6 @@
namespace Pterodactyl\Exceptions\Service\Helper;
use Exception;
class CdnVersionFetchingException extends Exception
class CdnVersionFetchingException extends \Exception
{
}

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Exceptions\Service;
use Throwable;
use Pterodactyl\Exceptions\DisplayException;
class ServiceLimitExceededException extends DisplayException
@ -11,7 +10,7 @@ class ServiceLimitExceededException extends DisplayException
* Exception thrown when something goes over a defined limit, such as allocated
* ports, tasks, databases, etc.
*/
public function __construct(string $message, Throwable $previous = null)
public function __construct(string $message, ?\Throwable $previous = null)
{
parent::__construct($message, $previous, self::LEVEL_WARNING);
}

View File

@ -7,7 +7,6 @@ use Aws\S3\S3Client;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Webmozart\Assert\Assert;
use InvalidArgumentException;
use Illuminate\Foundation\Application;
use League\Flysystem\FilesystemAdapter;
use Pterodactyl\Extensions\Filesystem\S3Filesystem;
@ -39,7 +38,7 @@ class BackupManager
/**
* Returns a backup adapter instance.
*/
public function adapter(string $name = null): FilesystemAdapter
public function adapter(?string $name = null): FilesystemAdapter
{
return $this->get($name ?: $this->getDefaultAdapter());
}
@ -70,7 +69,7 @@ class BackupManager
$config = $this->getConfig($name);
if (empty($config['adapter'])) {
throw new InvalidArgumentException("Backup disk [$name] does not have a configured adapter.");
throw new \InvalidArgumentException("Backup disk [$name] does not have a configured adapter.");
}
$adapter = $config['adapter'];
@ -88,7 +87,7 @@ class BackupManager
return $instance;
}
throw new InvalidArgumentException("Adapter [$adapter] is not supported.");
throw new \InvalidArgumentException("Adapter [$adapter] is not supported.");
}
/**
@ -164,7 +163,7 @@ class BackupManager
/**
* Register a custom adapter creator closure.
*/
public function extend(string $adapter, Closure $callback): self
public function extend(string $adapter, \Closure $callback): self
{
$this->customCreators[$adapter] = $callback;

View File

@ -19,7 +19,7 @@ class DynamicDatabaseConnection
public function __construct(
protected ConfigRepository $config,
protected Encrypter $encrypter,
protected DatabaseHostRepositoryInterface $repository
protected DatabaseHostRepositoryInterface $repository,
) {
}

View File

@ -2,21 +2,16 @@
namespace Pterodactyl\Extensions;
use Illuminate\Support\Arr;
use Hashids\Hashids as VendorHashids;
use Pterodactyl\Contracts\Extensions\HashidsInterface;
class Hashids extends VendorHashids implements HashidsInterface
{
/**
* {@inheritdoc}
*/
public function decodeFirst(string $encoded, string $default = null): mixed
public function decodeFirst(string $encoded, ?string $default = null): mixed
{
$result = $this->decode($encoded);
if (!is_array($result)) {
return $default;
}
return array_first($result, null, $default);
return Arr::first($result, null, $default);
}
}

View File

@ -6,7 +6,7 @@ use Pterodactyl\Models\ApiKey;
use Laravel\Sanctum\NewAccessToken as SanctumAccessToken;
/**
* @property \Pterodactyl\Models\ApiKey $accessToken
* @property ApiKey $accessToken
*/
class NewAccessToken extends SanctumAccessToken
{

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Extensions\Lcobucci\JWT\Encoding;
use DateTimeImmutable;
use Lcobucci\JWT\ClaimsFormatter;
use Lcobucci\JWT\Token\RegisteredClaims;
@ -21,7 +20,7 @@ final class TimestampDates implements ClaimsFormatter
continue;
}
assert($claims[$claim] instanceof DateTimeImmutable);
assert($claims[$claim] instanceof \DateTimeImmutable);
$claims[$claim] = $claims[$claim]->getTimestamp();
}

View File

@ -5,6 +5,9 @@ namespace Pterodactyl\Facades;
use Illuminate\Support\Facades\Facade;
use Pterodactyl\Services\Activity\ActivityLogTargetableService;
/**
* @mixin \Pterodactyl\Services\Activity\ActivityLogTargetableService
*/
class LogTarget extends Facade
{
protected static function getFacadeAccessor(): string

View File

@ -15,8 +15,6 @@ final class Time
*/
public static function getMySQLTimezoneOffset(string $timezone): string
{
$offset = round(CarbonImmutable::now($timezone)->getTimezone()->getOffset(CarbonImmutable::now('UTC')) / 3600);
return sprintf('%s%s:00', $offset > 0 ? '+' : '-', str_pad((string) abs($offset), 2, '0', STR_PAD_LEFT));
return CarbonImmutable::now($timezone)->getTimezone()->toOffsetName();
}
}

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Helpers;
use Exception;
use Carbon\Carbon;
use Cron\CronExpression;
use Illuminate\Support\Facades\Log;
@ -25,7 +24,7 @@ class Utilities
$string = substr_replace($string, $character, random_int(0, $length - 1), 1);
}
} catch (Exception $exception) {
} catch (\Exception $exception) {
// Just log the error and hope for the best at this point.
Log::error($exception);
}

View File

@ -9,7 +9,6 @@ use Pterodactyl\Models\ApiKey;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Pterodactyl\Services\Acl\Api\AdminAcl;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Api\KeyCreationService;
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
@ -24,7 +23,6 @@ class ApiController extends Controller
private AlertsMessageBag $alert,
private ApiKeyRepositoryInterface $repository,
private KeyCreationService $keyCreationService,
private ViewFactory $view,
) {
}
@ -33,7 +31,7 @@ class ApiController extends Controller
*/
public function index(Request $request): View
{
return $this->view->make('admin.api.index', [
return view('admin.api.index', [
'keys' => $this->repository->getApplicationKeys($request->user()),
]);
}
@ -48,7 +46,7 @@ class ApiController extends Controller
$resources = AdminAcl::getResourceList();
sort($resources);
return $this->view->make('admin.api.new', [
return view('admin.api.new', [
'resources' => $resources,
'permissions' => [
'r' => AdminAcl::READ,

View File

@ -3,7 +3,6 @@
namespace Pterodactyl\Http\Controllers\Admin;
use Illuminate\View\View;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
@ -12,7 +11,7 @@ class BaseController extends Controller
/**
* BaseController constructor.
*/
public function __construct(private SoftwareVersionService $version, private ViewFactory $view)
public function __construct(private SoftwareVersionService $version)
{
}
@ -21,6 +20,6 @@ class BaseController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.index', ['version' => $this->version]);
return view('admin.index', ['version' => $this->version]);
}
}

View File

@ -2,13 +2,10 @@
namespace Pterodactyl\Http\Controllers\Admin;
use Exception;
use PDOException;
use Illuminate\View\View;
use Pterodactyl\Models\DatabaseHost;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Databases\Hosts\HostUpdateService;
use Pterodactyl\Http\Requests\Admin\DatabaseHostFormRequest;
@ -31,7 +28,6 @@ class DatabaseController extends Controller
private HostDeletionService $deletionService,
private HostUpdateService $updateService,
private LocationRepositoryInterface $locationRepository,
private ViewFactory $view
) {
}
@ -40,7 +36,7 @@ class DatabaseController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.databases.index', [
return view('admin.databases.index', [
'locations' => $this->locationRepository->getAllWithNodes(),
'hosts' => $this->repository->getWithViewDetails(),
]);
@ -53,7 +49,7 @@ class DatabaseController extends Controller
*/
public function view(int $host): View
{
return $this->view->make('admin.databases.view', [
return view('admin.databases.view', [
'locations' => $this->locationRepository->getAllWithNodes(),
'host' => $this->repository->find($host),
'databases' => $this->databaseRepository->getDatabasesForHost($host),
@ -69,8 +65,8 @@ class DatabaseController extends Controller
{
try {
$host = $this->creationService->handle($request->normalize());
} catch (Exception $exception) {
if ($exception instanceof PDOException || $exception->getPrevious() instanceof PDOException) {
} catch (\Exception $exception) {
if ($exception instanceof \PDOException || $exception->getPrevious() instanceof \PDOException) {
$this->alert->danger(
sprintf('There was an error while trying to connect to the host or while executing a query: "%s"', $exception->getMessage())
)->flash();
@ -98,10 +94,10 @@ class DatabaseController extends Controller
try {
$this->updateService->handle($host->id, $request->normalize());
$this->alert->success('Database host was updated successfully.')->flash();
} catch (Exception $exception) {
} catch (\Exception $exception) {
// Catch any SQL related exceptions and display them back to the user, otherwise just
// throw the exception like normal and move on with it.
if ($exception instanceof PDOException || $exception->getPrevious() instanceof PDOException) {
if ($exception instanceof \PDOException || $exception->getPrevious() instanceof \PDOException) {
$this->alert->danger(
sprintf('There was an error while trying to connect to the host or while executing a query: "%s"', $exception->getMessage())
)->flash();

View File

@ -26,7 +26,7 @@ class LocationController extends Controller
protected LocationDeletionService $deletionService,
protected LocationRepositoryInterface $repository,
protected LocationUpdateService $updateService,
protected ViewFactory $view
protected ViewFactory $view,
) {
}
@ -35,7 +35,7 @@ class LocationController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.locations.index', [
return view('admin.locations.index', [
'locations' => $this->repository->getAllWithDetails(),
]);
}
@ -47,7 +47,7 @@ class LocationController extends Controller
*/
public function view(int $id): View
{
return $this->view->make('admin.locations.view', [
return view('admin.locations.view', [
'location' => $this->repository->getWithNodes($id),
]);
}
@ -86,7 +86,7 @@ class LocationController extends Controller
* Delete a location from the system.
*
* @throws \Exception
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
*/
public function delete(Location $location): RedirectResponse
{

View File

@ -28,7 +28,7 @@ class MountController extends Controller
protected NestRepositoryInterface $nestRepository,
protected LocationRepositoryInterface $locationRepository,
protected MountRepository $repository,
protected ViewFactory $view
protected ViewFactory $view,
) {
}
@ -37,7 +37,7 @@ class MountController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.mounts.index', [
return view('admin.mounts.index', [
'mounts' => $this->repository->getAllWithDetails(),
]);
}
@ -52,7 +52,7 @@ class MountController extends Controller
$nests = Nest::query()->with('eggs')->get();
$locations = Location::query()->with('nodes')->get();
return $this->view->make('admin.mounts.view', [
return view('admin.mounts.view', [
'mount' => $this->repository->getWithRelations($id),
'nests' => $nests,
'locations' => $locations,

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Http\Controllers\Admin\Nests;
use JavaScript;
use Illuminate\View\View;
use Pterodactyl\Models\Egg;
use Illuminate\Http\RedirectResponse;
@ -28,7 +27,7 @@ class EggController extends Controller
protected EggRepositoryInterface $repository,
protected EggUpdateService $updateService,
protected NestRepositoryInterface $nestRepository,
protected ViewFactory $view
protected ViewFactory $view,
) {
}
@ -40,9 +39,9 @@ class EggController extends Controller
public function create(): View
{
$nests = $this->nestRepository->getWithEggs();
JavaScript::put(['nests' => $nests->keyBy('id')]);
\JavaScript::put(['nests' => $nests->keyBy('id')]);
return $this->view->make('admin.eggs.new', ['nests' => $nests]);
return view('admin.eggs.new', ['nests' => $nests]);
}
/**
@ -67,7 +66,7 @@ class EggController extends Controller
*/
public function view(Egg $egg): View
{
return $this->view->make('admin.eggs.view', [
return view('admin.eggs.view', [
'egg' => $egg,
'images' => array_map(
fn ($key, $value) => $key === $value ? $value : "$key|$value",
@ -112,7 +111,7 @@ class EggController extends Controller
/**
* Normalizes a string of docker image data into the expected egg format.
*/
protected function normalizeDockerImages(string $input = null): array
protected function normalizeDockerImages(?string $input = null): array
{
$data = array_map(fn ($value) => trim($value), explode("\n", $input ?? ''));

View File

@ -21,7 +21,7 @@ class EggScriptController extends Controller
protected AlertsMessageBag $alert,
protected EggRepositoryInterface $repository,
protected InstallScriptService $installScriptService,
protected ViewFactory $view
protected ViewFactory $view,
) {
}
@ -41,7 +41,7 @@ class EggScriptController extends Controller
['copy_script_from', '=', $egg->id],
]);
return $this->view->make('admin.eggs.scripts', [
return view('admin.eggs.scripts', [
'copyFromOptions' => $copy,
'relyOnScript' => $rely,
'egg' => $egg,

View File

@ -21,7 +21,7 @@ class EggShareController extends Controller
protected AlertsMessageBag $alert,
protected EggExporterService $exporterService,
protected EggImporterService $importerService,
protected EggUpdateImporterService $updateImporterService
protected EggUpdateImporterService $updateImporterService,
) {
}

View File

@ -26,7 +26,7 @@ class EggVariableController extends Controller
protected VariableUpdateService $updateService,
protected EggRepositoryInterface $repository,
protected EggVariableRepositoryInterface $variableRepository,
protected ViewFactory $view
protected ViewFactory $view,
) {
}
@ -39,7 +39,7 @@ class EggVariableController extends Controller
{
$egg = $this->repository->getWithVariables($egg);
return $this->view->make('admin.eggs.variables', ['egg' => $egg]);
return view('admin.eggs.variables', ['egg' => $egg]);
}
/**
@ -69,7 +69,7 @@ class EggVariableController extends Controller
{
$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);
@ -82,7 +82,7 @@ class EggVariableController extends Controller
{
$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);

View File

@ -24,7 +24,7 @@ class NestController extends Controller
protected NestDeletionService $nestDeletionService,
protected NestRepositoryInterface $repository,
protected NestUpdateService $nestUpdateService,
protected ViewFactory $view
protected ViewFactory $view,
) {
}
@ -35,7 +35,7 @@ class NestController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.nests.index', [
return view('admin.nests.index', [
'nests' => $this->repository->getWithCounts(),
]);
}
@ -45,7 +45,7 @@ class NestController extends Controller
*/
public function create(): View
{
return $this->view->make('admin.nests.new');
return view('admin.nests.new');
}
/**
@ -56,7 +56,7 @@ class NestController extends Controller
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);
}
@ -68,7 +68,7 @@ class NestController extends Controller
*/
public function view(int $nest): View
{
return $this->view->make('admin.nests.view', [
return view('admin.nests.view', [
'nest' => $this->repository->getWithEggServers($nest),
]);
}

View File

@ -19,7 +19,7 @@ class NodeAutoDeployController extends Controller
public function __construct(
private ApiKeyRepository $repository,
private Encrypter $encrypter,
private KeyCreationService $keyCreationService
private KeyCreationService $keyCreationService,
) {
}
@ -31,7 +31,7 @@ class NodeAutoDeployController extends Controller
*/
public function __invoke(Request $request, Node $node): JsonResponse
{
/** @var \Pterodactyl\Models\ApiKey|null $key */
/** @var ApiKey|null $key */
$key = $this->repository->getApplicationKeys($request->user())
->filter(function (ApiKey $key) {
foreach ($key->getAttributes() as $permission => $value) {

View File

@ -7,17 +7,9 @@ use Illuminate\Http\Request;
use Pterodactyl\Models\Node;
use Spatie\QueryBuilder\QueryBuilder;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\View\Factory as ViewFactory;
class NodeController extends Controller
{
/**
* NodeController constructor.
*/
public function __construct(private ViewFactory $view)
{
}
/**
* Returns a listing of nodes on the system.
*/
@ -30,6 +22,6 @@ class NodeController extends Controller
->allowedSorts(['id'])
->paginate(25);
return $this->view->make('admin.nodes.index', ['nodes' => $nodes]);
return view('admin.nodes.index', ['nodes' => $nodes]);
}
}

View File

@ -8,13 +8,11 @@ use Pterodactyl\Models\Node;
use Illuminate\Support\Collection;
use Pterodactyl\Models\Allocation;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Traits\Controllers\JavascriptInjection;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
use Pterodactyl\Repositories\Eloquent\LocationRepository;
use Pterodactyl\Repositories\Eloquent\AllocationRepository;
class NodeViewController extends Controller
{
@ -24,12 +22,10 @@ class NodeViewController extends Controller
* NodeViewController constructor.
*/
public function __construct(
private AllocationRepository $allocationRepository,
private LocationRepository $locationRepository,
private NodeRepository $repository,
private ServerRepository $serverRepository,
private SoftwareVersionService $versionService,
private ViewFactory $view
) {
}
@ -40,7 +36,7 @@ class NodeViewController extends Controller
{
$node = $this->repository->loadLocationAndServerCount($node);
return $this->view->make('admin.nodes.view.index', [
return view('admin.nodes.view.index', [
'node' => $node,
'stats' => $this->repository->getUsageStats($node),
'version' => $this->versionService,
@ -52,7 +48,7 @@ class NodeViewController extends Controller
*/
public function settings(Request $request, Node $node): View
{
return $this->view->make('admin.nodes.view.settings', [
return view('admin.nodes.view.settings', [
'node' => $node,
'locations' => $this->locationRepository->all(),
]);
@ -63,7 +59,7 @@ class NodeViewController extends Controller
*/
public function configuration(Request $request, Node $node): View
{
return $this->view->make('admin.nodes.view.configuration', compact('node'));
return view('admin.nodes.view.configuration', compact('node'));
}
/**
@ -73,9 +69,9 @@ class NodeViewController extends Controller
{
$node = $this->repository->loadNodeAllocations($node);
$this->plainInject(['node' => Collection::wrap($node)->only(['id'])]);
$this->plainInject(['node' => Collection::make([$node])->only(['id'])]);
return $this->view->make('admin.nodes.view.allocation', [
return view('admin.nodes.view.allocation', [
'node' => $node,
'allocations' => Allocation::query()->where('node_id', $node->id)
->groupBy('ip')
@ -90,11 +86,11 @@ class NodeViewController extends Controller
public function servers(Request $request, Node $node): View
{
$this->plainInject([
'node' => Collection::wrap($node->makeVisible(['daemon_token_id', 'daemon_token']))
'node' => Collection::make([$node->makeVisible(['daemon_token_id', 'daemon_token'])])
->only(['scheme', 'fqdn', 'daemonListen', 'daemon_token_id', 'daemon_token']),
]);
return $this->view->make('admin.nodes.view.servers', [
return view('admin.nodes.view.servers', [
'node' => $node,
'servers' => $this->serverRepository->loadAllServersForNode($node->id, 25),
]);

View File

@ -44,7 +44,7 @@ class NodesController extends Controller
protected ServerRepositoryInterface $serverRepository,
protected NodeUpdateService $updateService,
protected SoftwareVersionService $versionService,
protected ViewFactory $view
protected ViewFactory $view,
) {
}
@ -60,7 +60,7 @@ class NodesController extends Controller
return redirect()->route('admin.locations');
}
return $this->view->make('admin.nodes.new', ['locations' => $locations]);
return view('admin.nodes.new', ['locations' => $locations]);
}
/**
@ -131,7 +131,7 @@ class NodesController extends Controller
['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);

View File

@ -2,13 +2,12 @@
namespace Pterodactyl\Http\Controllers\Admin\Servers;
use JavaScript;
use Illuminate\View\View;
use Pterodactyl\Models\Nest;
use Pterodactyl\Models\Node;
use Pterodactyl\Models\Location;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Repositories\Eloquent\NestRepository;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
@ -25,7 +24,6 @@ class CreateServerController extends Controller
private NestRepository $nestRepository,
private NodeRepository $nodeRepository,
private ServerCreationService $creationService,
private ViewFactory $view
) {
}
@ -45,16 +43,16 @@ class CreateServerController extends Controller
$nests = $this->nestRepository->getWithEggs();
JavaScript::put([
\JavaScript::put([
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
'nests' => $nests->map(function ($item) {
'nests' => $nests->map(function (Nest $item) {
return array_merge($item->toArray(), [
'eggs' => $item->eggs->keyBy('id')->toArray(),
]);
})->keyBy('id'),
]);
return $this->view->make('admin.servers.new', [
return view('admin.servers.new', [
'locations' => Location::all(),
'nests' => $nests,
]);

View File

@ -9,17 +9,9 @@ use Spatie\QueryBuilder\QueryBuilder;
use Spatie\QueryBuilder\AllowedFilter;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Models\Filters\AdminServerFilter;
use Illuminate\Contracts\View\Factory as ViewFactory;
class ServerController extends Controller
{
/**
* ServerController constructor.
*/
public function __construct(private ViewFactory $view)
{
}
/**
* Returns all the servers that exist on the system using a paginated result set. If
* a query is passed along in the request it is also passed to the repository function.
@ -33,6 +25,6 @@ class ServerController extends Controller
])
->paginate(config()->get('pterodactyl.paginate.admin.servers'));
return $this->view->make('admin.servers.index', ['servers' => $servers]);
return view('admin.servers.index', ['servers' => $servers]);
}
}

View File

@ -26,7 +26,7 @@ class ServerTransferController extends Controller
private ConnectionInterface $connection,
private DaemonTransferRepository $daemonTransferRepository,
private NodeJWTService $nodeJWTService,
private NodeRepository $nodeRepository
private NodeRepository $nodeRepository,
) {
}
@ -66,7 +66,7 @@ class ServerTransferController extends Controller
$transfer->new_node = $node_id;
$transfer->old_allocation = $server->allocation_id;
$transfer->new_allocation = $allocation_id;
$transfer->old_additional_allocations = $server->allocations->where('id', '!=', $server->allocation_id)->pluck('id');
$transfer->old_additional_allocations = $server->allocations->where('id', '!=', $server->allocation_id)->pluck('id')->values()->toArray();
$transfer->new_additional_allocations = $additional_allocations;
$transfer->save();

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Http\Controllers\Admin\Servers;
use JavaScript;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Pterodactyl\Models\Nest;
@ -10,11 +9,9 @@ use Pterodactyl\Models\Server;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\Servers\EnvironmentService;
use Illuminate\Contracts\View\Factory as ViewFactory;
use Pterodactyl\Repositories\Eloquent\NestRepository;
use Pterodactyl\Repositories\Eloquent\NodeRepository;
use Pterodactyl\Repositories\Eloquent\MountRepository;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Traits\Controllers\JavascriptInjection;
use Pterodactyl\Repositories\Eloquent\LocationRepository;
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
@ -32,9 +29,7 @@ class ServerViewController extends Controller
private MountRepository $mountRepository,
private NestRepository $nestRepository,
private NodeRepository $nodeRepository,
private ServerRepository $repository,
private EnvironmentService $environmentService,
private ViewFactory $view
) {
}
@ -43,7 +38,7 @@ class ServerViewController extends Controller
*/
public function index(Request $request, Server $server): View
{
return $this->view->make('admin.servers.view.index', compact('server'));
return view('admin.servers.view.index', compact('server'));
}
/**
@ -51,7 +46,7 @@ class ServerViewController extends Controller
*/
public function details(Request $request, Server $server): View
{
return $this->view->make('admin.servers.view.details', compact('server'));
return view('admin.servers.view.details', compact('server'));
}
/**
@ -61,7 +56,7 @@ class ServerViewController extends Controller
{
$allocations = $server->node->allocations->toBase();
return $this->view->make('admin.servers.view.build', [
return view('admin.servers.view.build', [
'server' => $server,
'assigned' => $allocations->where('server_id', $server->id)->sortBy('port')->sortBy('ip'),
'unassigned' => $allocations->where('server_id', null)->sortBy('port')->sortBy('ip'),
@ -88,7 +83,7 @@ class ServerViewController extends Controller
})->keyBy('id'),
]);
return $this->view->make('admin.servers.view.startup', compact('server', 'nests'));
return view('admin.servers.view.startup', compact('server', 'nests'));
}
/**
@ -96,7 +91,7 @@ class ServerViewController extends Controller
*/
public function database(Request $request, Server $server): View
{
return $this->view->make('admin.servers.view.database', [
return view('admin.servers.view.database', [
'hosts' => $this->databaseHostRepository->all(),
'server' => $server,
]);
@ -109,7 +104,7 @@ class ServerViewController extends Controller
{
$server->load('mounts');
return $this->view->make('admin.servers.view.mounts', [
return view('admin.servers.view.mounts', [
'mounts' => $this->mountRepository->getMountListForServer($server),
'server' => $server,
]);
@ -119,7 +114,7 @@ class ServerViewController extends Controller
* Returns the base server management page, or an exception if the server
* is in a state that cannot be recovered from.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
*/
public function manage(Request $request, Server $server): View
{
@ -134,11 +129,11 @@ class ServerViewController extends Controller
$canTransfer = true;
}
JavaScript::put([
\JavaScript::put([
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
]);
return $this->view->make('admin.servers.view.manage', [
return view('admin.servers.view.manage', [
'server' => $server,
'locations' => $this->locationRepository->all(),
'canTransfer' => $canTransfer,
@ -150,6 +145,6 @@ class ServerViewController extends Controller
*/
public function delete(Request $request, Server $server): View
{
return $this->view->make('admin.servers.view.delete', compact('server'));
return view('admin.servers.view.delete', compact('server'));
}
}

View File

@ -57,14 +57,14 @@ class ServersController extends Controller
protected NestRepositoryInterface $nestRepository,
protected ServerConfigurationStructureService $serverConfigurationStructureService,
protected StartupModificationService $startupModificationService,
protected SuspensionService $suspensionService
protected SuspensionService $suspensionService,
) {
}
/**
* Update the details for a server.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function setDetails(Request $request, Server $server): RedirectResponse
@ -81,8 +81,8 @@ class ServersController extends Controller
/**
* Toggles the installation status for a server.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws DisplayException
* @throws DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function toggleInstall(Server $server): RedirectResponse
@ -103,8 +103,8 @@ class ServersController extends Controller
/**
* Reinstalls the server with the currently assigned service.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws DisplayException
* @throws DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function reinstallServer(Server $server): RedirectResponse
@ -118,8 +118,8 @@ class ServersController extends Controller
/**
* Manage the suspension status for a server.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws DisplayException
* @throws DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function manageSuspension(Request $request, Server $server): RedirectResponse
@ -135,9 +135,9 @@ class ServersController extends Controller
/**
* Update the build configuration for a server.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Illuminate\Validation\ValidationException
* @throws ValidationException
*/
public function updateBuild(Request $request, Server $server): RedirectResponse
{
@ -159,7 +159,7 @@ class ServersController extends Controller
/**
* Start the server deletion process.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
* @throws \Throwable
*/
public function delete(Request $request, Server $server): RedirectResponse
@ -173,7 +173,7 @@ class ServersController extends Controller
/**
* Update the startup command as well as variables.
*
* @throws \Illuminate\Validation\ValidationException
* @throws ValidationException
*/
public function saveStartup(Request $request, Server $server): RedirectResponse
{
@ -220,7 +220,7 @@ class ServersController extends Controller
*/
public function resetDatabasePassword(Request $request, Server $server): Response
{
/** @var \Pterodactyl\Models\Database $database */
/** @var Database $database */
$database = $server->databases()->findOrFail($request->input('database'));
$this->databasePasswordService->handle($database);

View File

@ -6,7 +6,6 @@ use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
@ -22,7 +21,6 @@ class AdvancedController extends Controller
private ConfigRepository $config,
private Kernel $kernel,
private SettingsRepositoryInterface $settings,
private ViewFactory $view
) {
}
@ -39,7 +37,7 @@ class AdvancedController extends Controller
$showRecaptchaWarning = true;
}
return $this->view->make('admin.settings.advanced', [
return view('admin.settings.advanced', [
'showRecaptchaWarning' => $showRecaptchaWarning,
]);
}

View File

@ -6,7 +6,6 @@ use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Prologue\Alerts\AlertsMessageBag;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\View\Factory as ViewFactory;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Traits\Helpers\AvailableLanguages;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
@ -25,7 +24,6 @@ class IndexController extends Controller
private Kernel $kernel,
private SettingsRepositoryInterface $settings,
private SoftwareVersionService $versionService,
private ViewFactory $view
) {
}
@ -34,7 +32,7 @@ class IndexController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.settings.index', [
return view('admin.settings.index', [
'version' => $this->versionService,
'languages' => $this->getAvailableLanguages(true),
]);

View File

@ -2,13 +2,11 @@
namespace Pterodactyl\Http\Controllers\Admin\Settings;
use Exception;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Contracts\Console\Kernel;
use Pterodactyl\Notifications\MailTested;
use Illuminate\View\Factory as ViewFactory;
use Illuminate\Support\Facades\Notification;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Http\Controllers\Controller;
@ -28,7 +26,6 @@ class MailController extends Controller
private Encrypter $encrypter,
private Kernel $kernel,
private SettingsRepositoryInterface $settings,
private ViewFactory $view
) {
}
@ -38,7 +35,7 @@ class MailController extends Controller
*/
public function index(): View
{
return $this->view->make('admin.settings.mail', [
return view('admin.settings.mail', [
'disabled' => $this->config->get('mail.default') !== 'smtp',
]);
}
@ -82,7 +79,7 @@ class MailController extends Controller
try {
Notification::route('mail', $request->user()->email)
->notify(new MailTested($request->user()));
} catch (Exception $exception) {
} catch (\Exception $exception) {
return response($exception->getMessage(), 500);
}

View File

@ -36,7 +36,7 @@ class UserController extends Controller
protected Translator $translator,
protected UserUpdateService $updateService,
protected UserRepositoryInterface $repository,
protected ViewFactory $view
protected ViewFactory $view,
) {
}
@ -54,10 +54,11 @@ class UserController extends Controller
->groupBy('users.id')
)
->allowedFilters(['username', 'email', 'uuid'])
->defaultSort('-root_admin')
->allowedSorts(['id', 'uuid'])
->paginate(50);
return $this->view->make('admin.users.index', ['users' => $users]);
return view('admin.users.index', ['users' => $users]);
}
/**
@ -65,7 +66,7 @@ class UserController extends Controller
*/
public function create(): View
{
return $this->view->make('admin.users.new', [
return view('admin.users.new', [
'languages' => $this->getAvailableLanguages(true),
]);
}
@ -75,7 +76,7 @@ class UserController extends Controller
*/
public function view(User $user): View
{
return $this->view->make('admin.users.view', [
return view('admin.users.view', [
'user' => $user,
'languages' => $this->getAvailableLanguages(true),
]);
@ -85,12 +86,12 @@ class UserController extends Controller
* Delete a user from the system.
*
* @throws \Exception
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
*/
public function delete(Request $request, User $user): RedirectResponse
{
if ($request->user()->id === $user->id) {
throw new DisplayException($this->translator->get('admin/user.exceptions.user_has_servers'));
if ($request->user()->is($user)) {
throw new DisplayException(__('admin/user.exceptions.delete_self'));
}
$this->deletionService->handle($user);
@ -139,12 +140,14 @@ class UserController extends Controller
// Handle single user requests.
if ($request->query('user_id')) {
$user = User::query()->findOrFail($request->input('user_id'));
// @phpstan-ignore-next-line property.notFound
$user->md5 = md5(strtolower($user->email));
return $user;
}
return $users->map(function ($item) {
// @phpstan-ignore-next-line property.notFound
$item->md5 = md5(strtolower($item->email));
return $item;

View File

@ -59,7 +59,7 @@ abstract class ApplicationApiController extends Controller
*/
public function getTransformer(string $abstract)
{
Assert::subclassOf($abstract, BaseTransformer::class);
Assert::subclassOf($abstract, BaseTransformer::class); // @phpstan-ignore staticMethod.alreadyNarrowedType
return $abstract::fromRequest($this->request);
}

View File

@ -25,7 +25,7 @@ class LocationController extends ApplicationApiController
public function __construct(
private LocationCreationService $creationService,
private LocationDeletionService $deletionService,
private LocationUpdateService $updateService
private LocationUpdateService $updateService,
) {
parent::__construct();
}

View File

@ -23,7 +23,7 @@ class AllocationController extends ApplicationApiController
*/
public function __construct(
private AssignmentService $assignmentService,
private AllocationDeletionService $deletionService
private AllocationDeletionService $deletionService,
) {
parent::__construct();
}

View File

@ -24,7 +24,7 @@ class NodeController extends ApplicationApiController
public function __construct(
private NodeCreationService $creationService,
private NodeDeletionService $deletionService,
private NodeUpdateService $updateService
private NodeUpdateService $updateService,
) {
parent::__construct();
}

View File

@ -22,7 +22,7 @@ class DatabaseController extends ApplicationApiController
*/
public function __construct(
private DatabaseManagementService $databaseManagementService,
private DatabasePasswordService $databasePasswordService
private DatabasePasswordService $databasePasswordService,
) {
parent::__construct();
}

View File

@ -22,7 +22,7 @@ class ServerController extends ApplicationApiController
*/
public function __construct(
private ServerCreationService $creationService,
private ServerDeletionService $deletionService
private ServerDeletionService $deletionService,
) {
parent::__construct();
}

View File

@ -17,7 +17,7 @@ class ServerDetailsController extends ApplicationApiController
*/
public function __construct(
private BuildModificationService $buildModificationService,
private DetailsModificationService $detailsModificationService
private DetailsModificationService $detailsModificationService,
) {
parent::__construct();
}

View File

@ -16,7 +16,7 @@ class ServerManagementController extends ApplicationApiController
*/
public function __construct(
private ReinstallServerService $reinstallServerService,
private SuspensionService $suspensionService
private SuspensionService $suspensionService,
) {
parent::__construct();
}

View File

@ -23,7 +23,7 @@ class UserController extends ApplicationApiController
public function __construct(
private UserCreationService $creationService,
private UserDeletionService $deletionService,
private UserUpdateService $updateService
private UserUpdateService $updateService,
) {
parent::__construct();
}

View File

@ -64,7 +64,7 @@ class AccountController extends ClientApiController
$guard->setUser($user);
// This method doesn't exist in the stateless Sanctum world.
if (method_exists($guard, 'logoutOtherDevices')) {
if (method_exists($guard, 'logoutOtherDevices')) { // @phpstan-ignore function.alreadyNarrowedType
$guard->logoutOtherDevices($request->input('password'));
}

View File

@ -25,7 +25,7 @@ class ApiKeyController extends ClientApiController
/**
* Store a new API key for a user's account.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
*/
public function store(StoreApiKeyRequest $request): array
{
@ -54,7 +54,7 @@ class ApiKeyController extends ClientApiController
*/
public function delete(ClientApiRequest $request, string $identifier): JsonResponse
{
/** @var \Pterodactyl\Models\ApiKey $key */
/** @var ApiKey $key */
$key = $request->user()->apiKeys()
->where('key_type', ApiKey::TYPE_ACCOUNT)
->where('identifier', $identifier)

View File

@ -49,7 +49,7 @@ abstract class ClientApiController extends ApplicationApiController
*/
public function getTransformer(string $abstract)
{
Assert::subclassOf($abstract, BaseClientTransformer::class);
Assert::subclassOf($abstract, BaseClientTransformer::class); // @phpstan-ignore staticMethod.alreadyNarrowedType
return $abstract::fromRequest($this->request);
}

View File

@ -18,6 +18,7 @@ use Pterodactyl\Transformers\Api\Client\BackupTransformer;
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\StoreBackupRequest;
use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\RestoreBackupRequest;
class BackupController extends ClientApiController
{
@ -29,7 +30,7 @@ class BackupController extends ClientApiController
private DeleteBackupService $deleteBackupService,
private InitiateBackupService $initiateBackupService,
private DownloadLinkService $downloadLinkService,
private BackupRepository $repository
private BackupRepository $repository,
) {
parent::__construct();
}
@ -38,7 +39,7 @@ class BackupController extends ClientApiController
* Returns all the backups for a given server instance in a paginated
* result set.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
* @throws AuthorizationException
*/
public function index(Request $request, Server $server): array
{
@ -73,15 +74,21 @@ class BackupController extends ClientApiController
// how best to allow a user to create a backup that is locked without also preventing
// them from just filling up a server with backups that can never be deleted?
if ($request->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) {
$action->setIsLocked((bool) $request->input('is_locked'));
$action->setIsLocked($request->boolean('is_locked'));
}
$backup = $action->handle($server, $request->input('name'));
$backup = Activity::event('server:backup.start')->transaction(function ($log) use ($action, $server, $request) {
$server->backups()->lockForUpdate();
Activity::event('server:backup.start')
->subject($backup)
->property(['name' => $backup->name, 'locked' => (bool) $request->input('is_locked')])
->log();
$backup = $action->handle($server, $request->input('name'));
$log->subject($backup)->property([
'name' => $backup->name,
'locked' => $request->boolean('is_locked'),
]);
return $backup;
});
return $this->fractal->item($backup)
->transformWith($this->getTransformer(BackupTransformer::class))
@ -92,7 +99,7 @@ class BackupController extends ClientApiController
* Toggles the lock status of a given backup for a server.
*
* @throws \Throwable
* @throws \Illuminate\Auth\Access\AuthorizationException
* @throws AuthorizationException
*/
public function toggleLock(Request $request, Server $server, Backup $backup): array
{
@ -114,7 +121,7 @@ class BackupController extends ClientApiController
/**
* Returns information about a single backup.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
* @throws AuthorizationException
*/
public function view(Request $request, Server $server, Backup $backup): array
{
@ -155,7 +162,7 @@ class BackupController extends ClientApiController
* which the user is redirected to.
*
* @throws \Throwable
* @throws \Illuminate\Auth\Access\AuthorizationException
* @throws AuthorizationException
*/
public function download(Request $request, Server $server, Backup $backup): JsonResponse
{
@ -188,12 +195,8 @@ class BackupController extends ClientApiController
*
* @throws \Throwable
*/
public function restore(Request $request, Server $server, Backup $backup): JsonResponse
public function restore(RestoreBackupRequest $request, Server $server, Backup $backup): JsonResponse
{
if (!$request->user()->can(Permission::ACTION_BACKUP_RESTORE, $server)) {
throw new AuthorizationException();
}
// Cannot restore a backup unless a server is fully installed and not currently
// processing a different backup restoration request.
if (!is_null($server->status)) {

View File

@ -5,7 +5,6 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
use Illuminate\Http\Response;
use Pterodactyl\Models\Server;
use Pterodactyl\Facades\Activity;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\BadResponseException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Pterodactyl\Repositories\Wings\DaemonCommandRepository;
@ -26,7 +25,7 @@ class CommandController extends ClientApiController
/**
* Send a command to a running server.
*
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
* @throws DaemonConnectionException
*/
public function index(SendCommandRequest $request, Server $server): Response
{
@ -36,10 +35,7 @@ class CommandController extends ClientApiController
$previous = $exception->getPrevious();
if ($previous instanceof BadResponseException) {
if (
$previous->getResponse() instanceof ResponseInterface
&& $previous->getResponse()->getStatusCode() === Response::HTTP_BAD_GATEWAY
) {
if ($previous->getResponse()->getStatusCode() === Response::HTTP_BAD_GATEWAY) {
throw new HttpException(Response::HTTP_BAD_GATEWAY, 'Server must be online in order to send commands.', $exception);
}
}

View File

@ -24,7 +24,7 @@ class DatabaseController extends ClientApiController
public function __construct(
private DeployServerDatabaseService $deployDatabaseService,
private DatabaseManagementService $managementService,
private DatabasePasswordService $passwordService
private DatabasePasswordService $passwordService,
) {
parent::__construct();
}
@ -48,12 +48,15 @@ class DatabaseController extends ClientApiController
*/
public function store(StoreDatabaseRequest $request, Server $server): array
{
$database = $this->deployDatabaseService->handle($server, $request->validated());
$database = Activity::event('server:database.create')->transaction(function ($log) use ($request, $server) {
$server->databases()->lockForUpdate();
Activity::event('server:database.create')
->subject($database)
->property('name', $database->database)
->log();
$database = $this->deployDatabaseService->handle($server, $request->validated());
$log->subject($database)->property('name', $database->database);
return $database;
});
return $this->fractal->item($database)
->parseIncludes(['password'])
@ -69,15 +72,16 @@ class DatabaseController extends ClientApiController
*/
public function rotatePassword(RotatePasswordRequest $request, Server $server, Database $database): array
{
$this->passwordService->handle($database);
$database->refresh();
Activity::event('server:database.rotate-password')
->subject($database)
->property('name', $database->database)
->log();
->transaction(function () use ($database) {
$database->lockForUpdate();
return $this->fractal->item($database)
$this->passwordService->handle($database);
});
return $this->fractal->item($database->refresh())
->parseIncludes(['password'])
->transformWith($this->getTransformer(DatabaseTransformer::class))
->toArray();

View File

@ -30,7 +30,7 @@ class FileController extends ClientApiController
*/
public function __construct(
private NodeJWTService $jwtService,
private DaemonFileRepository $fileRepository
private DaemonFileRepository $fileRepository,
) {
parent::__construct();
}

View File

@ -16,7 +16,7 @@ class FileUploadController extends ClientApiController
* FileUploadController constructor.
*/
public function __construct(
private NodeJWTService $jwtService
private NodeJWTService $jwtService,
) {
parent::__construct();
}

View File

@ -6,6 +6,7 @@ use Pterodactyl\Models\Server;
use Illuminate\Http\JsonResponse;
use Pterodactyl\Facades\Activity;
use Pterodactyl\Models\Allocation;
use Illuminate\Database\ConnectionInterface;
use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Repositories\Eloquent\ServerRepository;
use Pterodactyl\Transformers\Api\Client\AllocationTransformer;
@ -23,8 +24,9 @@ class NetworkAllocationController extends ClientApiController
* NetworkAllocationController constructor.
*/
public function __construct(
protected readonly ConnectionInterface $connection,
private FindAssignableAllocationService $assignableAllocationService,
private ServerRepository $serverRepository
private ServerRepository $serverRepository,
) {
parent::__construct();
}
@ -88,20 +90,21 @@ class NetworkAllocationController extends ClientApiController
* Set the notes for the allocation for a server.
*s.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
*/
public function store(NewAllocationRequest $request, Server $server): array
{
if ($server->allocations()->count() >= $server->allocation_limit) {
throw new DisplayException('Cannot assign additional allocations to this server: limit has been reached.');
}
$allocation = Activity::event('server:allocation.create')->transaction(function ($log) use ($server) {
if ($server->allocations()->lockForUpdate()->count() >= $server->allocation_limit) {
throw new DisplayException('Cannot assign additional allocations to this server: limit has been reached.');
}
$allocation = $this->assignableAllocationService->handle($server);
$allocation = $this->assignableAllocationService->handle($server);
Activity::event('server:allocation.create')
->subject($allocation)
->property('allocation', $allocation->toString())
->log();
$log->subject($allocation)->property('allocation', $allocation->toString());
return $allocation;
});
return $this->fractal->item($allocation)
->transformWith($this->getTransformer(AllocationTransformer::class))
@ -111,7 +114,7 @@ class NetworkAllocationController extends ClientApiController
/**
* Delete an allocation from a server.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
*/
public function delete(DeleteAllocationRequest $request, Server $server, Allocation $allocation): JsonResponse
{

View File

@ -2,7 +2,6 @@
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
use Exception;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@ -48,12 +47,12 @@ class ScheduleController extends ClientApiController
/**
* Store a new schedule for a server.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function store(StoreScheduleRequest $request, Server $server): array
{
/** @var \Pterodactyl\Models\Schedule $model */
/** @var Schedule $model */
$model = $this->repository->create([
'server_id' => $server->id,
'name' => $request->input('name'),
@ -96,7 +95,7 @@ class ScheduleController extends ClientApiController
/**
* Updates a given schedule with the new data provided.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
@ -166,7 +165,7 @@ class ScheduleController extends ClientApiController
/**
* Get the next run timestamp based on the cron data provided.
*
* @throws \Pterodactyl\Exceptions\DisplayException
* @throws DisplayException
*/
protected function getNextRunAt(Request $request): Carbon
{
@ -178,7 +177,7 @@ class ScheduleController extends ClientApiController
$request->input('month'),
$request->input('day_of_week')
);
} catch (Exception $exception) {
} catch (\Exception $exception) {
throw new DisplayException('The cron data provided does not evaluate to a valid expression.');
}
}

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