Compare commits

..

109 Commits
3.x ... 2.x

Author SHA1 Message Date
Matthew Penner
5bcf6fd459 Merge branch '1.0-develop' into develop 2024-04-16 15:18:29 -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
7f192dce20 Merge branch '1.0-develop' into develop 2024-04-10 19:38:14 -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
6a33c73294 Merge branch '1.0-develop' into develop 2024-03-16 14:04:46 -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
fe83a4f755 Merge branch '1.0-develop' into develop 2023-12-29 22:11:34 -07:00
Matthew Penner
a9bdf7a1ef Merge branch '1.0-develop' into develop 2023-10-02 17:06:39 -06:00
Matthew Penner
804a08bd2e nix: update flake.lock 2023-10-02 16:59:23 -06:00
Matthew Penner
8ffe0f1ff0 chore: fix eslint 2023-10-02 16:56:48 -06:00
Matthew Penner
9b35a55eea ui: make the Input component slightly shorter 2023-09-29 16:34:56 -06:00
Matthew Penner
35ded9def8 ui(admin): fix server egg select improperly switching 2023-09-29 16:33:15 -06:00
Matthew Penner
3721b2007b ui(admin): fix egg creation 2023-09-28 13:48:21 -06:00
Matthew Penner
6f5fb09c13 Merge branch '1.0-develop' into develop 2023-08-22 19:22:50 -06:00
Matthew Penner
d3c6568522 Merge branch '1.0-develop' into develop 2023-07-11 20:40:41 -06:00
Matthew Penner
b7b128efc5 Merge branch '1.0-develop' into develop 2023-06-28 20:24:29 -06:00
Matthew Penner
eaf46429f2 Merge branch '1.0-develop' into develop 2023-05-12 23:12:06 -06:00
Matthew Penner
bad765039b Update README.md 2023-05-12 23:10:17 -06:00
Matthew Penner
dc6fadd1c5 Merge branch '1.0-develop' into develop 2023-03-11 14:12:23 -07:00
Matthew Penner
f5ce1a240c ci: install pnpm 2023-02-23 14:39:45 -07:00
Matthew Penner
8320c64918 switch from yarn to pnpm 2023-02-23 14:37:12 -07:00
Matthew Penner
0d225b0e8f ci(docker): revert workflow changes 2023-02-23 14:35:07 -07:00
Matthew Penner
8ae40a7c71 containerfile: remove platform arg 2023-02-23 14:22:31 -07:00
Matthew Penner
7241829da6 containerfile: reinstall tzdata
ref; https://bugzilla.redhat.com/show_bug.cgi?id=1870814
2023-02-23 14:09:24 -07:00
Matthew Penner
05d8de0671 ci(container): tweak options 2023-02-23 13:47:39 -07:00
Matthew Penner
f98aa11a3a ci(container): update to ubuntu-22.04 2023-02-23 13:43:40 -07:00
Matthew Penner
ab4b4e6ada ci(container): replace old docker workflow 2023-02-23 13:40:04 -07:00
Matthew Penner
673f7282e0 ui: fix prettier 2023-02-23 13:15:06 -07:00
Matthew Penner
2195aa6447 ci(docker): upgrade to php 8.2 2023-02-23 13:08:49 -07:00
Matthew Penner
187c7f74cd yarn: upgrade dependencies 2023-02-23 13:08:40 -07:00
Matthew Penner
0af39492e3 app(services): fix DeployServerDatabaseService phpstan 2023-02-23 12:49:07 -07:00
Matthew Penner
733771ae75 nix: update flake lock 2023-02-23 12:48:53 -07:00
Matthew Penner
85df1a4ec7 ci(laravel): add PHP 8.2 to test matrix 2023-02-23 12:48:28 -07:00
Matthew Penner
a1e5afccb4 composer: update lock 2023-02-23 12:37:27 -07:00
Matthew Penner
18f6611a2d Merge branch '1.0-develop' into develop 2023-02-23 12:36:22 -07:00
Matthew Penner
582c50c6d4 Merge branch '1.0-develop' into develop 2023-02-06 10:22:50 -07:00
Matthew Penner
3bd8164415 Merge branch '1.0-develop' into develop 2023-01-27 13:09:22 -07:00
Matthew Penner
c5be3ad04b nix: update flake lock 2023-01-25 13:34:47 -07:00
Matthew Penner
d8b7747828 ui(server): lazy load server console to reduce main bundle size 2023-01-25 11:39:07 -07:00
Matthew Penner
7c67ff3711 yarn: upgrade dependencies 2023-01-25 11:36:42 -07:00
Matthew Penner
d09e61b4f4 Update Containerfile to node 18, install composer through rpms 2023-01-25 11:36:28 -07:00
Matthew Penner
4b82ca1042 ui(admin): fix users list 2023-01-25 11:14:39 -07:00
Matthew Penner
5063db7d95 Merge branch '1.0-develop' into develop 2023-01-25 10:47:17 -07:00
Matthew Penner
0b237071f2 Update README.md, fix CI status badge 2023-01-17 15:26:08 -07:00
Matthew Penner
62238ad418 Merge branch '1.0-develop' into develop 2023-01-17 15:25:28 -07:00
Matthew Penner
7665eea14d app(server): rename oom_disabled to oom_killer and invert existing values 2023-01-17 12:11:31 -07:00
Matthew Penner
450fba00bc ui(admin): fix oom killer setting toggle 2023-01-17 11:43:26 -07:00
Matthew Penner
f6cf4a1236 ui: add read-only styling to Input element 2023-01-13 11:59:11 -07:00
Matthew Penner
e88197c4b1 ui: fix DashboardRouter trailing slashes 2023-01-13 11:58:40 -07:00
Matthew Penner
b59e1da860 tests: fix remaining failures 2023-01-12 13:19:01 -07:00
Matthew Penner
f45eac623c chore: run php-cs-fixer 2023-01-12 12:46:40 -07:00
Matthew Penner
3d7112b702 ui: fix eslint 2023-01-12 12:45:07 -07:00
Matthew Penner
7e1aa8d7e2 ui: fix tests 2023-01-12 12:44:49 -07:00
Matthew Penner
155d7bb876 chore: run prettier 2023-01-12 12:31:47 -07:00
Matthew Penner
9cdbbc3a00 ui(admin): fix server editing 2023-01-12 12:25:58 -07:00
Matthew Penner
216c464ac8 ui(admin): update New Nest button 2023-01-12 12:12:06 -07:00
Matthew Penner
bc7737840a ui(editor): fix editor child styling 2023-01-12 12:08:11 -07:00
Matthew Penner
76b67cb889 ui: fix IPv6 formatting logic 2023-01-12 11:28:11 -07:00
Matthew Penner
42d8f2cb82 ui(server): fix file editor and file manager 2023-01-12 11:22:24 -07:00
Matthew Penner
27e3eec5fc yarn: upgrade @codemirror/* 2023-01-12 11:21:32 -07:00
Matthew Penner
f68864db00 Merge branch '1.0-develop' into develop 2023-01-01 15:26:55 -07:00
Matthew Penner
089860b721 ui(admin): update button components, fix Editor for eggs 2022-12-21 14:27:55 -07:00
Matthew Penner
4e56f6dbea yarn: upgrade dependencies 2022-12-21 14:27:07 -07:00
Matthew Penner
5402584508 ui(admin): add "working" React admin ui 2022-12-15 19:06:14 -07:00
Matthew Penner
d1c7494933 app: fix DeployServerDatabaseService 2022-12-15 12:39:37 -07:00
Matthew Penner
926c8563d0 user: cleanup 2022-12-15 12:26:34 -07:00
Matthew Penner
7f669828c6 tests: more fixes, but stuff is still broken 2022-12-14 19:53:07 -07:00
Matthew Penner
10b2380e9e Make sure to actually update other references as well 2022-12-14 19:15:19 -07:00
Matthew Penner
8fff0846a0 Attempt to fix Fractal object type being null 2022-12-14 19:13:00 -07:00
Matthew Penner
507a802dec database-host: reverse node relationship 2022-12-14 18:53:31 -07:00
Matthew Penner
0c5416ee27 cli: fix up command override 2022-12-14 18:43:20 -07:00
Matthew Penner
160c3ddeff composer: update dependencies 2022-12-14 18:41:39 -07:00
Matthew Penner
a24c594cbd user: remove name_first and name_last from tests 2022-12-14 18:23:46 -07:00
Matthew Penner
6b11836a41 user: remove name_first and name_last 2022-12-14 18:17:27 -07:00
Matthew Penner
2f15d94957 database: fix migrations with postgres 2022-12-14 18:17:16 -07:00
Matthew Penner
f68c46b0a0 eggs: remove config_logs field 2022-12-14 18:10:12 -07:00
Matthew Penner
3670dc6d4b phpstan 2022-12-14 18:08:50 -07:00
Matthew Penner
7ed2be50fd php-cs-fixer and phpstan 2022-12-14 18:04:16 -07:00
Matthew Penner
363c4fd49f php-cs-fixer 2022-12-14 17:06:28 -07:00
Matthew Penner
67bf3e342e api(application): v2 backport 2022-12-14 17:05:46 -07:00
Matthew Penner
4cd0bee231 yeet 2022-12-14 14:36:07 -07:00
Matthew Penner
7fde336036 Merge branch '1.0-develop' into develop 2022-12-14 14:21:01 -07:00
Matthew Penner
5fbc7a89e4 nix&docker: simplify Caddyfile 2022-12-12 19:23:03 -07:00
Matthew Penner
4138fb7497 Merge branch '1.0-develop' into develop 2022-12-12 16:23:11 -07:00
Matthew Penner
c44842e517 chore: run prettier 2022-12-12 14:09:22 -07:00
Matthew Penner
e64e28839b Merge branch '1.0-develop' into develop 2022-12-12 14:06:52 -07:00
Matthew Penner
3b062ed2d9 yarn: upgrade dependencies 2022-12-12 14:01:31 -07:00
Matthew Penner
8425076f8b Merge branch '1.0-develop' into develop 2022-12-04 15:27:52 -07:00
Matthew Penner
ae27a8a65c Merge branch '1.0-develop' into develop 2022-12-04 15:10:06 -07:00
Matthew Penner
209711c826 ui(server): disable file manager upload, due to library issues 2022-11-29 14:39:48 -07:00
Matthew Penner
ee863fa262 phpstan 2022-11-29 10:56:16 -07:00
Matthew Penner
3ea6d45cda php-cs-fixer 2022-11-29 10:53:59 -07:00
Matthew Penner
16e34af773 nix: add panel and container packages 2022-11-29 10:48:14 -07:00
Matthew Penner
56839a14c5 Update Containerfile 2022-11-29 10:45:30 -07:00
Matthew Penner
fd356c7219 composer: update dependencies 2022-11-29 10:44:52 -07:00
Lance Pioch
a1a52754ad chore: add phpstan static analysis minimum (#4511) 2022-11-28 09:56:03 -07:00
Matthew Penner
3f7e2a565f Merge branch '1.0-develop' into develop 2022-11-28 09:33:33 -07:00
Matthew Penner
f76155aa13 ci(docker): update build-push-action from v2 to v3 2022-11-27 17:02:10 -07:00
Matthew Penner
dae40ee02d ci(docker): temporarily disable arm64 dev build 2022-11-27 15:57:54 -07:00
Matthew Penner
db4aa86fbc docker: cleanup, install shadow-utils 2022-11-27 12:41:35 -07:00
Matthew Penner
490690f1d0 docker: overhaul container image 2022-11-27 12:34:31 -07:00
Matthew Penner
c475d601f3 ui: remove unused codemirror 5 editor 2022-11-27 11:53:46 -07:00
Lance Pioch
3bf5a71802 PostgreSQL Support (#4486)
Co-authored-by: Matthew Penner <matthew@pterodactyl.io>
2022-11-25 13:29:04 -07:00
Matthew Penner
21613fa602 React 18 and Vite (#4510) 2022-11-25 13:25:03 -07:00
1565 changed files with 41581 additions and 45347 deletions

View File

@@ -2,12 +2,11 @@ APP_ENV=production
APP_DEBUG=false
APP_KEY=
APP_TIMEZONE=UTC
APP_URL=http://panel.test
APP_URL=http://panel.example.com
APP_LOCALE=en
APP_ENVIRONMENT_ONLY=true
LOG_CHANNEL=daily
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
@@ -15,30 +14,30 @@ DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=panel
DB_USERNAME=panel
DB_USERNAME=pterodactyl
DB_PASSWORD=
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_STORE=file
QUEUE_CONNECTION=sync
CACHE_DRIVER=file
QUEUE_CONNECTION=redis
SESSION_DRIVER=file
HASHIDS_SALT=
HASHIDS_LENGTH=8
MAIL_MAILER=log
MAIL_MAILER=smtp
MAIL_HOST=smtp.example.com
MAIL_PORT=25
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=no-reply@example.com
MAIL_FROM_NAME="Pelican Admin"
# Set this to your domain to prevent it defaulting to 'localhost', causing mail servers such as Gmail to reject your mail
MAIL_FROM_NAME="Pterodactyl Panel"
# You should set this to your domain to prevent it defaulting to 'localhost', causing
# mail servers such as Gmail to reject your mail.
#
# @see: https://github.com/pterodactyl/panel/pull/3110
# MAIL_EHLO_DOMAIN=panel.example.com
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null

View File

@@ -28,8 +28,8 @@ module.exports = {
// 'standard',
'eslint:recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:@typescript-eslint/recommended',
'plugin:jest-dom/recommended',
],
rules: {
eqeqeq: 'error',
@@ -37,6 +37,7 @@ module.exports = {
// TypeScript can infer this significantly better than eslint ever can.
'react/prop-types': 0,
'react/display-name': 0,
'react/no-unknown-property': ['error', {ignore: ['css']}],
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-non-null-assertion': 0,
// This setup is required to avoid a spam of errors when running eslint about React being

2
.github/FUNDING.yml vendored
View File

@@ -1 +1 @@
custom: [https://buy.stripe.com/14kdU99SI4UT7ni9AB, https://buy.stripe.com/14kaHXc0Q9b9372eUU]
github: [matthewpi]

View File

@@ -5,23 +5,23 @@ 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.
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
- type: textarea
attributes:
label: Current Behavior
description: Please provide a clear & concise description of the issue.
validations:
required: true
- type: textarea
- type: textarea
attributes:
label: Expected Behavior
description: Please describe what you expected to happen.
validations:
required: true
- type: textarea
- 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.
@@ -45,20 +45,20 @@ body:
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/pelican-dev/yolks:java_17
placeholder: ghcr.io/pterodactyl/yolks:java_17
- type: textarea
id: panel-logs
@@ -66,18 +66,18 @@ body:
label: Error Logs
description: |
Run the following command to collect logs on your system.
Wings: `sudo wings diagnostics`
Panel: `tail -n 150 /var/www/pelican/storage/logs/laravel-$(date +%F).log | nc pelipaste.com 99`
placeholder: "https://pelipaste.com/a1h6z"
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/pelican-dev/panel/issues) to see if an issue already exists for your problem.
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

View File

@@ -1,11 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Feature Request
url: https://github.com/pelican-dev/panel/discussions
about: Suggest a new feature or improvement for the software.
- name: Installation Help
url: https://pelican.dev/discord
url: https://discord.gg/pterodactyl
about: Please visit our Discord for help with your installation.
- name: General Question
url: https://pelican.dev/discord
about: Please visit our Discord for general questions about Pelican.
url: https://discord.gg/pterodactyl
about: Please visit our Discord for general questions about Pterodactyl.

View File

@@ -0,0 +1,32 @@
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

21
.github/docker/Caddyfile vendored Normal file
View File

@@ -0,0 +1,21 @@
:8080 {
root * /var/www/pterodactyl/public/
file_server
header {
-Server
-X-Powered-By
Referrer-Policy "same-origin"
X-Frame-Options "deny"
X-XSS-Protection "1; mode=block"
X-Content-Type-Options "nosniff"
}
encode gzip zstd
php_fastcgi 127.0.0.1:9000 {
trusted_proxies 172.20.0.0/16
}
try_files {path} {path}/ /index.php?{query}
}

View File

@@ -1,76 +0,0 @@
# Pelican Panel - Docker Image
This is a ready to use docker image for the panel.
## Requirements
This docker image requires some additional software to function. The software can either be provided in other containers (see the [docker-compose.yml](https://github.com/pelican-dev/panel/blob/develop/docker-compose.example.yml) as an example) or as existing instances.
A mysql database is required. We recommend the stock [MariaDB Image](https://hub.docker.com/_/mariadb/) image if you prefer to run it in a docker container. As a non-containerized option we recommend mariadb.
A caching software is required as well. We recommend the stock [Redis Image](https://hub.docker.com/_/redis/) image. You can choose any of the [supported options](#cache-drivers).
You can provide additional settings using a custom `.env` file or by setting the appropriate environment variables in the docker-compose file.
## Setup
Start the docker container and the required dependencies (either provide existing ones or start containers as well, see the [docker-compose.yml](https://github.com/pelican-dev/panel/blob/develop/docker-compose.example.yml) file as an example.
After the startup is complete you'll need to create a user.
If you are running the docker container without docker-compose, use:
```
docker exec -it <container id> php artisan p:user:make
```
If you are using docker compose use
```
docker-compose exec panel php artisan p:user:make
```
## Environment Variables
There are multiple environment variables to configure the panel when not providing your own `.env` file, see the following table for details on each available option.
Note: If your `APP_URL` starts with `https://` you need to provide an `LE_EMAIL` as well so Certificates can be generated.
| Variable | Description | Required |
|-------------------| ------------------------------------------------------------------------------ | -------- |
| `APP_URL` | The URL the panel will be reachable with (including protocol) | yes |
| `APP_TIMEZONE` | The timezone to use for the panel | yes |
| `LE_EMAIL` | The email used for letsencrypt certificate generation | yes |
| `DB_HOST` | The host of the mysql instance | yes |
| `DB_PORT` | The port of the mysql instance | yes |
| `DB_DATABASE` | The name of the mysql database | yes |
| `DB_USERNAME` | The mysql user | yes |
| `DB_PASSWORD` | The mysql password for the specified user | yes |
| `CACHE_STORE` | The cache driver (see [Cache drivers](#cache-drivers) for detais) | yes |
| `SESSION_DRIVER` | | yes |
| `QUEUE_DRIVER` | | yes |
| `REDIS_HOST` | The hostname or IP address of the redis database | yes |
| `REDIS_PASSWORD` | The password used to secure the redis database | maybe |
| `REDIS_PORT` | The port the redis database is using on the host | maybe |
| `MAIL_DRIVER` | The email driver (see [Mail drivers](#mail-drivers) for details) | yes |
| `MAIL_FROM` | The email that should be used as the sender email | yes |
| `MAIL_HOST` | The host of your mail driver instance | maybe |
| `MAIL_PORT` | The port of your mail driver instance | maybe |
| `MAIL_USERNAME` | The username for your mail driver | maybe |
| `MAIL_PASSWORD` | The password for your mail driver | maybe |
### Cache drivers
You can choose between different cache drivers depending on what you prefer.
We recommend redis when using docker as it can be started in a container easily.
| Driver | Description | Required variables |
| -------- | ------------------------------------ | ------------------------------------------------------ |
| redis | host where redis is running | `REDIS_HOST` |
| redis | port redis is running on | `REDIS_PORT` |
| redis | redis database password | `REDIS_PASSWORD` |
### Mail drivers
You can choose between different mail drivers according to your needs.
Every driver requires `MAIL_FROM` to be set.
| Driver | Description | Required variables |
| -------- | ------------------------------------ | ------------------------------------------------------------- |
| mail | uses the installed php mail | |
| mandrill | [Mandrill](http://www.mandrill.com/) | `MAIL_USERNAME` |
| postmark | [Postmark](https://postmarkapp.com/) | `MAIL_USERNAME` |
| mailgun | [Mailgun](https://www.mailgun.com/) | `MAIL_USERNAME`, `MAIL_HOST` |
| smtp | Any SMTP server can be configured | `MAIL_USERNAME`, `MAIL_HOST`, `MAIL_PASSWORD`, `MAIL_PORT` |

View File

@@ -1,51 +0,0 @@
# If using Ubuntu this file should be placed in:
# /etc/nginx/sites-available/
#
# If using CentOS this file should be placed in:
# /etc/nginx/conf.d/
#
server {
listen 80;
server_name _;
root /app/public;
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/panel.app-error.log error;
# allow larger file uploads and longer script runtimes
client_max_body_size 100m;
client_body_timeout 120s;
sendfile off;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# the fastcgi_pass path needs to be changed accordingly when using CentOS
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_PROXY "";
fastcgi_intercept_errors off;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
}
location ~ /\.ht {
deny all;
}
}

View File

@@ -1,70 +0,0 @@
# If using Ubuntu this file should be placed in:
# /etc/nginx/sites-available/
#
server {
listen 80;
server_name <domain>;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name <domain>;
root /app/public;
index index.php;
access_log /var/log/nginx/panel.app-access.log;
error_log /var/log/nginx/panel.app-error.log error;
# allow larger file uploads and longer script runtimes
client_max_body_size 100m;
client_body_timeout 120s;
sendfile off;
# strengthen ssl security
ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<domain>/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
# See the link below for more SSL information:
# https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
#
# ssl_dhparam /etc/ssl/certs/dhparam.pem;
# Add headers to serve security related headers
add_header Strict-Transport-Security "max-age=15768000; preload;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header Content-Security-Policy "frame-ancestors 'self'";
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_PROXY "";
fastcgi_intercept_errors off;
fastcgi_buffer_size 16k;
fastcgi_buffers 4 16k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
include /etc/nginx/fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}

View File

@@ -1,81 +0,0 @@
#!/bin/ash -e
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 /app/storage/logs/ /var/log/panel/
## check for .env file and generate app keys if missing
if [ -f /app/var/.env ]; then
echo "external vars exist."
rm -rf /app/.env
ln -s /app/var/.env /app/
else
echo "external vars don't exist."
rm -rf /app/.env
touch /app/var/.env
## manually generate a key because key generate --force fails
if [ -z $APP_KEY ]; then
echo -e "Generating key."
APP_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
echo -e "Generated app key: $APP_KEY"
echo -e "APP_KEY=$APP_KEY" > /app/var/.env
else
echo -e "APP_KEY exists in environment, using that."
echo -e "APP_KEY=$APP_KEY" > /app/var/.env
fi
ln -s /app/var/.env /app/
fi
echo "Checking if https is required."
if [ -f /etc/nginx/http.d/panel.conf ]; then
echo "Using nginx config already in place."
if [ $LE_EMAIL ]; then
echo "Checking for cert update"
certbot certonly -d $(echo $APP_URL | sed 's~http[s]*://~~g') --standalone -m $LE_EMAIL --agree-tos -n
else
echo "No letsencrypt email is set"
fi
else
echo "Checking if letsencrypt email is set."
if [ -z $LE_EMAIL ]; then
echo "No letsencrypt email is set using http config."
cp .github/docker/default.conf /etc/nginx/http.d/panel.conf
else
echo "writing ssl config"
cp .github/docker/default_ssl.conf /etc/nginx/http.d/panel.conf
echo "updating ssl config for domain"
sed -i "s|<domain>|$(echo $APP_URL | sed 's~http[s]*://~~g')|g" /etc/nginx/http.d/panel.conf
echo "generating certs"
certbot certonly -d $(echo $APP_URL | sed 's~http[s]*://~~g') --standalone -m $LE_EMAIL --agree-tos -n
fi
echo "Removing the default nginx config"
rm -rf /etc/nginx/http.d/default.conf
fi
if [[ -z $DB_PORT ]]; then
echo -e "DB_PORT not specified, defaulting to 3306"
DB_PORT=3306
fi
## check for DB up before starting the panel
echo "Checking database status."
until nc -z -v -w30 $DB_HOST $DB_PORT
do
echo "Waiting for database connection..."
# wait for 1 seconds before check again
sleep 1
done
## make sure the db is set up
echo -e "Migrating and Seeding D.B"
php artisan migrate --seed --force
## start cronjobs for the queue
echo -e "Starting cron jobs."
crond -L /var/log/crond -l 5
echo -e "Starting supervisord."
exec "$@"

21
.github/docker/php-fpm.conf vendored Normal file
View File

@@ -0,0 +1,21 @@
[global]
error_log = /dev/stderr
daemonize = no
[www]
user = nobody
group = nobody
listen = 127.0.0.1:9000
pm = dynamic
pm.start_servers = 4
pm.min_spare_servers = 4
pm.max_spare_servers = 16
pm.max_children = 64
pm.max_requests = 256
clear_env = no
catch_workers_output = yes
decorate_workers_output = no

View File

@@ -1,39 +1,57 @@
[unix_http_server]
file=/tmp/supervisor.sock ; path to your socket file
[supervisord]
logfile=/var/log/supervisord/supervisord.log ; supervisord log file
logfile_maxbytes=50MB ; maximum size of logfile before rotation
logfile_backups=2 ; number of backed up logfiles
loglevel=error ; info, debug, warn, trace
pidfile=/var/run/supervisord.pid ; pidfile location
nodaemon=false ; run supervisord as a daemon
minfds=1024 ; number of startup file descriptors
minprocs=200 ; number of process descriptors
user=root ; default user
childlogdir=/var/log/supervisord/ ; where child log files will live
logfile=/dev/stdout
logfile_maxbytes=0
loglevel=info
minfds=1024
minprocs=200
nodaemon=true
pidfile=/dev/null
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[unix_http_server]
file=/tmp/supervisor.sock
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
serverurl=unix:///tmp/supervisor.sock
[program:php-fpm]
command=/usr/local/sbin/php-fpm -F
autostart=true
autorestart=true
[rpcinterface:supervisor]
supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface
[program:queue-worker]
command=/usr/local/bin/php /app/artisan queue:work --queue=high,standard,low --sleep=3 --tries=3
user=nginx
autostart=true
autorestart=true
[program:nginx]
command=/usr/sbin/nginx -g 'daemon off;'
[program:caddy]
command=/usr/local/bin/caddy run --config /etc/caddy/Caddyfile
autostart=true
autorestart=true
priority=10
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:php-fpm]
command=/usr/sbin/php-fpm --nodaemonize
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=LOG_CHANNEL="stderr"
[program:queue-worker]
command=/usr/bin/php /var/www/pterodactyl/artisan queue:work --queue=standard --sleep=3 --tries=3
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=LOG_CHANNEL="stderr"
[program:yacron]
command=/usr/local/bin/yacron -c /etc/yacron.yaml
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=LOG_CHANNEL="stderr"

View File

@@ -1,16 +0,0 @@
[www]
user = nginx
group = nginx
listen = 127.0.0.1:9000
listen.owner = nginx
listen.group = nginx
listen.mode = 0750
pm = ondemand
pm.max_children = 9
pm.process_idle_timeout = 10s
pm.max_requests = 200
clear_env = no

8
.github/docker/yacron.yaml vendored Normal file
View File

@@ -0,0 +1,8 @@
jobs:
- name: scheduler
command:
- /usr/bin/php
- /var/www/pterodactyl/artisan
- schedule:run
schedule: "* * * * *"
utc: true

View File

@@ -1,30 +0,0 @@
name: Build
on:
pull_request:
branches:
- '**'
jobs:
ui:
name: UI
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [18]
steps:
- name: Code Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "yarn"
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build
run: yarn build:production

View File

@@ -1,71 +0,0 @@
name: Tests
on:
pull_request:
branches:
- '**'
jobs:
tests:
name: Tests
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: [8.2, 8.3]
database: ["mariadb:10.2", "mysql:8"]
services:
database:
image: ${{ matrix.database }}
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
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@v4
- name: Get cache directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache
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
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.example .env
- name: Install dependencies
run: composer install --no-interaction --no-suggest --prefer-dist
- name: Generate App Key
run: php artisan key:generate
- name: Unit tests
run: vendor/bin/phpunit tests/Unit
if: ${{ always() }}
env:
DB_HOST: UNIT_NO_DB
SKIP_MIGRATIONS: true
- name: Integration tests
run: vendor/bin/phpunit tests/Integration
env:
DB_PORT: ${{ job.services.database.ports[3306] }}
DB_USERNAME: root

View File

@@ -1,30 +0,0 @@
name: "CLA Assistant"
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened,closed,synchronize]
permissions:
actions: write
contents: write
pull-requests: write
statuses: write
jobs:
CLAAssistant:
runs-on: ubuntu-latest
steps:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
uses: contributor-assistant/github-action@v2.3.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
path-to-signatures: 'version1/cla.json'
path-to-document: 'https://github.com/pelican-dev/panel/blob/3.x/contributor_license_agreement.md'
branch: 'main'
allowlist: dependabot[bot]
remote-organization-name: pelican-dev
remote-repository-name: cla-signatures

67
.github/workflows/docker.yaml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: Docker
on:
push:
branches:
- develop
- 1.0-develop
pull_request:
branches:
- develop
- 1.0-develop
release:
types:
- published
jobs:
push:
name: Push
runs-on: ubuntu-22.04
steps:
- name: Code checkout
uses: actions/checkout@v3
- name: Fetch metadata
id: metadata
uses: docker/metadata-action@v4
with:
images: ghcr.io/pterodactyl/panel
flavor: |
latest=false
tags: |
type=raw,value=latest,enable=${{ github.event_name == 'release' && github.event.action == 'published' && github.event.release.prerelease == false }}
type=ref,event=tag
type=ref,event=branch
- name: Setup QEMU
uses: docker/setup-qemu-action@v2
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
if: "github.event_name != 'pull_request'"
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Update version
if: "github.event_name == 'release' && github.event.action == 'published'"
env:
REF: ${{ github.event.release.tag_name }}
run: |
sed -i "s/ 'version' => 'canary',/ 'version' => '${REF:1}',/" config/app.php
- name: Build and Push
uses: docker/build-push-action@v4
with:
context: .
file: ./Containerfile
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/amd64,linux/arm64
labels: ${{ steps.metadata.outputs.labels }}
tags: ${{ steps.metadata.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max

210
.github/workflows/laravel.yaml vendored Normal file
View File

@@ -0,0 +1,210 @@
name: Laravel
on:
push:
branches:
- "develop"
- "1.0-develop"
pull_request:
branches:
- "develop"
- "1.0-develop"
jobs:
analysis:
name: Static Analysis
runs-on: ubuntu-22.04
env:
APP_ENV: testing
APP_DEBUG: "true"
APP_KEY: SomeRandomString3232RandomString
CACHE_DRIVER: array
MAIL_MAILER: array
SESSION_DRIVER: array
QUEUE_CONNECTION: sync
steps:
- name: Code checkout
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.1
extensions: bcmath, cli, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
- name: Install dependencies
run: composer install --no-interaction --no-progress --no-suggest --prefer-dist
- name: Analyze
run: vendor/bin/phpstan analyse
lint:
name: Lint
runs-on: ubuntu-22.04
steps:
- name: Code checkout
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
# TODO: Update to 8.2 once php-cs-fixer supports it
php-version: 8.1
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
- 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
mysql:
name: Tests
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
php: [8.1, 8.2]
database: ["mariadb:10.2", "mariadb:10.9", "mysql:8"]
services:
database:
image: docker.io/library/${{ matrix.database }}
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testing
ports:
- 3306/tcp
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
env:
APP_ENV: testing
APP_DEBUG: "true"
APP_KEY: SomeRandomString3232RandomString
APP_THEME: pterodactyl
APP_TIMEZONE: UTC
APP_URL: http://localhost/
APP_ENVIRONMENT_ONLY: "true"
CACHE_DRIVER: array
MAIL_MAILER: array
SESSION_DRIVER: array
QUEUE_CONNECTION: sync
HASHIDS_SALT: test123
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_DATABASE: testing
DB_USERNAME: root
steps:
- name: Code checkout
uses: actions/checkout@v3
- name: Get cache directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache
uses: actions/cache@v3
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
with:
php-version: ${{ matrix.php }}
extensions: bcmath, cli, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
- 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
env:
DB_HOST: UNIT_NO_DB
- name: Integration tests
run: vendor/bin/phpunit tests/Integration
env:
DB_PORT: ${{ job.services.database.ports[3306] }}
postgres:
name: Tests
runs-on: ubuntu-22.04
if: "!contains(github.event.head_commit.message, 'skip ci') && !contains(github.event.head_commit.message, 'ci skip')"
strategy:
fail-fast: false
matrix:
php: [8.1, 8.2]
database: ["postgres:13", "postgres:14", "postgres:15"]
services:
database:
image: docker.io/library/${{ matrix.database }}
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: testing
ports:
- 5432/tcp
options: --health-cmd=pg_isready --health-interval=10s --health-timeout=5s --health-retries=3
env:
APP_ENV: testing
APP_DEBUG: "true"
APP_KEY: SomeRandomString3232RandomString
APP_THEME: pterodactyl
APP_TIMEZONE: UTC
APP_URL: http://localhost/
APP_ENVIRONMENT_ONLY: "true"
CACHE_DRIVER: array
MAIL_MAILER: array
SESSION_DRIVER: array
QUEUE_CONNECTION: sync
HASHIDS_SALT: test123
DB_CONNECTION: pgsql
DB_HOST: 127.0.0.1
DB_DATABASE: testing
DB_USERNAME: postgres
DB_PASSWORD: postgres
steps:
- name: Code checkout
uses: actions/checkout@v3
- name: Get cache directory
id: composer-cache
run: |
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache
uses: actions/cache@v3
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
with:
php-version: ${{ matrix.php }}
extensions: bcmath, cli, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
- 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
env:
DB_HOST: UNIT_NO_DB
- name: Integration tests
run: vendor/bin/phpunit tests/Integration
env:
DB_PORT: ${{ job.services.database.ports[5432] }}

View File

@@ -1,31 +0,0 @@
name: Lint
on:
pull_request:
branches:
- '**'
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Code Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "8.2"
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
tools: composer:v2
coverage: none
- name: Setup .env
run: cp .env.example .env
- name: Install dependencies
run: composer install --no-interaction --no-progress --prefer-dist
- name: Pint
run: vendor/bin/pint --test

View File

@@ -8,30 +8,33 @@ on:
jobs:
release:
name: Release
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Code checkout
uses: actions/checkout@v3
- name: Install pnpm
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16
cache: "yarn"
node-version: 18
cache: pnpm
- name: Install dependencies
run: yarn install --frozen-lockfile
run: pnpm install
- name: Build
run: yarn build:production
run: pnpm run build
- name: Create release branch and bump version
env:
REF: ${{ github.ref }}
run: |
BRANCH=release/${REF:10}
git config --local user.email "ci@pelican.dev"
git config --local user.name "Pelican CI"
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
@@ -41,7 +44,7 @@ jobs:
- 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 CODE_OF_CONDUCT.md CONTRIBUTING.md flake.lock flake.nix phpstan.neon phpunit.xml shell.nix
tar -czf panel.tar.gz * .editorconfig .env.example .eslintignore .eslintrc.js .gitignore .prettierrc.json
- name: Extract changelog

63
.github/workflows/ui.yaml vendored Normal file
View File

@@ -0,0 +1,63 @@
name: UI
on:
push:
branches:
- "develop"
- "1.0-develop"
pull_request:
branches:
- "develop"
- "1.0-develop"
jobs:
lint:
name: Lint
runs-on: ubuntu-22.04
steps:
- name: Code checkout
uses: actions/checkout@v3
- name: Install pnpm
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Lint
run: pnpm run lint
tests:
name: Tests
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
node: [16, 18]
steps:
- name: Code checkout
uses: actions/checkout@v3
- name: Install pnpm
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm run build
- name: Tests
run: pnpm run test

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
shamefully-hoist=true

4
.prettierignore Normal file
View File

@@ -0,0 +1,4 @@
.github
public
node_modules
resources/views

View File

@@ -4,6 +4,19 @@
"useTabs": false,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"endOfLine": "lf"
"jsxSingleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "lf",
"overrides": [
{
"files": ["**/*.md"],
"options": {
"tabWidth": 2,
"useTabs": false,
"singleQuote": false
}
}
]
}

1769
CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

74
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,74 @@
# 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/

31
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,31 @@
# 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.
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.
### Responsible Disclosure
This is a fairly in-depth project and makes use of a lot of parts. 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.
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
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.
You can also find us on [Discord](https://discord.gg/pterodactyl).

77
Containerfile Normal file
View File

@@ -0,0 +1,77 @@
# Stage 1 - Builder
FROM --platform=$TARGETOS/$TARGETARCH registry.access.redhat.com/ubi9/nodejs-18-minimal AS builder
USER 0
RUN npm install -g pnpm
WORKDIR /var/www/pterodactyl
COPY --chown=1001:0 public ./public
COPY --chown=1001:0 resources/scripts ./resources/scripts
COPY --chown=1001:0 .eslintignore .eslintrc.js .npmrc .prettierrc.json package.json pnpm-lock.yaml tailwind.config.js tsconfig.json vite.config.ts .
RUN /opt/app-root/src/.npm-global/bin/pnpm install \
&& /opt/app-root/src/.npm-global/bin/pnpm build \
&& rm -rf resources/scripts .eslintignore .eslintrc.yml .npmrc package.json pnpm-lock.yaml tailwind.config.js tsconfig.json vite.config.ts node_modules
USER 1001
COPY --chown=1001:0 app ./app
COPY --chown=1001:0 bootstrap ./bootstrap
COPY --chown=1001:0 config ./config
COPY --chown=1001:0 database ./database
COPY --chown=1001:0 resources/lang ./resources/lang
COPY --chown=1001:0 resources/views ./resources/views
COPY --chown=1001:0 routes ./routes
COPY --chown=1001:0 .env.example ./.env
COPY --chown=1001:0 artisan CHANGELOG.md composer.json composer.lock LICENSE.md README.md SECURITY.md .
# Stage 2 - Final
FROM --platform=$TARGETOS/$TARGETARCH registry.access.redhat.com/ubi9/ubi-minimal
RUN microdnf update -y \
&& rpm --install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm \
&& rpm --install https://rpms.remirepo.net/enterprise/remi-release-9.rpm \
&& microdnf update -y \
&& microdnf install -y ca-certificates shadow-utils tar tzdata unzip wget \
# ref; https://bugzilla.redhat.com/show_bug.cgi?id=1870814
&& microdnf reinstall -y tzdata \
&& microdnf module -y reset php \
&& microdnf module -y enable php:remi-8.2 \
&& microdnf install -y composer cronie php-{bcmath,cli,common,fpm,gd,gmp,intl,json,mbstring,mysqlnd,opcache,pdo,pecl-redis5,pecl-zip,phpiredis,pgsql,process,sodium,xml,zstd} supervisor \
&& rm /etc/php-fpm.d/www.conf \
&& useradd --home-dir /var/lib/caddy --create-home caddy \
&& mkdir /etc/caddy \
&& wget -O /usr/local/bin/yacron https://github.com/gjcarneiro/yacron/releases/download/0.17.0/yacron-0.17.0-x86_64-unknown-linux-gnu \
&& chmod 755 /usr/local/bin/yacron \
&& microdnf remove -y tar wget \
&& microdnf clean all
COPY --chown=caddy:caddy --from=builder /var/www/pterodactyl /var/www/pterodactyl
WORKDIR /var/www/pterodactyl
RUN mkdir -p /tmp/pterodactyl/cache /tmp/pterodactyl/framework/{cache,sessions,views} storage/framework \
&& rm -rf bootstrap/cache storage/framework/sessions storage/framework/views storage/framework/cache \
&& ln -s /tmp/pterodactyl/cache /var/www/pterodactyl/bootstrap/cache \
&& ln -s /tmp/pterodactyl/framework/cache /var/www/pterodactyl/storage/framework/cache \
&& ln -s /tmp/pterodactyl/framework/sessions /var/www/pterodactyl/storage/framework/sessions \
&& ln -s /tmp/pterodactyl/framework/views /var/www/pterodactyl/storage/framework/views \
&& chmod -R 755 /var/www/pterodactyl/storage/* /tmp/pterodactyl/cache \
&& chown -R caddy:caddy /var/www/pterodactyl /tmp/pterodactyl/{cache,framework}
USER caddy
ENV USER=caddy
RUN composer install --no-dev --optimize-autoloader \
&& rm -rf bootstrap/cache/*.php \
&& rm -rf .env storage/logs/*.log
COPY --from=docker.io/library/caddy:latest /usr/bin/caddy /usr/local/bin/caddy
COPY .github/docker/Caddyfile /etc/caddy/Caddyfile
COPY .github/docker/php-fpm.conf /etc/php-fpm.conf
COPY .github/docker/supervisord.conf /etc/supervisord.conf
COPY .github/docker/yacron.yaml /etc/yacron.yaml
EXPOSE 8080
CMD ["/usr/bin/supervisord", "--configuration=/etc/supervisord.conf"]

View File

@@ -1,41 +0,0 @@
# Stage 0:
# 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
FROM --platform=$TARGETOS/$TARGETARCH mhart/alpine-node:14
WORKDIR /app
COPY . ./
RUN yarn install --frozen-lockfile \
&& yarn run build:production
# 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
WORKDIR /app
COPY . ./
COPY --from=0 /app/public/assets ./public/assets
RUN apk add --no-cache --update ca-certificates dcron curl git supervisor tar unzip nginx libpng-dev libxml2-dev libzip-dev certbot certbot-nginx \
&& docker-php-ext-configure zip \
&& docker-php-ext-install bcmath gd pdo_mysql zip \
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& cp .env.example .env \
&& mkdir -p bootstrap/cache/ storage/logs storage/framework/sessions storage/framework/views storage/framework/cache \
&& 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 \
&& echo "* * * * * /usr/local/bin/php /app/artisan schedule:run >> /dev/null 2>&1" >> /var/spool/cron/crontabs/root \
&& echo "0 23 * * * certbot renew --nginx --quiet" >> /var/spool/cron/crontabs/root \
&& sed -i s/ssl_session_cache/#ssl_session_cache/g /etc/nginx/nginx.conf \
&& mkdir -p /var/run/php /var/run/nginx
COPY .github/docker/default.conf /etc/nginx/http.d/default.conf
COPY .github/docker/www.conf /usr/local/etc/php-fpm.conf
COPY .github/docker/supervisord.conf /etc/supervisord.conf
EXPOSE 80 443
ENTRYPOINT [ "/bin/ash", ".github/docker/entrypoint.sh" ]
CMD [ "supervisord", "-n", "-c", "/etc/supervisord.conf" ]

24
LICENSE.md Normal file
View File

@@ -0,0 +1,24 @@
# The MIT License (MIT)
```
Pterodactyl®
Copyright © Dane Everitt <dane@daneeveritt.com> and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

72
README.md Normal file
View File

@@ -0,0 +1,72 @@
[![Logo Image](https://cdn.pterodactyl.io/logos/new/pterodactyl_logo.png)](https://pterodactyl.io)
![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/pterodactyl/panel/laravel.yaml?label=Tests&style=for-the-badge&branch=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
in mind, Pterodactyl runs all game servers in isolated Docker containers while exposing a beautiful and intuitive
UI to end users.
Stop settling for less. Make game servers a first class citizen on your platform.
![Image](https://cdn.pterodactyl.io/site-assets/pterodactyl_v1_demo.gif)
## Documentation
* [Panel Documentation](https://pterodactyl.io/panel/1.0/getting_started.html)
* [Wings Documentation](https://pterodactyl.io/wings/1.0/installing.html)
* [Community Guides](https://pterodactyl.io/community/about.html)
* Or, get additional help [via Discord](https://discord.gg/pterodactyl)
## Sponsors
I would like to extend my sincere thanks to the following sponsors for helping fund Pterodactyl's development.
[Interested in becoming a sponsor?](https://github.com/sponsors/matthewpi)
| Company | About |
|-----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [**Aussie Server Hosts**](https://aussieserverhosts.com/) | No frills Australian Owned and operated High Performance Server hosting for some of the most demanding games serving Australia and New Zealand. |
| [**BisectHosting**](https://www.bisecthosting.com/) | BisectHosting provides Minecraft, Valheim and other server hosting services with the highest reliability and lightning fast support since 2012. |
| [**MineStrator**](https://minestrator.com/) | Looking for the most highend French hosting company for your minecraft server? More than 24,000 members on our discord trust us. Give us a try! |
| [**VibeGAMES**](https://vibegames.net/) | VibeGAMES is a game server provider that specializes in DDOS protection for the games we offer. We have multiple locations in the US, Brazil, France, Germany, Singapore, Australia and South Africa. |
| [**HostEZ**](https://hostez.io) | US & EU Rust & Minecraft Hosting. DDoS Protected bare metal, VPS and colocation with low latency, high uptime and maximum availability. EZ! |
| [**Blueprint**](https://blueprint.zip/?pterodactyl=true) | Create and install Pterodactyl addons and themes with the growing Blueprint framework - the package-manager for Pterodactyl. Use multiple modifications at once without worrying about conflicts and make use of the large extension ecosystem. |
### Supported Games
Pterodactyl supports a wide variety of games by utilizing Docker containers to isolate each instance. This gives
you the power to run game servers without bloating machines with a host of additional dependencies.
Some of our core supported games include:
* Minecraft — including Paper, Sponge, Bungeecord, Waterfall, and more
* Rust
* Terraria
* Teamspeak
* Mumble
* Team Fortress 2
* Counter Strike: Global Offensive
* Garry's Mod
* ARK: Survival Evolved
In addition to our standard nest of supported games, our community is constantly pushing the limits of this software
and there are plenty more games available provided by the community. Some of these games include:
* Factorio
* San Andreas: MP
* Pocketmine MP
* Squad
* Xonotic
* Starmade
* Discord ATLBot, and most other Node.js/Python discord bots
* [and many more...](https://github.com/parkervcp/eggs)
## License
Pterodactyl® Copyright © 2015 - 2022 Dane Everitt and contributors.
Code released under the [MIT License](./LICENSE.md).

19
SECURITY.md Normal file
View File

@@ -0,0 +1,19 @@
# Security Policy
## 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.11.x | wings@1.11.x | :white_check_mark: |
| 0.7.x | daemon@0.6.x | :x: |
## 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`.
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.

View File

@@ -1,33 +1,33 @@
<?php
namespace App\Console\Commands\Environment;
namespace Pterodactyl\Console\Commands\Environment;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel;
use App\Traits\Commands\EnvironmentWriterTrait;
use Pterodactyl\Traits\Commands\EnvironmentWriterTrait;
class AppSettingsCommand extends Command
{
use EnvironmentWriterTrait;
public const CACHE_DRIVERS = [
'redis' => 'Redis',
'redis' => 'Redis (recommended)',
'memcached' => 'Memcached',
'file' => 'Filesystem (recommended)',
'file' => 'Filesystem',
];
public const SESSION_DRIVERS = [
'redis' => 'Redis',
'redis' => 'Redis (recommended)',
'memcached' => 'Memcached',
'database' => 'MySQL Database',
'file' => 'Filesystem (recommended)',
'file' => 'Filesystem',
'cookie' => 'Cookie',
];
public const QUEUE_DRIVERS = [
'redis' => 'Redis',
'redis' => 'Redis (recommended)',
'database' => 'MySQL Database',
'sync' => 'Sync (recommended)',
'sync' => 'Sync',
];
protected $description = 'Configure basic environment settings for the Panel.';
@@ -43,7 +43,8 @@ class AppSettingsCommand extends Command
{--redis-host= : Redis host to use for connections.}
{--redis-pass= : Password used to connect to redis.}
{--redis-port= : Port to connect to redis over.}
{--settings-ui= : Enable or disable the settings UI.}';
{--settings-ui= : Enable or disable the settings UI.}
{--telemetry= : Enable or disable anonymous telemetry.}';
protected array $variables = [];
@@ -58,7 +59,7 @@ class AppSettingsCommand extends Command
/**
* Handle command execution.
*
* @throws \App\Exceptions\PanelException
* @throws \Pterodactyl\Exceptions\PterodactylException
*/
public function handle(): int
{
@@ -69,7 +70,7 @@ class AppSettingsCommand extends Command
$this->output->comment('Provide the email address that eggs exported by this Panel should be from. This should be a valid email address.');
$this->variables['APP_SERVICE_AUTHOR'] = $this->option('author') ?? $this->ask(
'Egg Author Email',
config('panel.service.author', 'unknown@unknown.com')
config('pterodactyl.service.author', 'unknown@unknown.com')
);
if (!filter_var($this->variables['APP_SERVICE_AUTHOR'], FILTER_VALIDATE_EMAIL)) {
@@ -91,21 +92,21 @@ class AppSettingsCommand extends Command
config('app.timezone')
);
$selected = config('cache.default', 'file');
$this->variables['CACHE_STORE'] = $this->option('cache') ?? $this->choice(
$selected = config('cache.default', 'redis');
$this->variables['CACHE_DRIVER'] = $this->option('cache') ?? $this->choice(
'Cache Driver',
self::CACHE_DRIVERS,
array_key_exists($selected, self::CACHE_DRIVERS) ? $selected : null
);
$selected = config('session.driver', 'file');
$selected = config('session.driver', 'redis');
$this->variables['SESSION_DRIVER'] = $this->option('session') ?? $this->choice(
'Session Driver',
self::SESSION_DRIVERS,
array_key_exists($selected, self::SESSION_DRIVERS) ? $selected : null
);
$selected = config('queue.default', 'sync');
$selected = config('queue.default', 'redis');
$this->variables['QUEUE_CONNECTION'] = $this->option('queue') ?? $this->choice(
'Queue Driver',
self::QUEUE_DRIVERS,
@@ -118,6 +119,12 @@ class AppSettingsCommand extends Command
$this->variables['APP_ENVIRONMENT_ONLY'] = $this->confirm('Enable UI based settings editor?', true) ? 'false' : 'true';
}
$this->output->comment('Please reference https://pterodactyl.io/panel/1.0/additional_configuration.html#telemetry for more detailed information regarding telemetry data and collection.');
$this->variables['PTERODACTYL_TELEMETRY_ENABLED'] = $this->option('telemetry') ?? $this->confirm(
'Enable sending anonymous telemetry data?',
config('pterodactyl.telemetry.enabled', true)
) ? 'true' : 'false';
// Make sure session cookies are set as "secure" when using HTTPS
if (str_starts_with($this->variables['APP_URL'], 'https://')) {
$this->variables['SESSION_SECURE_COOKIE'] = 'true';

View File

@@ -1,11 +1,11 @@
<?php
namespace App\Console\Commands\Environment;
namespace Pterodactyl\Console\Commands\Environment;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Database\DatabaseManager;
use App\Traits\Commands\EnvironmentWriterTrait;
use Pterodactyl\Traits\Commands\EnvironmentWriterTrait;
class DatabaseSettingsCommand extends Command
{
@@ -32,6 +32,8 @@ class DatabaseSettingsCommand extends Command
/**
* Handle command execution.
*
* @throws \Pterodactyl\Exceptions\PterodactylException
*/
public function handle(): int
{
@@ -54,7 +56,7 @@ class DatabaseSettingsCommand extends Command
$this->output->note('Using the "root" account for MySQL connections is not only highly frowned upon, it is also not allowed by this application. You\'ll need to have created a MySQL user for this software.');
$this->variables['DB_USERNAME'] = $this->option('username') ?? $this->ask(
'Database Username',
config('database.connections.mysql.username', 'panel')
config('database.connections.mysql.username', 'pterodactyl')
);
$askForMySQLPassword = true;
@@ -74,7 +76,7 @@ class DatabaseSettingsCommand extends Command
$this->output->error('Your connection credentials have NOT been saved. You will need to provide valid connection information before proceeding.');
if ($this->confirm('Go back and try again?')) {
$this->database->disconnect('_panel_command_test');
$this->database->disconnect('_pterodactyl_command_test');
return $this->handle();
}
@@ -94,7 +96,7 @@ class DatabaseSettingsCommand extends Command
*/
private function testMySQLConnection()
{
config()->set('database.connections._panel_command_test', [
config()->set('database.connections._pterodactyl_command_test', [
'driver' => 'mysql',
'host' => $this->variables['DB_HOST'],
'port' => $this->variables['DB_PORT'],
@@ -106,6 +108,6 @@ class DatabaseSettingsCommand extends Command
'strict' => true,
]);
$this->database->connection('_panel_command_test')->getPdo();
$this->database->connection('_pterodactyl_command_test')->getPdo();
}
}

View File

@@ -1,9 +1,10 @@
<?php
namespace App\Console\Commands\Environment;
namespace Pterodactyl\Console\Commands\Environment;
use Illuminate\Console\Command;
use App\Traits\Commands\EnvironmentWriterTrait;
use Pterodactyl\Traits\Commands\EnvironmentWriterTrait;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
class EmailSettingsCommand extends Command
{
@@ -24,12 +25,20 @@ class EmailSettingsCommand extends Command
protected array $variables = [];
/**
* EmailSettingsCommand constructor.
*/
public function __construct(private ConfigRepository $config)
{
parent::__construct();
}
/**
* Handle command execution.
*
* @throws \App\Exceptions\PanelException
* @throws \Pterodactyl\Exceptions\PterodactylException
*/
public function handle(): void
public function handle()
{
$this->variables['MAIL_DRIVER'] = $this->option('driver') ?? $this->choice(
trans('command/messages.environment.mail.ask_driver'),
@@ -40,7 +49,7 @@ class EmailSettingsCommand extends Command
'mandrill' => 'Mandrill Transactional Email',
'postmark' => 'Postmark Transactional Email',
],
config('mail.default', 'smtp')
$this->config->get('mail.default', 'smtp')
);
$method = 'setup' . studly_case($this->variables['MAIL_DRIVER']) . 'DriverVariables';
@@ -50,12 +59,12 @@ class EmailSettingsCommand extends Command
$this->variables['MAIL_FROM_ADDRESS'] = $this->option('email') ?? $this->ask(
trans('command/messages.environment.mail.ask_mail_from'),
config('mail.from.address')
$this->config->get('mail.from.address')
);
$this->variables['MAIL_FROM_NAME'] = $this->option('from') ?? $this->ask(
trans('command/messages.environment.mail.ask_mail_name'),
config('mail.from.name')
$this->config->get('mail.from.name')
);
$this->writeToEnvironment($this->variables);
@@ -71,17 +80,17 @@ class EmailSettingsCommand extends Command
{
$this->variables['MAIL_HOST'] = $this->option('host') ?? $this->ask(
trans('command/messages.environment.mail.ask_smtp_host'),
config('mail.mailers.smtp.host')
$this->config->get('mail.mailers.smtp.host')
);
$this->variables['MAIL_PORT'] = $this->option('port') ?? $this->ask(
trans('command/messages.environment.mail.ask_smtp_port'),
config('mail.mailers.smtp.port')
$this->config->get('mail.mailers.smtp.port')
);
$this->variables['MAIL_USERNAME'] = $this->option('username') ?? $this->ask(
trans('command/messages.environment.mail.ask_smtp_username'),
config('mail.mailers.smtp.username')
$this->config->get('mail.mailers.smtp.username')
);
$this->variables['MAIL_PASSWORD'] = $this->option('password') ?? $this->secret(
@@ -91,7 +100,7 @@ class EmailSettingsCommand extends Command
$this->variables['MAIL_ENCRYPTION'] = $this->option('encryption') ?? $this->choice(
trans('command/messages.environment.mail.ask_encryption'),
['tls' => 'TLS', 'ssl' => 'SSL', '' => 'None'],
config('mail.mailers.smtp.encryption', 'tls')
$this->config->get('mail.mailers.smtp.encryption', 'tls')
);
}
@@ -102,17 +111,17 @@ class EmailSettingsCommand extends Command
{
$this->variables['MAILGUN_DOMAIN'] = $this->option('host') ?? $this->ask(
trans('command/messages.environment.mail.ask_mailgun_domain'),
config('services.mailgun.domain')
$this->config->get('services.mailgun.domain')
);
$this->variables['MAILGUN_SECRET'] = $this->option('password') ?? $this->ask(
trans('command/messages.environment.mail.ask_mailgun_secret'),
config('services.mailgun.secret')
$this->config->get('services.mailgun.secret')
);
$this->variables['MAILGUN_ENDPOINT'] = $this->option('endpoint') ?? $this->ask(
trans('command/messages.environment.mail.ask_mailgun_endpoint'),
config('services.mailgun.endpoint')
$this->config->get('services.mailgun.endpoint')
);
}
@@ -123,7 +132,7 @@ class EmailSettingsCommand extends Command
{
$this->variables['MANDRILL_SECRET'] = $this->option('password') ?? $this->ask(
trans('command/messages.environment.mail.ask_mandrill_secret'),
config('services.mandrill.secret')
$this->config->get('services.mandrill.secret')
);
}
@@ -137,7 +146,7 @@ class EmailSettingsCommand extends Command
$this->variables['MAIL_PORT'] = 587;
$this->variables['MAIL_USERNAME'] = $this->variables['MAIL_PASSWORD'] = $this->option('username') ?? $this->ask(
trans('command/messages.environment.mail.ask_postmark_username'),
config('mail.username')
$this->config->get('mail.username')
);
}
}

View File

@@ -1,9 +1,10 @@
<?php
namespace App\Console\Commands;
namespace Pterodactyl\Console\Commands;
use Illuminate\Console\Command;
use App\Services\Helpers\SoftwareVersionService;
use Pterodactyl\Services\Helpers\SoftwareVersionService;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
class InfoCommand extends Command
{
@@ -14,7 +15,7 @@ class InfoCommand extends Command
/**
* VersionCommand constructor.
*/
public function __construct(private SoftwareVersionService $versionService)
public function __construct(private ConfigRepository $config, private SoftwareVersionService $softwareVersionService)
{
parent::__construct();
}
@@ -22,51 +23,51 @@ class InfoCommand extends Command
/**
* Handle execution of command.
*/
public function handle(): void
public function handle()
{
$this->output->title('Version Information');
$this->table([], [
['Panel Version', config('app.version')],
['Latest Version', $this->versionService->getPanel()],
['Up-to-Date', $this->versionService->isLatestPanel() ? 'Yes' : $this->formatText('No', 'bg=red')],
['Unique Identifier', config('panel.service.author')],
['Panel Version', $this->softwareVersionService->getCurrentVersion()],
['Latest Version', $this->softwareVersionService->getLatestPanel()],
['Up-to-Date', $this->softwareVersionService->isLatestPanel() ? 'Yes' : $this->formatText('No', 'bg=red')],
['Unique Identifier', $this->config->get('pterodactyl.service.author')],
], 'compact');
$this->output->title('Application Configuration');
$this->table([], [
['Environment', $this->formatText(config('app.env'), config('app.env') === 'production' ?: 'bg=red')],
['Debug Mode', $this->formatText(config('app.debug') ? 'Yes' : 'No', !config('app.debug') ?: 'bg=red')],
['Installation URL', config('app.url')],
['Environment', $this->formatText($this->config->get('app.env'), $this->config->get('app.env') === 'production' ?: 'bg=red')],
['Debug Mode', $this->formatText($this->config->get('app.debug') ? 'Yes' : 'No', !$this->config->get('app.debug') ?: 'bg=red')],
['Installation URL', $this->config->get('app.url')],
['Installation Directory', base_path()],
['Timezone', config('app.timezone')],
['Cache Driver', config('cache.default')],
['Queue Driver', config('queue.default')],
['Session Driver', config('session.driver')],
['Filesystem Driver', config('filesystems.default')],
['Default Theme', config('themes.active')],
['Proxies', config('trustedproxies.proxies')],
['Timezone', $this->config->get('app.timezone')],
['Cache Driver', $this->config->get('cache.default')],
['Queue Driver', $this->config->get('queue.default')],
['Session Driver', $this->config->get('session.driver')],
['Filesystem Driver', $this->config->get('filesystems.default')],
['Default Theme', $this->config->get('themes.active')],
['Proxies', $this->config->get('trustedproxies.proxies')],
], 'compact');
$this->output->title('Database Configuration');
$driver = config('database.default');
$driver = $this->config->get('database.default');
$this->table([], [
['Driver', $driver],
['Host', config("database.connections.$driver.host")],
['Port', config("database.connections.$driver.port")],
['Database', config("database.connections.$driver.database")],
['Username', config("database.connections.$driver.username")],
['Host', $this->config->get("database.connections.$driver.host")],
['Port', $this->config->get("database.connections.$driver.port")],
['Database', $this->config->get("database.connections.$driver.database")],
['Username', $this->config->get("database.connections.$driver.username")],
], 'compact');
// TODO: Update this to handle other mail drivers
$this->output->title('Email Configuration');
$this->table([], [
['Driver', config('mail.default')],
['Host', config('mail.mailers.smtp.host')],
['Port', config('mail.mailers.smtp.port')],
['Username', config('mail.mailers.smtp.username')],
['From Address', config('mail.from.address')],
['From Name', config('mail.from.name')],
['Encryption', config('mail.mailers.smtp.encryption')],
['Driver', $this->config->get('mail.default')],
['Host', $this->config->get('mail.mailers.smtp.host')],
['Port', $this->config->get('mail.mailers.smtp.port')],
['Username', $this->config->get('mail.mailers.smtp.username')],
['From Address', $this->config->get('mail.from.address')],
['From Name', $this->config->get('mail.from.name')],
['Encryption', $this->config->get('mail.mailers.smtp.encryption')],
], 'compact');
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Pterodactyl\Console\Commands\Location;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Pterodactyl\Services\Locations\LocationDeletionService;
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
class DeleteLocationCommand extends Command
{
protected $description = 'Deletes a location from the Panel.';
protected $signature = 'p:location:delete {--short= : The short code of the location to delete.}';
protected Collection $locations;
/**
* DeleteLocationCommand constructor.
*/
public function __construct(
private LocationDeletionService $deletionService,
private LocationRepositoryInterface $repository
) {
parent::__construct();
}
/**
* Respond to the command request.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
* @throws \Pterodactyl\Exceptions\Service\Location\HasActiveNodesException
*/
public function handle()
{
$this->locations = $this->locations ?? $this->repository->all();
$short = $this->option('short') ?? $this->anticipate(
trans('command/messages.location.ask_short'),
$this->locations->pluck('short')->toArray()
);
$location = $this->locations->where('short', $short)->first();
if (is_null($location)) {
$this->error(trans('command/messages.location.no_location_found'));
if ($this->input->isInteractive()) {
$this->handle();
}
return;
}
$this->deletionService->handle($location->id);
$this->line(trans('command/messages.location.deleted'));
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Pterodactyl\Console\Commands\Location;
use Illuminate\Console\Command;
use Pterodactyl\Services\Locations\LocationCreationService;
class MakeLocationCommand extends Command
{
protected $signature = 'p:location:make
{--short= : The shortcode name of this location (ex. us1).}
{--long= : A longer description of this location.}';
protected $description = 'Creates a new location on the system via the CLI.';
/**
* Create a new command instance.
*/
public function __construct(private LocationCreationService $creationService)
{
parent::__construct();
}
/**
* Handle the command execution process.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function handle()
{
$short = $this->option('short') ?? $this->ask(trans('command/messages.location.ask_short'));
$long = $this->option('long') ?? $this->ask(trans('command/messages.location.ask_long'));
$location = $this->creationService->handle(compact('short', 'long'));
$this->line(trans('command/messages.location.created', [
'name' => $location->short,
'id' => $location->id,
]));
}
}

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Console\Commands\Maintenance;
namespace Pterodactyl\Console\Commands\Maintenance;
use Carbon\Carbon;
use Illuminate\Console\Command;
@@ -30,7 +30,7 @@ class CleanServiceBackupFilesCommand extends Command
/**
* Handle command execution.
*/
public function handle(): void
public function handle()
{
$files = $this->disk->files('services/.bak');

View File

@@ -1,10 +1,10 @@
<?php
namespace App\Console\Commands\Maintenance;
namespace Pterodactyl\Console\Commands\Maintenance;
use App\Models\Backup;
use Carbon\CarbonImmutable;
use Illuminate\Console\Command;
use Pterodactyl\Repositories\Eloquent\BackupRepository;
class PruneOrphanedBackupsCommand extends Command
{
@@ -12,14 +12,22 @@ class PruneOrphanedBackupsCommand extends Command
protected $description = 'Marks all backups older than "n" minutes that have not yet completed as being failed.';
public function handle(): void
/**
* PruneOrphanedBackupsCommand constructor.
*/
public function __construct(private BackupRepository $backupRepository)
{
parent::__construct();
}
public function handle()
{
$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.');
}
$query = Backup::query()
$query = $this->backupRepository->getBuilder()
->whereNull('completed_at')
->where('created_at', '<=', CarbonImmutable::now()->subMinutes($since)->toDateTimeString());

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Console\Commands\Node;
namespace Pterodactyl\Console\Commands\Node;
use Illuminate\Console\Command;
use App\Services\Nodes\NodeCreationService;
use Pterodactyl\Services\Nodes\NodeCreationService;
class MakeNodeCommand extends Command
{
@@ -21,8 +21,8 @@ class MakeNodeCommand extends Command
{--maxDisk= : Set the max disk amount.}
{--overallocateDisk= : Enter the amount of disk to overallocate (% or -1 to overallocate the maximum).}
{--uploadSize= : Enter the maximum upload filesize.}
{--daemonListeningPort= : Enter the daemon listening port.}
{--daemonSFTPPort= : Enter the daemon SFTP listening port.}
{--daemonListeningPort= : Enter the wings listening port.}
{--daemonSFTPPort= : Enter the wings SFTP listening port.}
{--daemonBase= : Enter the base folder.}';
protected $description = 'Creates a new node on the system via the CLI.';
@@ -38,12 +38,13 @@ class MakeNodeCommand extends Command
/**
* Handle the command execution process.
*
* @throws \App\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function handle(): void
public function handle()
{
$data['name'] = $this->option('name') ?? $this->ask('Enter a short identifier used to distinguish this node from others');
$data['description'] = $this->option('description') ?? $this->ask('Enter a description to identify the node');
$data['location_id'] = $this->option('locationId') ?? $this->ask('Enter a valid location id');
$data['scheme'] = $this->option('scheme') ?? $this->anticipate(
'Please either enter https for SSL or http for a non-ssl connection',
['https', 'http'],
@@ -58,11 +59,11 @@ class MakeNodeCommand extends Command
$data['disk'] = $this->option('maxDisk') ?? $this->ask('Enter the maximum amount of disk space');
$data['disk_overallocate'] = $this->option('overallocateDisk') ?? $this->ask('Enter the amount of memory to over allocate by, -1 will disable checking and 0 will prevent creating new server');
$data['upload_size'] = $this->option('uploadSize') ?? $this->ask('Enter the maximum filesize upload', '100');
$data['daemonListen'] = $this->option('daemonListeningPort') ?? $this->ask('Enter the daemon listening port', '8080');
$data['daemonSFTP'] = $this->option('daemonSFTPPort') ?? $this->ask('Enter the daemon SFTP listening port', '2022');
$data['daemonBase'] = $this->option('daemonBase') ?? $this->ask('Enter the base folder', '/var/lib/panel/volumes');
$data['daemonListen'] = $this->option('daemonListeningPort') ?? $this->ask('Enter the wings listening port', '8080');
$data['daemonSFTP'] = $this->option('daemonSFTPPort') ?? $this->ask('Enter the wings SFTP listening port', '2022');
$data['daemonBase'] = $this->option('daemonBase') ?? $this->ask('Enter the base folder', '/var/lib/pterodactyl/volumes');
$node = $this->creationService->handle($data);
$this->line('Successfully created a new node with the name ' . $data['name'] . ' and has an id of ' . $node->id . '.');
$this->line('Successfully created a new node on the location ' . $data['location_id'] . ' with the name ' . $data['name'] . ' and has an id of ' . $node->id . '.');
}
}

View File

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

View File

@@ -1,8 +1,8 @@
<?php
namespace App\Console\Commands\Node;
namespace Pterodactyl\Console\Commands\Node;
use App\Models\Node;
use Pterodactyl\Models\Node;
use Illuminate\Console\Command;
class NodeListCommand extends Command
@@ -11,11 +11,12 @@ class NodeListCommand extends Command
public function handle(): int
{
$nodes = Node::query()->get()->map(function (Node $node) {
$nodes = Node::query()->with('location')->get()->map(function (Node $node) {
return [
'id' => $node->id,
'uuid' => $node->uuid,
'name' => $node->name,
'location' => $node->location->short,
'host' => $node->getConnectionAddress(),
];
});
@@ -23,7 +24,7 @@ class NodeListCommand extends Command
if ($this->option('format') === 'json') {
$this->output->write($nodes->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
} else {
$this->table(['ID', 'UUID', 'Name', 'Host'], $nodes->toArray());
$this->table(['ID', 'UUID', 'Name', 'Location', 'Host'], $nodes->toArray());
}
$this->output->newLine();

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Console\Commands\Overrides;
namespace Pterodactyl\Console\Commands\Overrides;
use Illuminate\Foundation\Console\KeyGenerateCommand as BaseKeyGenerateCommand;
@@ -10,7 +10,7 @@ class KeyGenerateCommand extends BaseKeyGenerateCommand
* Override the default Laravel key generation command to throw a warning to the user
* if it appears that they have already generated an application encryption key.
*/
public function handle(): void
public function handle()
{
if (!empty(config('app.key')) && $this->input->isInteractive()) {
$this->output->warning('It appears you have already configured an application encryption key. Continuing with this process with overwrite that key and cause data corruption for any existing encrypted data. DO NOT CONTINUE UNLESS YOU KNOW WHAT YOU ARE DOING.');

View File

@@ -1,8 +1,8 @@
<?php
namespace App\Console\Commands\Overrides;
namespace Pterodactyl\Console\Commands\Overrides;
use App\Console\RequiresDatabaseMigrations;
use Pterodactyl\Console\RequiresDatabaseMigrations;
use Illuminate\Database\Console\Seeds\SeedCommand as BaseSeedCommand;
class SeedCommand extends BaseSeedCommand

View File

@@ -1,8 +1,8 @@
<?php
namespace App\Console\Commands\Overrides;
namespace Pterodactyl\Console\Commands\Overrides;
use App\Console\RequiresDatabaseMigrations;
use Pterodactyl\Console\RequiresDatabaseMigrations;
use Illuminate\Foundation\Console\UpCommand as BaseUpCommand;
class UpCommand extends BaseUpCommand

View File

@@ -1,11 +1,13 @@
<?php
namespace App\Console\Commands\Schedule;
namespace Pterodactyl\Console\Commands\Schedule;
use Exception;
use Illuminate\Console\Command;
use App\Models\Schedule;
use Pterodactyl\Models\Schedule;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Builder;
use App\Services\Schedules\ProcessScheduleService;
use Pterodactyl\Services\Schedules\ProcessScheduleService;
class ProcessRunnableCommand extends Command
{
@@ -49,6 +51,8 @@ class ProcessRunnableCommand extends Command
* Processes a given schedule and logs and errors encountered the console output. This should
* never throw an exception out, otherwise you'll end up killing the entire run group causing
* any other schedules to not process correctly.
*
* @see https://github.com/pterodactyl/panel/issues/2609
*/
protected function processSchedule(Schedule $schedule)
{
@@ -64,7 +68,7 @@ class ProcessRunnableCommand extends Command
'hash' => $schedule->hashid,
]));
} catch (\Throwable|\Exception $exception) {
logger()->error($exception, ['schedule_id' => $schedule->id]);
Log::error($exception, ['schedule_id' => $schedule->id]);
$this->error("An error was encountered while processing Schedule #$schedule->id: " . $exception->getMessage());
}

View File

@@ -1,14 +1,14 @@
<?php
namespace App\Console\Commands\Server;
namespace Pterodactyl\Console\Commands\Server;
use App\Models\Server;
use Pterodactyl\Models\Server;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Validation\ValidationException;
use Illuminate\Validation\Factory as ValidatorFactory;
use App\Repositories\Daemon\DaemonPowerRepository;
use App\Exceptions\Http\Connection\DaemonConnectionException;
use Pterodactyl\Repositories\Wings\DaemonPowerRepository;
use Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException;
class BulkPowerActionCommand extends Command
{
@@ -32,7 +32,7 @@ class BulkPowerActionCommand extends Command
*
* @throws \Illuminate\Validation\ValidationException
*/
public function handle(): void
public function handle()
{
$action = $this->argument('action');
$nodes = empty($this->option('nodes')) ? [] : explode(',', $this->option('nodes'));
@@ -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)) {
} elseif (!empty($nodes) && empty($servers)) {
$instance->whereIn('node_id', $nodes);
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Pterodactyl\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\VarDumper\VarDumper;
use Pterodactyl\Services\Telemetry\TelemetryCollectionService;
class TelemetryCommand extends Command
{
protected $description = 'Displays all the data that would be sent to the Pterodactyl Telemetry Service if telemetry collection is enabled.';
protected $signature = 'p:telemetry';
/**
* TelemetryCommand constructor.
*/
public function __construct(private TelemetryCollectionService $telemetryCollectionService)
{
parent::__construct();
}
/**
* Handle execution of command.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function handle()
{
$this->output->info('Collecting telemetry data, this may take a while...');
VarDumper::dump($this->telemetryCollectionService->collect());
}
}

View File

@@ -1,28 +1,28 @@
<?php
namespace App\Console\Commands;
namespace Pterodactyl\Console\Commands;
use Illuminate\Console\Command;
use App\Console\Kernel;
use Pterodactyl\Console\Kernel;
use Symfony\Component\Process\Process;
use Symfony\Component\Console\Helper\ProgressBar;
class UpgradeCommand extends Command
{
protected const DEFAULT_URL = 'https://github.com/pelican-dev/panel/releases/%s/panel.tar.gz';
protected const DEFAULT_URL = 'https://github.com/pterodactyl/panel/releases/%s/panel.tar.gz';
protected $signature = 'p:upgrade
{--user= : The user that PHP runs under. All files will be owned by this user.}
{--group= : The group that PHP runs under. All files will be owned by this group.}
{--url= : The specific archive to download.}
{--release= : A specific version to download from GitHub. Leave blank to use latest.}
{--release= : A specific Pterodactyl version to download from GitHub. Leave blank to use latest.}
{--skip-download : If set no archive will be downloaded.}';
protected $description = 'Downloads a new archive from GitHub and then executes the normal upgrade commands.';
protected $description = 'Downloads a new archive for Pterodactyl from GitHub and then executes the normal upgrade commands.';
/**
* Executes an upgrade command which will run through all of our standard
* Panel commands and enable users to basically just download
* commands for Pterodactyl and enable users to basically just download
* the archive and execute this and be done.
*
* This places the application in maintenance mode as well while the commands
@@ -30,7 +30,7 @@ class UpgradeCommand extends Command
*
* @throws \Exception
*/
public function handle(): void
public function handle()
{
$skipDownload = $this->option('skip-download');
if (!$skipDownload) {
@@ -51,7 +51,7 @@ class UpgradeCommand extends Command
}
if (is_null($this->option('user'))) {
$userDetails = function_exists('posix_getpwuid') ? posix_getpwuid(fileowner('public')) : [];
$userDetails = posix_getpwuid(fileowner('public'));
$user = $userDetails['name'] ?? 'www-data';
if (!$this->confirm("Your webserver user has been detected as <fg=blue>[{$user}]:</> is this correct?", true)) {
@@ -67,7 +67,7 @@ class UpgradeCommand extends Command
}
if (is_null($this->option('group'))) {
$groupDetails = function_exists('posix_getgrgid') ? posix_getgrgid(filegroup('public')) : [];
$groupDetails = posix_getgrgid(filegroup('public'));
$group = $groupDetails['name'] ?? 'www-data';
if (!$this->confirm("Your webserver group has been detected as <fg=blue>[{$group}]:</> is this correct?", true)) {
@@ -133,7 +133,7 @@ class UpgradeCommand extends Command
/** @var \Illuminate\Foundation\Application $app */
$app = require __DIR__ . '/../../../bootstrap/app.php';
/** @var \App\Console\Kernel $kernel */
/** @var \Pterodactyl\Console\Kernel $kernel */
$kernel = $app->make(Kernel::class);
$kernel->bootstrap();
$this->setLaravel($app);
@@ -173,7 +173,7 @@ class UpgradeCommand extends Command
});
$this->newLine(2);
$this->info('Panel has been successfully upgraded. Please ensure you also update any Daemon instances');
$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)

View File

@@ -1,10 +1,11 @@
<?php
namespace App\Console\Commands\User;
namespace Pterodactyl\Console\Commands\User;
use App\Models\User;
use Pterodactyl\Models\User;
use Webmozart\Assert\Assert;
use Illuminate\Console\Command;
use Pterodactyl\Services\Users\UserDeletionService;
class DeleteUserCommand extends Command
{
@@ -12,6 +13,14 @@ class DeleteUserCommand extends Command
protected $signature = 'p:user:delete {--user=}';
/**
* DeleteUserCommand constructor.
*/
public function __construct(private UserDeletionService $deletionService)
{
parent::__construct();
}
public function handle(): int
{
$search = $this->option('user') ?? $this->ask(trans('command/messages.user.search_users'));
@@ -35,10 +44,10 @@ class DeleteUserCommand extends Command
if ($this->input->isInteractive()) {
$tableValues = [];
foreach ($results as $user) {
$tableValues[] = [$user->id, $user->email, $user->name];
$tableValues[] = [$user->id, $user->email, $user->username];
}
$this->table(['User ID', 'Email', 'Name'], $tableValues);
$this->table(['User ID', 'Email', 'Username'], $tableValues);
if (!$deleteUser = $this->ask(trans('command/messages.user.select_search_user'))) {
return $this->handle();
}
@@ -53,9 +62,7 @@ class DeleteUserCommand extends Command
}
if ($this->confirm(trans('command/messages.user.confirm_delete')) || !$this->input->isInteractive()) {
$user = User::query()->findOrFail($deleteUser);
$user->delete();
$this->deletionService->handle($deleteUser);
$this->info(trans('command/messages.user.deleted'));
}

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Console\Commands\User;
namespace Pterodactyl\Console\Commands\User;
use App\Models\User;
use Illuminate\Console\Command;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
class DisableTwoFactorCommand extends Command
{
@@ -11,24 +11,33 @@ class DisableTwoFactorCommand extends Command
protected $signature = 'p:user:disable2fa {--email= : The email of the user to disable 2-Factor for.}';
/**
* DisableTwoFactorCommand constructor.
*/
public function __construct(private UserRepositoryInterface $repository)
{
parent::__construct();
}
/**
* Handle command execution process.
*
* @throws \App\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function handle(): void
public function handle()
{
if ($this->input->isInteractive()) {
$this->output->warning(trans('command/messages.user.2fa_help_text'));
}
$email = $this->option('email') ?? $this->ask(trans('command/messages.user.ask_email'));
$user = $this->repository->setColumns(['id', 'email'])->findFirstWhere([['email', '=', $email]]);
$user = User::query()->where('email', $email)->firstOrFail();
$user->use_totp = false;
$user->totp_secret = null;
$user->save();
$this->repository->withoutFreshModel()->update($user->id, [
'use_totp' => false,
'totp_secret' => null,
]);
$this->info(trans('command/messages.user.2fa_disabled', ['email' => $user->email]));
}
}

View File

@@ -1,11 +1,9 @@
<?php
namespace App\Console\Commands\User;
namespace Pterodactyl\Console\Commands\User;
use Exception;
use Illuminate\Console\Command;
use App\Services\Users\UserCreationService;
use Illuminate\Support\Facades\DB;
use Pterodactyl\Services\Users\UserCreationService;
class MakeUserCommand extends Command
{
@@ -24,24 +22,14 @@ class MakeUserCommand extends Command
/**
* Handle command request to create a new user.
*
* @throws Exception
* @throws \App\Exceptions\Model\DataValidationException
* @throws \Exception
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function handle(): int
public function handle()
{
try {
DB::select('select 1 where 1');
} catch (Exception $exception) {
$this->error($exception->getMessage());
return 1;
}
$root_admin = $this->option('admin') ?? $this->confirm(trans('command/messages.user.ask_admin'));
$email = $this->option('email') ?? $this->ask(trans('command/messages.user.ask_email'));
$username = $this->option('username') ?? $this->ask(trans('command/messages.user.ask_username'));
$name_first = $this->option('name-first') ?? $this->ask(trans('command/messages.user.ask_name_first'));
$name_last = $this->option('name-last') ?? $this->ask(trans('command/messages.user.ask_name_last'));
if (is_null($password = $this->option('password')) && !$this->option('no-password')) {
$this->warn(trans('command/messages.user.ask_password_help'));
@@ -49,15 +37,12 @@ class MakeUserCommand extends Command
$password = $this->secret(trans('command/messages.user.ask_password'));
}
$user = $this->creationService->handle(compact('email', 'username', 'name_first', 'name_last', 'password', 'root_admin'));
$user = $this->creationService->handle(compact('email', 'username', 'password', 'root_admin'));
$this->table(['Field', 'Value'], [
['UUID', $user->uuid],
['Email', $user->email],
['Username', $user->username],
['Name', $user->name],
['Admin', $user->root_admin ? 'Yes' : 'No'],
]);
return 0;
}
}

View File

@@ -1,14 +1,17 @@
<?php
namespace App\Console;
namespace Pterodactyl\Console;
use App\Models\ActivityLog;
use Ramsey\Uuid\Uuid;
use Pterodactyl\Models\ActivityLog;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Database\Console\PruneCommand;
use Pterodactyl\Repositories\Eloquent\SettingsRepository;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use App\Console\Commands\Schedule\ProcessRunnableCommand;
use App\Console\Commands\Maintenance\PruneOrphanedBackupsCommand;
use App\Console\Commands\Maintenance\CleanServiceBackupFilesCommand;
use Pterodactyl\Services\Telemetry\TelemetryCollectionService;
use Pterodactyl\Console\Commands\Schedule\ProcessRunnableCommand;
use Pterodactyl\Console\Commands\Maintenance\PruneOrphanedBackupsCommand;
use Pterodactyl\Console\Commands\Maintenance\CleanServiceBackupFilesCommand;
class Kernel extends ConsoleKernel
{
@@ -40,5 +43,34 @@ class Kernel extends ConsoleKernel
if (config('activity.prune_days')) {
$schedule->command(PruneCommand::class, ['--model' => [ActivityLog::class]])->daily();
}
if (config('pterodactyl.telemetry.enabled')) {
$this->registerTelemetry($schedule);
}
}
/**
* I wonder what this does.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
private function registerTelemetry(Schedule $schedule): void
{
$settingsRepository = app()->make(SettingsRepository::class);
$uuid = $settingsRepository->get('app:telemetry:uuid');
if (is_null($uuid)) {
$uuid = Uuid::uuid4()->toString();
$settingsRepository->set('app:telemetry:uuid', $uuid);
}
// Calculate a fixed time to run the data push at, this will be the same time every day.
$time = hexdec(str_replace('-', '', substr($uuid, 27))) % 1440;
$hour = floor($time / 60);
$minute = $time % 60;
// Run the telemetry collector.
$schedule->call(app()->make(TelemetryCollectionService::class))->description('Collect Telemetry')->dailyAt("$hour:$minute");
}
}

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Console;
namespace Pterodactyl\Console;
/**
* @mixin \Illuminate\Console\Command
@@ -46,7 +46,7 @@ You must run the following command to finish migrating your database:
<fg=green;options=bold>php artisan migrate --step --force</>
You will not be able to use the Panel as expected without fixing your
You will not be able to use Pterodactyl Panel as expected without fixing your
database state by running the command above.
');

View File

@@ -0,0 +1,13 @@
<?php
namespace Pterodactyl\Contracts\Core;
use Pterodactyl\Events\Event;
interface ReceivesEvents
{
/**
* Handles receiving an event from the application.
*/
public function handle(Event $notification): void;
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Pterodactyl\Contracts\Criteria;
use Illuminate\Database\Eloquent\Model;
use Pterodactyl\Repositories\Repository;
interface CriteriaInterface
{
/**
* Apply selected criteria to a repository call.
*/
public function apply(Model $model, Repository $repository): mixed;
}

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Contracts\Extensions;
namespace Pterodactyl\Contracts\Extensions;
use Hashids\HashidsInterface as VendorHashidsInterface;

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Contracts\Http;
namespace Pterodactyl\Contracts\Http;
interface ClientPermissionsRequest
{

View File

@@ -0,0 +1,19 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Allocation;
interface AllocationRepositoryInterface extends RepositoryInterface
{
/**
* Return all the allocations that exist for a node that are not currently
* allocated.
*/
public function getUnassignedAllocationIds(int $node): array;
/**
* Return a single allocation from those meeting the requirements.
*/
public function getRandomAllocation(array $nodes, array $ports, bool $dedicated = false): ?Allocation;
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\User;
use Illuminate\Support\Collection;
interface ApiKeyRepositoryInterface extends RepositoryInterface
{
/**
* Get all the account API keys that exist for a specific user.
*/
public function getAccountKeys(User $user): Collection;
/**
* Get all the application API keys that exist for a specific user.
*/
public function getApplicationKeys(User $user): Collection;
/**
* Delete an account API key from the panel for a specific user.
*/
public function deleteAccountKey(User $user, string $identifier): int;
/**
* Delete an application API key from the panel for a specific user.
*/
public function deleteApplicationKey(User $user, string $identifier): int;
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Pterodactyl\Contracts\Repository;
interface ApiPermissionRepositoryInterface extends RepositoryInterface
{
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Illuminate\Support\Collection;
interface DatabaseHostRepositoryInterface extends RepositoryInterface
{
/**
* Return database hosts with a count of databases and the node
* information for which it is attached.
*/
public function getWithViewDetails(): Collection;
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Illuminate\Support\Collection;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
interface DatabaseRepositoryInterface extends RepositoryInterface
{
public const DEFAULT_CONNECTION_NAME = 'dynamic';
/**
* Set the connection name to execute statements against.
*/
public function setConnection(string $connection): self;
/**
* Return the connection to execute statements against.
*/
public function getConnection(): string;
/**
* Return all the databases belonging to a server.
*/
public function getDatabasesForServer(int $server): Collection;
/**
* Return all the databases for a given host with the server relationship loaded.
*/
public function getDatabasesForHost(int $host, int $count = 25): LengthAwarePaginator;
/**
* Create a new database on a given connection.
*/
public function createDatabase(string $database): bool;
/**
* Create a new database user on a given connection.
*/
public function createUser(string $username, string $remote, string $password, ?int $max_connections): bool;
/**
* Give a specific user access to a given database.
*/
public function assignUserToDatabase(string $database, string $username, string $remote): bool;
/**
* Flush the privileges for a given connection.
*/
public function flush(): bool;
/**
* Drop a given database on a specific connection.
*/
public function dropDatabase(string $database): bool;
/**
* Drop a given user on a specific connection.
*/
public function dropUser(string $username, string $remote): bool;
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Egg;
use Illuminate\Database\Eloquent\Collection;
interface EggRepositoryInterface extends RepositoryInterface
{
/**
* Return an egg with the variables relation attached.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithVariables(int $id): Egg;
/**
* Return all eggs and their relations to be used in the daemon API.
*/
public function getAllWithCopyAttributes(): Collection;
/**
* Return an egg with the scriptFrom and configFrom relations loaded onto the model.
*/
public function getWithCopyAttributes(int|string $value, string $column = 'id'): Egg;
/**
* Return all the data needed to export a service.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithExportAttributes(int $id): Egg;
/**
* Confirm a copy script belongs to the same nest as the item trying to use it.
*/
public function isCopyableScript(int $copyFromId, int $service): bool;
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Illuminate\Support\Collection;
interface EggVariableRepositoryInterface extends RepositoryInterface
{
/**
* Return editable variables for a given egg. Editable variables must be set to
* user viewable in order to be picked up by this function.
*/
public function getEditableVariables(int $egg): Collection;
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Location;
use Illuminate\Support\Collection;
interface LocationRepositoryInterface extends RepositoryInterface
{
/**
* Return locations with a count of nodes and servers attached to it.
*/
public function getAllWithDetails(): Collection;
/**
* Return all the available locations with the nodes as a relationship.
*/
public function getAllWithNodes(): Collection;
/**
* Return all the nodes and their respective count of servers for a location.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithNodes(int $id): Location;
/**
* Return a location and the count of nodes in that location.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithNodeCount(int $id): Location;
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Nest;
use Illuminate\Database\Eloquent\Collection;
interface NestRepositoryInterface extends RepositoryInterface
{
/**
* Return a nest or all nests with their associated eggs and variables.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
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;
/**
* Return a nest along with its associated eggs and the servers relation on those eggs.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithEggServers(int $id): Nest;
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Node;
use Illuminate\Support\Collection;
interface NodeRepositoryInterface extends RepositoryInterface
{
public const THRESHOLD_PERCENTAGE_LOW = 75;
public const THRESHOLD_PERCENTAGE_MEDIUM = 90;
/**
* Return the usage stats for a single node.
*/
public function getUsageStats(Node $node): array;
/**
* Return the usage stats for a single node.
*/
public function getUsageStatsRaw(Node $node): array;
/**
* Return a single node with location and server information.
*/
public function loadLocationAndServerCount(Node $node, bool $refresh = false): Node;
/**
* Attach a paginated set of allocations to a node mode including
* any servers that are also attached to those allocations.
*/
public function loadNodeAllocations(Node $node, bool $refresh = false): Node;
/**
* Return a collection of nodes for all locations to use in server creation UI.
*/
public function getNodesForServerCreation(): Collection;
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Pterodactyl\Contracts\Repository;
interface PermissionRepositoryInterface extends RepositoryInterface
{
}

View File

@@ -0,0 +1,141 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
interface RepositoryInterface
{
/**
* Return an identifier or Model object to be used by the repository.
*/
public function model(): string;
/**
* Return the model being used for this repository instance.
*/
public function getModel(): Model;
/**
* Returns an instance of a query builder.
*/
public function getBuilder(): Builder;
/**
* Returns the columns to be selected or returned by the query.
*/
public function getColumns(): array;
/**
* An array of columns to filter the response by.
*/
public function setColumns(array|string $columns = ['*']): self;
/**
* Stop repository update functions from returning a fresh
* model when changes are committed.
*/
public function withoutFreshModel(): self;
/**
* Return a fresh model with a repository updates a model.
*/
public function withFreshModel(): self;
/**
* Set whether the repository should return a fresh model
* when changes are committed.
*/
public function setFreshModel(bool $fresh = true): self;
/**
* Create a new model instance and persist it to the database.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function create(array $fields, bool $validate = true, bool $force = false): mixed;
/**
* Find a model that has the specific ID passed.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function find(int $id): mixed;
/**
* Find a model matching an array of where clauses.
*/
public function findWhere(array $fields): Collection;
/**
* Find and return the first matching instance for the given fields.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function findFirstWhere(array $fields): mixed;
/**
* Return a count of records matching the passed arguments.
*/
public function findCountWhere(array $fields): int;
/**
* Delete a given record from the database.
*/
public function delete(int $id): int;
/**
* Delete records matching the given attributes.
*/
public function deleteWhere(array $attributes): int;
/**
* Update a given ID with the passed array of fields.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function update(int $id, array $fields, bool $validate = true, bool $force = false): mixed;
/**
* Perform a mass update where matching records are updated using whereIn.
* This does not perform any model data validation.
*/
public function updateWhereIn(string $column, array $values, array $fields): int;
/**
* Update a record if it exists in the database, otherwise create it.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function updateOrCreate(array $where, array $fields, bool $validate = true, bool $force = false): mixed;
/**
* Return all records associated with the given model.
*/
public function all(): Collection;
/**
* Return a paginated result set using a search term if set on the repository.
*/
public function paginated(int $perPage): LengthAwarePaginator;
/**
* Insert a single or multiple records into the database at once skipping
* validation and mass assignment checking.
*/
public function insert(array $data): bool;
/**
* Insert multiple records into the database and ignore duplicates.
*/
public function insertIgnore(array $values): bool;
/**
* Get the amount of entries in the database.
*/
public function count(): int;
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Schedule;
use Illuminate\Support\Collection;
interface ScheduleRepositoryInterface extends RepositoryInterface
{
/**
* Return all the schedules for a given server.
*/
public function findServerSchedules(int $server): Collection;
/**
* Return a schedule model with all the associated tasks as a relationship.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getScheduleWithTasks(int $schedule): Schedule;
}

View File

@@ -0,0 +1,73 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Server;
use Illuminate\Support\Collection;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
interface ServerRepositoryInterface extends RepositoryInterface
{
/**
* Load the egg relations onto the server model.
*/
public function loadEggRelations(Server $server, bool $refresh = false): Server;
/**
* Return a collection of servers with their associated data for rebuild operations.
*/
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;
/**
* Return a server model and all variables associated with the server.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function findWithVariables(int $id): Server;
/**
* Get the primary allocation for a given server. If a model is passed into
* the function, load the allocation relationship onto it. Otherwise, find and
* return the server from the database.
*/
public function getPrimaryAllocation(Server $server, bool $refresh = false): Server;
/**
* Return enough data to be used for the creation of a server via the daemon.
*/
public function getDataForCreation(Server $server, bool $refresh = false): Server;
/**
* Load associated databases onto the server model.
*/
public function loadDatabaseRelations(Server $server, bool $refresh = false): Server;
/**
* Get data for use when updating a server on the Daemon. Returns an array of
* the egg which is used for build and rebuild. Only loads relations
* if they are missing, or refresh is set to true.
*/
public function getDaemonServiceData(Server $server, bool $refresh = false): array;
/**
* Return a server by UUID.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getByUuid(string $uuid): Server;
/**
* Check if a given UUID and UUID-Short string are unique to a server.
*/
public function isUniqueUuidCombo(string $uuid, string $short): bool;
/**
* Returns all the servers that exist for a given node in a paginated response.
*/
public function loadAllServersForNode(int $node, int $limit): LengthAwarePaginator;
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Pterodactyl\Contracts\Repository;
interface ServerVariableRepositoryInterface extends RepositoryInterface
{
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Illuminate\Support\Collection;
interface SessionRepositoryInterface extends RepositoryInterface
{
/**
* Return all the active sessions for a user.
*/
public function getUserSessions(int $user): Collection;
/**
* Delete a session for a given user.
*/
public function deleteUserSession(int $user, string $session): ?int;
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Pterodactyl\Contracts\Repository;
interface SettingsRepositoryInterface extends RepositoryInterface
{
/**
* Store a new persistent setting in the database.
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function set(string $key, string $value = null);
/**
* Retrieve a persistent setting from the database.
*/
public function get(string $key, mixed $default): mixed;
/**
* Remove a key from the database cache.
*/
public function forget(string $key);
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Subuser;
interface SubuserRepositoryInterface extends RepositoryInterface
{
/**
* Return a subuser with the associated server relationship.
*/
public function loadServerAndUserRelations(Subuser $subuser, bool $refresh = false): Subuser;
/**
* Return a subuser with the associated permissions relationship.
*/
public function getWithPermissions(Subuser $subuser, bool $refresh = false): Subuser;
/**
* Return a subuser and associated permissions given a user_id and server_id.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithPermissionsUsingUserAndServer(int $user, int $server): Subuser;
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Pterodactyl\Contracts\Repository;
use Pterodactyl\Models\Task;
interface TaskRepositoryInterface extends RepositoryInterface
{
/**
* Get a task and the server relationship for that task.
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getTaskForJobProcess(int $id): Task;
/**
* Returns the next task in a schedule.
*/
public function getNextTask(int $schedule, int $index): ?Task;
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Pterodactyl\Contracts\Repository;
interface UserRepositoryInterface extends RepositoryInterface
{
}

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events;
namespace Pterodactyl\Events;
use Illuminate\Support\Str;
use App\Models\ActivityLog;
use Pterodactyl\Models\ActivityLog;
use Illuminate\Database\Eloquent\Model;
class ActivityLogged extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Auth;
namespace Pterodactyl\Events\Auth;
use App\Models\User;
use App\Events\Event;
use Pterodactyl\Models\User;
use Pterodactyl\Events\Event;
class DirectLogin extends Event
{

View File

@@ -1,8 +1,8 @@
<?php
namespace App\Events\Auth;
namespace Pterodactyl\Events\Auth;
use App\Events\Event;
use Pterodactyl\Events\Event;
use Illuminate\Queue\SerializesModels;
class FailedCaptcha extends Event

View File

@@ -1,8 +1,8 @@
<?php
namespace App\Events\Auth;
namespace Pterodactyl\Events\Auth;
use App\Events\Event;
use Pterodactyl\Events\Event;
use Illuminate\Queue\SerializesModels;
class FailedPasswordReset extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Auth;
namespace Pterodactyl\Events\Auth;
use App\Models\User;
use App\Events\Event;
use Pterodactyl\Models\User;
use Pterodactyl\Events\Event;
class ProvidedAuthenticationToken extends Event
{

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Events;
namespace Pterodactyl\Events;
abstract class Event
{

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Server;
namespace Pterodactyl\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Server;
use Illuminate\Queue\SerializesModels;
class Created extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Server;
namespace Pterodactyl\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Server;
use Illuminate\Queue\SerializesModels;
class Creating extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Server;
namespace Pterodactyl\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Server;
use Illuminate\Queue\SerializesModels;
class Deleted extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Server;
namespace Pterodactyl\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Server;
use Illuminate\Queue\SerializesModels;
class Deleting extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Server;
namespace Pterodactyl\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Server;
use Illuminate\Queue\SerializesModels;
class Installed extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Server;
namespace Pterodactyl\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Server;
use Illuminate\Queue\SerializesModels;
class Saved extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Server;
namespace Pterodactyl\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Server;
use Illuminate\Queue\SerializesModels;
class Saving extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Server;
namespace Pterodactyl\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Server;
use Illuminate\Queue\SerializesModels;
class Updated extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Server;
namespace Pterodactyl\Events\Server;
use App\Events\Event;
use App\Models\Server;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Server;
use Illuminate\Queue\SerializesModels;
class Updating extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Subuser;
namespace Pterodactyl\Events\Subuser;
use App\Events\Event;
use App\Models\Subuser;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Subuser;
use Illuminate\Queue\SerializesModels;
class Created extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Subuser;
namespace Pterodactyl\Events\Subuser;
use App\Events\Event;
use App\Models\Subuser;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Subuser;
use Illuminate\Queue\SerializesModels;
class Creating extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Subuser;
namespace Pterodactyl\Events\Subuser;
use App\Events\Event;
use App\Models\Subuser;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Subuser;
use Illuminate\Queue\SerializesModels;
class Deleted extends Event

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Events\Subuser;
namespace Pterodactyl\Events\Subuser;
use App\Events\Event;
use App\Models\Subuser;
use Pterodactyl\Events\Event;
use Pterodactyl\Models\Subuser;
use Illuminate\Queue\SerializesModels;
class Deleting extends Event

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