mirror of
https://github.com/pterodactyl/panel.git
synced 2026-02-05 12:22:23 -06:00
Compare commits
No commits in common. "1.0-develop" and "v1.11.3" have entirely different histories.
1.0-develo
...
v1.11.3
@ -47,6 +47,5 @@ module.exports = {
|
||||
'@typescript-eslint/no-use-before-define': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
||||
'@typescript-eslint/ban-ts-comment': ['error', { 'ts-expect-error': 'allow-with-description' }],
|
||||
'react/no-unknown-property': ['error', { ignore: ['css'] }],
|
||||
},
|
||||
};
|
||||
|
||||
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1 +1 @@
|
||||
github: [pterodactyl]
|
||||
github: [matthewpi]
|
||||
|
||||
82
.github/ISSUE_TEMPLATE/1-bug-report.yml
vendored
82
.github/ISSUE_TEMPLATE/1-bug-report.yml
vendored
@ -1,82 +0,0 @@
|
||||
name: Bug Reports
|
||||
description: For reporting known and reproducible issues with the software.
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Bug reports should only be used for reporting issues with how the software works. For assistance installing this software, as well as debugging issues with dependencies, please use our [Discord server](https://discord.gg/pterodactyl).
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: Please provide a clear & concise description of the issue.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: Please describe what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: Please be as detailed as possible when providing steps to reproduce, failure to provide steps will result in this issue being closed.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: panel-version
|
||||
attributes:
|
||||
label: Panel Version
|
||||
description: Version number of your Panel (latest is not a version)
|
||||
placeholder: 1.4.0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: wings-version
|
||||
attributes:
|
||||
label: Wings Version
|
||||
description: Version number of your Wings (latest is not a version)
|
||||
placeholder: 1.4.2
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: egg-details
|
||||
attributes:
|
||||
label: Games and/or Eggs Affected
|
||||
description: Please include the specific game(s) or egg(s) you are running into this bug with.
|
||||
placeholder: Minecraft (Paper), Minecraft (Forge)
|
||||
|
||||
- type: input
|
||||
id: docker-image
|
||||
attributes:
|
||||
label: Docker Image
|
||||
description: The specific Docker image you are using for the game(s) above.
|
||||
placeholder: ghcr.io/pterodactyl/yolks:java_17
|
||||
|
||||
- type: textarea
|
||||
id: panel-logs
|
||||
attributes:
|
||||
label: Error Logs
|
||||
description: |
|
||||
Run the following command to collect logs on your system.
|
||||
|
||||
Wings: `sudo wings diagnostics`
|
||||
Panel: `tail -n 150 /var/www/pterodactyl/storage/logs/laravel-$(date +%F).log | nc pteropaste.com 99`
|
||||
placeholder: "https://pteropaste.com/a1h6z"
|
||||
render: bash
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please [search here](https://github.com/pterodactyl/panel/issues) to see if an issue already exists for your problem.
|
||||
options:
|
||||
- label: I have searched the existing issues before opening this issue. I understand that maintainers may close this issue without communication if I have not provided sufficient information.
|
||||
required: true
|
||||
18
.github/ISSUE_TEMPLATE/2-approved.yml
vendored
18
.github/ISSUE_TEMPLATE/2-approved.yml
vendored
@ -1,18 +0,0 @@
|
||||
name: Pre-Discussed and Approved Topics
|
||||
description: For topics already previously discussed and approved in the GitHub Discussions section.
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**DO NOT** open a new issue for feature requests _without prior maintainer approval_ and corresponding
|
||||
thread in the discussions section. You MUST link to the corresponding discussion thread when opening
|
||||
this feature request issue or it will be closed without further consideration.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: The Feature Request
|
||||
- type: input
|
||||
attributes:
|
||||
label: GitHub Discussion Link
|
||||
description: Link to the GitHub Discussions thread where the feature was previously discussed and approved.
|
||||
validations:
|
||||
required: true
|
||||
87
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
87
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
name: Bug Report
|
||||
description: Something isn't working quite right in the software.
|
||||
labels: [not confirmed]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Bug reports should only be used for reporting issues with how the software works. For assistance installing this software, as well as debugging issues with dependencies, please use our [Discord server](https://discord.gg/pterodactyl).
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: Please provide a clear & concise description of the issue.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: Please describe what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: Please be as detailed as possible when providing steps to reproduce, failure to provide steps will result in this issue being closed.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: panel-version
|
||||
attributes:
|
||||
label: Panel Version
|
||||
description: Version number of your Panel (latest is not a version)
|
||||
placeholder: 1.4.0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: wings-version
|
||||
attributes:
|
||||
label: Wings Version
|
||||
description: Version number of your Wings (latest is not a version)
|
||||
placeholder: 1.4.2
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: egg-details
|
||||
attributes:
|
||||
label: Games and/or Eggs Affected
|
||||
description: Please include the specific game(s) or egg(s) you are running into this bug with.
|
||||
placeholder: Minecraft (Paper), Minecraft (Forge)
|
||||
|
||||
- type: input
|
||||
id: docker-image
|
||||
attributes:
|
||||
label: Docker Image
|
||||
description: The specific Docker image you are using for the game(s) above.
|
||||
placeholder: ghcr.io/pterodactyl/yolks:java_17
|
||||
|
||||
- type: textarea
|
||||
id: panel-logs
|
||||
attributes:
|
||||
label: Error Logs
|
||||
description: |
|
||||
Run the following command to collect logs on your system.
|
||||
|
||||
Wings: `sudo wings diagnostics`
|
||||
Panel: `tail -n 100 /var/www/pterodactyl/storage/logs/laravel-$(date +%F).log | nc bin.ptdl.co 99`
|
||||
placeholder: "https://bin.ptdl.co/a1h6z"
|
||||
render: bash
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please [search here](https://github.com/pterodactyl/panel/issues) to see if an issue already exists for your problem.
|
||||
options:
|
||||
- label: I have searched the existing issues before opening this issue.
|
||||
required: true
|
||||
- label: I have provided all relevant details, including the specific game and Docker images I am using if this issue is related to running a server.
|
||||
required: true
|
||||
- label: I have checked in the Discord server and believe this is a bug with the software, and not a configuration issue with my specific system.
|
||||
required: true
|
||||
12
.github/ISSUE_TEMPLATE/config.yml
vendored
12
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,8 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Features, Help, or Questions
|
||||
url: https://github.com/orgs/pterodactyl/discussions/categories/feature-requests
|
||||
about: The preferred method for getting help with Pterodactyl or seeking new features for the software.
|
||||
- name: Discord
|
||||
- name: Installation Help
|
||||
url: https://discord.gg/pterodactyl
|
||||
about: For quicker support with installations issues or running ideas by the community.
|
||||
about: Please visit our Discord for help with your installation.
|
||||
- name: General Question
|
||||
url: https://discord.gg/pterodactyl
|
||||
about: Please visit our Discord for general questions about Pterodactyl.
|
||||
|
||||
32
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
32
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal 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
|
||||
2
.github/docker/entrypoint.sh
vendored
2
.github/docker/entrypoint.sh
vendored
@ -3,7 +3,7 @@ cd /app
|
||||
|
||||
mkdir -p /var/log/panel/logs/ /var/log/supervisord/ /var/log/nginx/ /var/log/php7/ \
|
||||
&& chmod 777 /var/log/panel/logs/ \
|
||||
&& ln -s /app/storage/logs/ /var/log/panel/
|
||||
&& ln -s /var/log/panel/logs/ /app/storage/logs/
|
||||
|
||||
## check for .env file and generate app keys if missing
|
||||
if [ -f /app/var/.env ]; then
|
||||
|
||||
23
.github/workflows/build.yaml
vendored
23
.github/workflows/build.yaml
vendored
@ -1,32 +1,35 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "1.0-develop"
|
||||
pull_request:
|
||||
branches:
|
||||
- "develop"
|
||||
- "1.0-develop"
|
||||
|
||||
jobs:
|
||||
ui:
|
||||
name: UI
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [ 22 ]
|
||||
node-version: [16]
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: yarn
|
||||
cache: "yarn"
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
- run: yarn tsc
|
||||
- run: yarn lint
|
||||
- run: yarn build:production
|
||||
|
||||
- name: Build
|
||||
run: yarn build:production
|
||||
|
||||
53
.github/workflows/ci.yaml
vendored
53
.github/workflows/ci.yaml
vendored
@ -1,27 +1,24 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "1.0-develop"
|
||||
pull_request:
|
||||
branches:
|
||||
- "develop"
|
||||
- "1.0-develop"
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: Tests
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php:
|
||||
- 8.2
|
||||
- 8.3
|
||||
database:
|
||||
- mariadb:10
|
||||
- mariadb:11
|
||||
- mysql:8
|
||||
- mysql:9
|
||||
php: [8.0, 8.1]
|
||||
database: ["mariadb:10.2", "mysql:8"]
|
||||
services:
|
||||
database:
|
||||
image: ${{ matrix.database }}
|
||||
@ -30,30 +27,46 @@ jobs:
|
||||
MYSQL_DATABASE: testing
|
||||
ports:
|
||||
- 3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- id: composer-cache
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Get cache directory
|
||||
id: composer-cache
|
||||
run: |
|
||||
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
- uses: actions/cache@v4
|
||||
|
||||
- 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 }}-
|
||||
- uses: shivammathur/setup-php@v2
|
||||
|
||||
- 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
|
||||
- run: cp .env.ci .env
|
||||
- run: composer install --no-interaction --no-progress --no-suggest --prefer-dist
|
||||
- run: vendor/bin/php-cs-fixer fix --dry-run --diff
|
||||
- run: vendor/bin/phpunit --bootstrap vendor/autoload.php tests/Unit
|
||||
|
||||
- name: Setup .env
|
||||
run: cp .env.ci .env
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-interaction --no-progress --no-suggest --prefer-dist
|
||||
|
||||
- name: Unit tests
|
||||
run: vendor/bin/phpunit --bootstrap vendor/autoload.php tests/Unit
|
||||
if: ${{ always() }}
|
||||
env:
|
||||
DB_HOST: UNIT_NO_DB
|
||||
- run: vendor/bin/phpunit tests/Integration
|
||||
|
||||
- name: Integration tests
|
||||
run: vendor/bin/phpunit tests/Integration
|
||||
env:
|
||||
DB_PORT: ${{ job.services.database.ports[3306] }}
|
||||
DB_USERNAME: root
|
||||
|
||||
27
.github/workflows/docker.yaml
vendored
27
.github/workflows/docker.yaml
vendored
@ -3,6 +3,11 @@ name: Docker
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- 1.0-develop
|
||||
pull_request:
|
||||
branches:
|
||||
- develop
|
||||
- 1.0-develop
|
||||
release:
|
||||
types:
|
||||
@ -11,18 +16,15 @@ on:
|
||||
jobs:
|
||||
push:
|
||||
name: Push
|
||||
runs-on: ubuntu-24.04
|
||||
if: "!contains(github.event.head_commit.message, 'skip docker') && !contains(github.event.head_commit.message, 'docker skip')"
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
runs-on: ubuntu-20.04
|
||||
if: "!contains(github.ref, 'develop') || (!contains(github.event.head_commit.message, 'skip docker') && !contains(github.event.head_commit.message, 'docker skip'))"
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Docker metadata
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ghcr.io/pterodactyl/panel
|
||||
flavor: |
|
||||
@ -33,18 +35,17 @@ jobs:
|
||||
type=ref,event=branch
|
||||
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Setup Docker buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
if: "github.event_name != 'pull_request'"
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Update version
|
||||
if: "github.event_name == 'release' && github.event.action == 'published'"
|
||||
@ -54,7 +55,7 @@ jobs:
|
||||
sed -i "s/ 'version' => 'canary',/ 'version' => '${REF:1}',/" config/app.php
|
||||
|
||||
- name: Build and Push
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
|
||||
36
.github/workflows/lint.yaml
vendored
Normal file
36
.github/workflows/lint.yaml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "1.0-develop"
|
||||
pull_request:
|
||||
branches:
|
||||
- "develop"
|
||||
- "1.0-develop"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.1"
|
||||
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
|
||||
tools: composer:v2
|
||||
coverage: none
|
||||
|
||||
- name: Setup .env
|
||||
run: cp .env.ci .env
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-interaction --no-progress --no-suggest --prefer-dist
|
||||
|
||||
- name: PHP CS Fixer
|
||||
run: vendor/bin/php-cs-fixer fix --dry-run --diff
|
||||
94
.github/workflows/release.yaml
vendored
94
.github/workflows/release.yaml
vendored
@ -1,49 +1,89 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 22
|
||||
cache: yarn
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn tsc
|
||||
- run: yarn build:production
|
||||
- name: create release branch and bump version
|
||||
node-version: 16
|
||||
cache: "yarn"
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: yarn build:production
|
||||
|
||||
- name: Create release branch and bump version
|
||||
env:
|
||||
VERSION: ${{ github.ref_name }}
|
||||
REF: ${{ github.ref }}
|
||||
run: |
|
||||
BRANCH=release/${{ env.VERSION }}
|
||||
git config --local user.email 'ci@pterodactyl.io'
|
||||
git config --local user.name 'Pterodactyl CI'
|
||||
git checkout -b "$BRANCH"
|
||||
git push -u origin "$BRANCH"
|
||||
sed -i "s/'canary'/'${VERSION:1}'/" config/app.php
|
||||
BRANCH=release/${REF:10}
|
||||
git config --local user.email "ci@pterodactyl.io"
|
||||
git config --local user.name "Pterodactyl CI"
|
||||
git checkout -b $BRANCH
|
||||
git push -u origin $BRANCH
|
||||
sed -i "s/ 'version' => 'canary',/ 'version' => '${REF:11}',/" config/app.php
|
||||
git add config/app.php
|
||||
git commit -m 'ci(release): bump version'
|
||||
git commit -m "ci(release): bump version"
|
||||
git push
|
||||
- name: create release archive
|
||||
|
||||
- name: Create release archive
|
||||
run: |
|
||||
rm -rf node_modules tests 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 phpunit.xml shell.nix
|
||||
tar -czf panel.tar.gz * .editorconfig .env.example .eslintignore .eslintrc.js .gitignore .prettierrc.json
|
||||
- name: write changelog
|
||||
|
||||
- name: Extract changelog
|
||||
env:
|
||||
REF: ${{ github.ref }}
|
||||
run: |
|
||||
sed -n "/^## ${{ github.ref_name }}/,/^## /{/^## /b;p}" CHANGELOG.md > ./RELEASE_CHANGELOG
|
||||
- uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
|
||||
sed -n "/^## ${REF:10}/,/^## /{/^## /b;p}" CHANGELOG.md > ./RELEASE_CHANGELOG
|
||||
|
||||
- name: Create checksum and add to changelog
|
||||
run: |
|
||||
SUM=`sha256sum panel.tar.gz`
|
||||
echo -e "\n#### SHA256 Checksum\n\n\`\`\`\n$SUM\n\`\`\`\n" >> ./RELEASE_CHANGELOG
|
||||
echo $SUM > checksum.txt
|
||||
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
draft: true
|
||||
prerelease: ${{ contains(github.ref_name, 'rc') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'alpha') }}
|
||||
prerelease: ${{ contains(github.ref, 'rc') || contains(github.ref, 'beta') || contains(github.ref, 'alpha') }}
|
||||
body_path: ./RELEASE_CHANGELOG
|
||||
files: |
|
||||
panel.tar.gz
|
||||
|
||||
- name: Upload release archive
|
||||
id: upload-release-archive
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: panel.tar.gz
|
||||
asset_name: panel.tar.gz
|
||||
asset_content_type: application/gzip
|
||||
|
||||
- name: Upload release checksum
|
||||
id: upload-release-checksum
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./checksum.txt
|
||||
asset_name: checksum.txt
|
||||
asset_content_type: text/plain
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@ -21,9 +21,7 @@ public/assets/manifest.json
|
||||
# For local development with docker
|
||||
# Remove if we ever put the Dockerfile in the repo
|
||||
.dockerignore
|
||||
docker-compose.*
|
||||
!docker-compose.example.yml
|
||||
!docker-compose.example.yaml
|
||||
docker-compose.yml
|
||||
|
||||
# for image related files
|
||||
misc
|
||||
@ -35,3 +33,4 @@ resources/lang/locales.js
|
||||
/public/build
|
||||
/public/hot
|
||||
result
|
||||
docker-compose.yaml
|
||||
|
||||
@ -2,25 +2,20 @@
|
||||
|
||||
use PhpCsFixer\Config;
|
||||
use PhpCsFixer\Finder;
|
||||
use PhpCsFixer\Runner\Parallel\ParallelConfigFactory;
|
||||
|
||||
$finder = (new Finder())
|
||||
->name('*.php')
|
||||
->ignoreVCSIgnored(true)
|
||||
->exclude([__DIR__ . '/bootstrap/cache'])
|
||||
->in([
|
||||
__DIR__ . '/app',
|
||||
__DIR__ . '/bootstrap',
|
||||
__DIR__ . '/config',
|
||||
__DIR__ . '/database',
|
||||
__DIR__ . '/routes',
|
||||
__DIR__ . '/tests',
|
||||
]);
|
||||
->in(__DIR__)
|
||||
->exclude([
|
||||
'vendor',
|
||||
'node_modules',
|
||||
'storage',
|
||||
'bootstrap/cache',
|
||||
])
|
||||
->notName(['_ide_helper*']);
|
||||
|
||||
return (new Config())
|
||||
->setRiskyAllowed(true)
|
||||
->setFinder($finder)
|
||||
->setUsingCache(true)
|
||||
->setParallelConfig(ParallelConfigFactory::detect())
|
||||
->setRules([
|
||||
'@Symfony' => true,
|
||||
'@PSR1' => true,
|
||||
@ -30,8 +25,8 @@ return (new Config())
|
||||
'combine_consecutive_unsets' => true,
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'heredoc_to_nowdoc' => true,
|
||||
// 'no_alias_functions' => true,
|
||||
// 'no_unreachable_default_argument_value' => true,
|
||||
'no_alias_functions' => true,
|
||||
'no_unreachable_default_argument_value' => true,
|
||||
'no_useless_return' => true,
|
||||
'ordered_imports' => [
|
||||
'sort_algorithm' => 'length',
|
||||
@ -47,7 +42,7 @@ return (new Config())
|
||||
'var',
|
||||
],
|
||||
],
|
||||
// 'random_api_migration' => true,
|
||||
'random_api_migration' => true,
|
||||
'ternary_to_null_coalescing' => true,
|
||||
'yoda_style' => [
|
||||
'equal' => false,
|
||||
|
||||
82
CHANGELOG.md
82
CHANGELOG.md
@ -3,88 +3,6 @@ This file is a running track of new features and fixes to each version of the pa
|
||||
|
||||
This project follows [Semantic Versioning](http://semver.org) guidelines.
|
||||
|
||||
## v1.12.0
|
||||
### Fixed
|
||||
|
||||
* [CVE-2025-68954](https://github.com/pterodactyl/panel/security/advisories/GHSA-8c39-xppg-479c)
|
||||
* [CVE-2025-69197](https://github.com/pterodactyl/panel/security/advisories/GHSA-rgmp-4873-r683)
|
||||
* [CVE-2025-69198](https://github.com/pterodactyl/panel/security/advisories/GHSA-jw2v-cq5x-q68g)
|
||||
* Fixes a self-XSS issue when entering random data into boxes while creating a new database host.
|
||||
* Fixes missing `HttpForbiddenException` import in the backup status controller.
|
||||
* Fixes issue where scheduled tasks would execute every minute regardless of their configured cron syntax.
|
||||
* Pressing `Ctrl+Z` to undo while editing a file no longer deletes the initial file content.
|
||||
* Fixed incorrect error message being returned when attempting to delete your own account as an admin.
|
||||
* Fixes node description not being settable via the API.
|
||||
* Fixes 0-bytes files returning an error when attempting to upload.
|
||||
* Fixes nodes displaying the first available location even when that field was not edited and the node has a different value set.
|
||||
* Fixes allocation notes not being reset when a server is deleted. ([#5157](https://github.com/pterodactyl/panel/pull/5157))
|
||||
|
||||
### Changed
|
||||
* Minimum NodeJS version updated to 22 for building.
|
||||
* Updated all JS and PHP dependencies to their latest versions (where feasible).
|
||||
* The endpoint for disabling 2FA on an account using the client API changed from `DELETE /api/client/account/two-factor` to `POST /api/client/account/two-factor/disable`
|
||||
* `^C` in an egg's stop configuration no longer rewrites itself into the default stop configuration.
|
||||
* `IBM Plex Sans` font is now bundled with the local assets instead of loading from Google CDNs.
|
||||
* Upload size on nodes is no longer restricted to a max of 1024MB, any positive integer value can be used.
|
||||
* Administrators are now listed first when viewing a list of all users on the system.
|
||||
* Websocket no longer endlessly polls when connection issues are encountered, or when Wings disconnects the user for a reason that should not be re-attempted.
|
||||
|
||||
## v1.11.10
|
||||
### Fixed
|
||||
* Update Laravel to address [CVE-2024-52301](https://github.com/advisories/GHSA-gv7v-rgg6-548h)
|
||||
|
||||
### Changed
|
||||
* Minimum PHP version is now 8.2 due to Laravel upgrade!
|
||||
|
||||
## v1.11.9
|
||||
### Fixed
|
||||
* Fixed issue with CI not pushing Docker image
|
||||
|
||||
## v1.11.8
|
||||
### Fixed
|
||||
* Fixed an issue where a `DELETE` request was used instead of a `POST`, potentially logging user passwords in plain text if they disable 2FA.
|
||||
|
||||
## v1.11.7
|
||||
### Added
|
||||
* Java 21 to Minecraft eggs
|
||||
|
||||
### Changed
|
||||
* Updated Minecraft EULA link
|
||||
|
||||
### Fixed
|
||||
* Fixed backups not ever being marked as completed (#5088)
|
||||
* Fixed `.7z` files not being detected as a compressed file (#5016)
|
||||
|
||||
## v1.11.6
|
||||
### Changed
|
||||
* Better node ownership checks for internal backup endpoints
|
||||
* Improved validation rules on `docker_image` fields to prevent invalid inputs
|
||||
|
||||
### Fixed
|
||||
* Multiple XSS vulnerabilities in the admin area ([GHSA-384w-wffr-x63q](https://github.com/pterodactyl/panel/security/advisories/GHSA-384w-wffr-x63q))
|
||||
|
||||
## v1.11.5
|
||||
### Fixed
|
||||
* Rust egg using the wrong Docker image, breaking Rust modding frameworks.
|
||||
|
||||
## v1.11.4
|
||||
### Added
|
||||
* Added support for the `server.queryport` option on the Rust egg.
|
||||
* Added support for the Carbon modding framework to the Rust egg.
|
||||
|
||||
### Changed
|
||||
* Upgraded to Laravel 10.
|
||||
* Sensitive data is no longer shown in the CopyOnClick toast notification.
|
||||
|
||||
### Fixed
|
||||
* Allow SVGs to be edited in the server's file manager.
|
||||
* Properly validate the request body when creating a backup.
|
||||
* Fixed issue with schedules running at the wrong time when the panel utilized a timezone with non-hour offsets (such as `Australia/Darwin`).
|
||||
* Fixes the log directory when running the Panel in a container.
|
||||
* Fixes the permission name used to check if a user has permission to read files/folders.
|
||||
* Fixes the ability to unset a server's description through the client API.
|
||||
* Fixed the MassActionBar on the server's file manager blocking elements below it, preventing them from being interacted with.
|
||||
|
||||
## v1.11.3
|
||||
### Changed
|
||||
* When updating a server's description through the client API, if no value is specified, the description will now remain unchanged.
|
||||
|
||||
74
CODE_OF_CONDUCT.md
Normal file
74
CODE_OF_CONDUCT.md
Normal 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/
|
||||
@ -1,33 +1,31 @@
|
||||
# Contributing
|
||||
|
||||
**Pterodactyl does not accept Pull Requests (PRs) _for new functionality_** that was not previously approved by project
|
||||
maintainers on GitHub discussions. It has become overwhelming to try and give the proper time and attention that such
|
||||
complicated PRs tend to require. As a result, it is in the project's best interest to limit the scope of work on new
|
||||
functionality to work done within the core project team.
|
||||
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 or features **with a corresponding issue opened in our issue tracker** will continue to
|
||||
be accepted and reviewed. Their scope is often significantly more targeted, and simply improving upon existing and well
|
||||
defined logic.
|
||||
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.
|
||||
|
||||
## AI Assistance
|
||||
### Responsible Disclosure
|
||||
|
||||
If you use any type of AI assistance while developing for Pterodactyl **it must be disclosed** within the
|
||||
corresponding review PR and you must identify what it was used for. All interaction with the community must be written
|
||||
by a human. **You MUST NOT use AI to compose any PR titles, descriptions, or comments**, and must not use AI to
|
||||
interact with the GitHub Discussions community.
|
||||
|
||||
## Responsible Disclosure
|
||||
|
||||
This is an in-depth project making use of many moving pieces. While we strive to keep everything as secure as possible
|
||||
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. Please see [`SECURITY.md`](/SECURITY.md)
|
||||
for information on how to report security issues to the team.
|
||||
others who are using the software and not publicly disclose security issues without contacting us first by email.
|
||||
|
||||
## Contact Us
|
||||
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. Please make use of
|
||||
our [GitHub Discussions](https://github.com/orgs/pterodactyl/discussions/categories/feature-requests)
|
||||
for any feature requests, general questions, or help with the software.
|
||||
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).
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
# Build the assets that are needed for the frontend. This build stage is then discarded
|
||||
# since we won't need NodeJS anymore in the future. This Docker image ships a final production
|
||||
# level distribution of Pterodactyl.
|
||||
FROM --platform=$TARGETOS/$TARGETARCH node:22-alpine
|
||||
FROM --platform=$TARGETOS/$TARGETARCH mhart/alpine-node:14
|
||||
WORKDIR /app
|
||||
COPY . ./
|
||||
RUN yarn install --frozen-lockfile \
|
||||
@ -10,7 +10,7 @@ RUN yarn install --frozen-lockfile \
|
||||
|
||||
# Stage 1:
|
||||
# Build the actual container with all of the needed PHP dependencies that will run the application.
|
||||
FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine
|
||||
FROM --platform=$TARGETOS/$TARGETARCH php:8.1-fpm-alpine
|
||||
WORKDIR /app
|
||||
COPY . ./
|
||||
COPY --from=0 /app/public/assets ./public/assets
|
||||
@ -23,7 +23,6 @@ RUN apk add --no-cache --update ca-certificates dcron curl git supervisor tar un
|
||||
&& chmod 777 -R bootstrap storage \
|
||||
&& composer install --no-dev --optimize-autoloader \
|
||||
&& rm -rf .env bootstrap/cache/*.php \
|
||||
&& mkdir -p /app/storage/logs/ \
|
||||
&& chown -R nginx:nginx .
|
||||
|
||||
RUN rm /usr/local/etc/php-fpm.conf \
|
||||
|
||||
28
README.md
28
README.md
@ -7,7 +7,7 @@
|
||||
|
||||
# Pterodactyl Panel
|
||||
|
||||
Pterodactyl® is a free, open-source game server management panel built with PHP, React, and Go. Designed with security
|
||||
Pterodactyl® is a free, open-source game server management panel built with PHP, React, and Go. Designed with security
|
||||
in mind, Pterodactyl runs all game servers in isolated Docker containers while exposing a beautiful and intuitive
|
||||
UI to end users.
|
||||
|
||||
@ -24,17 +24,21 @@ Stop settling for less. Make game servers a first class citizen on your platform
|
||||
|
||||
## Sponsors
|
||||
|
||||
I would like to extend my sincere thanks to the following sponsors for helping fund Pterodactyl's development.
|
||||
[Interested in becoming a sponsor?](https://github.com/sponsors/pterodactyl)
|
||||
I would like to extend my sincere thanks to the following sponsors for helping fund Pterodactyl's developement.
|
||||
[Interested in becoming a sponsor?](https://github.com/sponsors/matthewpi)
|
||||
|
||||
| Company | About |
|
||||
|-----------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [**Aussie Server Hosts**](https://aussieserverhosts.com/) | No frills Australian Owned and operated High Performance Server hosting for some of the most demanding games serving Australia and New Zealand. |
|
||||
| [**BisectHosting**](https://www.bisecthosting.com/) | BisectHosting provides Minecraft, Valheim and other server hosting services with the highest reliability and lightning fast support since 2012. |
|
||||
| [**MineStrator**](https://minestrator.com/) | Looking for the most highend French hosting company for your minecraft server? More than 24,000 members on our discord trust us. Give us a try! |
|
||||
| [**HostEZ**](https://hostez.io) | US & EU Rust & Minecraft Hosting. DDoS Protected bare metal, VPS and colocation with low latency, high uptime and maximum availability. EZ! |
|
||||
| [**Blueprint**](https://blueprint.zip/?utm_source=pterodactyl&utm_medium=sponsor) | Create and install Pterodactyl addons and themes with the growing Blueprint framework - the package-manager for Pterodactyl. Use multiple modifications at once without worrying about conflicts and make use of the large extension ecosystem. |
|
||||
| [**indifferent broccoli**](https://indifferentbroccoli.com/) | indifferent broccoli is a game server hosting and rental company. With us, you get top-notch computer power for your gaming sessions. We destroy lag, latency, and complexity--letting you focus on the fun stuff. |
|
||||
| Company | About |
|
||||
|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [**WISP**](https://wisp.gg) | Extra features. |
|
||||
| [**RocketNode**](https://rocketnode.com/) | Innovative game server hosting combined with a straightforward control panel, affordable prices, and Rocket-Fast support. |
|
||||
| [**Aussie Server Hosts**](https://aussieserverhosts.com/) | No frills Australian Owned and operated High Performance Server hosting for some of the most demanding games serving Australia and New Zealand. |
|
||||
| [**BisectHosting**](https://www.bisecthosting.com/) | BisectHosting provides Minecraft, Valheim and other server hosting services with the highest reliability and lightning fast support since 2012. |
|
||||
| [**MineStrator**](https://minestrator.com/) | Looking for the most highend French hosting company for your minecraft server? More than 24,000 members on our discord trust us. Give us a try! |
|
||||
| [**Skynode**](https://www.skynode.pro/) | Skynode provides blazing fast game servers along with a top-notch user experience. Whatever our clients are looking for, we're able to provide it! |
|
||||
| [**VibeGAMES**](https://vibegames.net/) | VibeGAMES is a game server provider that specializes in DDOS protection for the games we offer. We have multiple locations in the US, Brazil, France, Germany, Singapore, Australia and South Africa. |
|
||||
| [**Pterodactyl Market**](https://pterodactylmarket.com/) | Pterodactyl Market is a one-and-stop shop for Pterodactyl. In our market, you can find Add-ons, Themes, Eggs, and more for Pterodactyl. |
|
||||
| [**UltraServers**](https://ultraservers.com/) | Deploy premium games hosting with the click of a button. Manage and swap games with ease and let us take care of the rest. We currently support Minecraft, Rust, ARK, 7 Days to Die, Garys MOD, CS:GO, Satisfactory and others. |
|
||||
| [**Realms Hosting**](https://realmshosting.com/) | Want to build your Gaming Empire? Use Realms Hosting today to kick start your game server hosting with outstanding DDOS Protection, 24/7 Support, Cheap Prices and a Custom Control Panel. | |
|
||||
|
||||
### Supported Games
|
||||
|
||||
@ -63,7 +67,7 @@ and there are plenty more games available provided by the community. Some of the
|
||||
* Xonotic
|
||||
* Starmade
|
||||
* Discord ATLBot, and most other Node.js/Python discord bots
|
||||
* [and many more...](https://pterodactyleggs.com)
|
||||
* [and many more...](https://github.com/parkervcp/eggs)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
24
SECURITY.md
24
SECURITY.md
@ -2,23 +2,19 @@
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Pterodactyl only provides security support for the latest `major.minor` versions of the Panel and Wings software.
|
||||
If a security vulnerability is found in an older version but cannot be reproduced on a supported version it will
|
||||
not be considered. Additionally, security issues found in unreleased code will be addressed, but do not warrant a
|
||||
security advisory.
|
||||
The following versions of Pterodactyl are receiving active support and maintenance. Any security vulnerabilities discovered must be reproducible in supported versions.
|
||||
|
||||
| Panel | Daemon | Supported |
|
||||
|--------|--------------|--------------------|
|
||||
| 1.10.x | wings@1.7.x | :white_check_mark: |
|
||||
| 1.11.x | wings@1.11.x | :white_check_mark: |
|
||||
| 0.7.x | daemon@0.6.x | :x: |
|
||||
|
||||
For example, if the latest version of the Panel is `1.2.5` then we only support security reports for issues that
|
||||
occur on `>= 1.2.x` versions of the Panel software. The Panel and Wings have their own versions, but they generally
|
||||
follow eachother.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please use our GitHub Security reporting meachnism to quickly alert the team to any security issues you come across,
|
||||
or send an email to `security@pterodactyl.io` with the details of your report.
|
||||
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.
|
||||
We make every effort to respond as soon as possible, although it may take a day or two for us to sync internally and determine the severity of the report and its impact. Please, _do not_ use a public facing channel or GitHub issues to report sensitive security issues.
|
||||
|
||||
As part of our process, we will create a security advisory for the affected versions and disclose it publicly, usually
|
||||
two to four weeks after a releasing a version that addresses it.
|
||||
As part of our process, we will create a security advisory for the affected versions and disclose it publicly, usually two to four weeks after a releasing a version that addresses it.
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Environment;
|
||||
|
||||
use DateTimeZone;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Pterodactyl\Traits\Commands\EnvironmentWriterTrait;
|
||||
@ -88,7 +89,7 @@ class AppSettingsCommand extends Command
|
||||
$this->output->comment('The timezone should match one of PHP\'s supported timezones. If you are unsure, please reference https://php.net/manual/en/timezones.php.');
|
||||
$this->variables['APP_TIMEZONE'] = $this->option('timezone') ?? $this->anticipate(
|
||||
'Application Timezone',
|
||||
\DateTimeZone::listIdentifiers(),
|
||||
DateTimeZone::listIdentifiers(),
|
||||
config('app.timezone')
|
||||
);
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Environment;
|
||||
|
||||
use PDOException;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Illuminate\Database\DatabaseManager;
|
||||
@ -71,7 +72,7 @@ class DatabaseSettingsCommand extends Command
|
||||
|
||||
try {
|
||||
$this->testMySQLConnection();
|
||||
} catch (\PDOException $exception) {
|
||||
} catch (PDOException $exception) {
|
||||
$this->output->error(sprintf('Unable to connect to the MySQL server using the provided credentials. The error returned was "%s".', $exception->getMessage()));
|
||||
$this->output->error('Your connection credentials have NOT been saved. You will need to provide valid connection information before proceeding.');
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ class EmailSettingsCommand extends Command
|
||||
trans('command/messages.environment.mail.ask_driver'),
|
||||
[
|
||||
'smtp' => 'SMTP Server',
|
||||
'sendmail' => 'sendmail Binary',
|
||||
'mail' => 'PHP\'s Internal Mail Function',
|
||||
'mailgun' => 'Mailgun Transactional Email',
|
||||
'mandrill' => 'Mandrill Transactional Email',
|
||||
'postmark' => 'Postmark Transactional Email',
|
||||
|
||||
@ -20,7 +20,7 @@ class DeleteLocationCommand extends Command
|
||||
*/
|
||||
public function __construct(
|
||||
private LocationDeletionService $deletionService,
|
||||
private LocationRepositoryInterface $repository,
|
||||
private LocationRepositoryInterface $repository
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Maintenance;
|
||||
|
||||
use SplFileInfo;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
@ -34,9 +35,9 @@ class CleanServiceBackupFilesCommand extends Command
|
||||
{
|
||||
$files = $this->disk->files('services/.bak');
|
||||
|
||||
collect($files)->each(function (\SplFileInfo $file) {
|
||||
collect($files)->each(function (SplFileInfo $file) {
|
||||
$lastModified = Carbon::createFromTimestamp($this->disk->lastModified($file->getPath()));
|
||||
if ((int) $lastModified->diffInMinutes(Carbon::now()) > self::BACKUP_THRESHOLD_MINUTES) {
|
||||
if ($lastModified->diffInMinutes(Carbon::now()) > self::BACKUP_THRESHOLD_MINUTES) {
|
||||
$this->disk->delete($file->getPath());
|
||||
$this->info(trans('command/messages.maintenance.deleting_service_backup', ['file' => $file->getFilename()]));
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace Pterodactyl\Console\Commands\Maintenance;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Console\Command;
|
||||
use Pterodactyl\Repositories\Eloquent\BackupRepository;
|
||||
|
||||
@ -10,7 +11,7 @@ class PruneOrphanedBackupsCommand extends Command
|
||||
{
|
||||
protected $signature = 'p:maintenance:prune-backups {--prune-age=}';
|
||||
|
||||
protected $description = 'Marks all backups older than "n" minutes that have not yet completed as being failed.';
|
||||
protected $description = 'Marks all backups that have not completed in the last "n" minutes as being failed.';
|
||||
|
||||
/**
|
||||
* PruneOrphanedBackupsCommand constructor.
|
||||
@ -24,7 +25,7 @@ class PruneOrphanedBackupsCommand extends Command
|
||||
{
|
||||
$since = $this->option('prune-age') ?? config('backups.prune_age', 360);
|
||||
if (!$since || !is_digit($since)) {
|
||||
throw new \InvalidArgumentException('The "--prune-age" argument must be a value greater than 0.');
|
||||
throw new InvalidArgumentException('The "--prune-age" argument must be a value greater than 0.');
|
||||
}
|
||||
|
||||
$query = $this->backupRepository->getBuilder()
|
||||
@ -38,7 +39,7 @@ class PruneOrphanedBackupsCommand extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
$this->warn("Marking $count uncompleted backups that are older than $since minutes as failed.");
|
||||
$this->warn("Marking $count backups that have not been marked as completed in the last $since minutes as failed.");
|
||||
|
||||
$query->update([
|
||||
'is_successful' => false,
|
||||
|
||||
@ -17,7 +17,7 @@ class NodeConfigurationCommand extends Command
|
||||
{
|
||||
$column = ctype_digit((string) $this->argument('node')) ? 'id' : 'uuid';
|
||||
|
||||
/** @var 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.');
|
||||
|
||||
|
||||
@ -21,6 +21,6 @@ class UpCommand extends BaseUpCommand
|
||||
return 1;
|
||||
}
|
||||
|
||||
return parent::handle();
|
||||
return parent::handle() ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Schedule;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use Illuminate\Console\Command;
|
||||
use Pterodactyl\Models\Schedule;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@ -66,7 +68,7 @@ class ProcessRunnableCommand extends Command
|
||||
'schedule' => $schedule->name,
|
||||
'hash' => $schedule->hashid,
|
||||
]));
|
||||
} catch (\Throwable $exception) {
|
||||
} catch (Throwable|Exception $exception) {
|
||||
Log::error($exception, ['schedule_id' => $schedule->id]);
|
||||
|
||||
$this->error("An error was encountered while processing Schedule #$schedule->id: " . $exception->getMessage());
|
||||
|
||||
@ -30,7 +30,7 @@ class BulkPowerActionCommand extends Command
|
||||
/**
|
||||
* Handle the bulk power request.
|
||||
*
|
||||
* @throws ValidationException
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
@ -97,7 +97,7 @@ class BulkPowerActionCommand extends Command
|
||||
$instance->whereIn('id', $servers)->orWhereIn('node_id', $nodes);
|
||||
} elseif (empty($nodes) && !empty($servers)) {
|
||||
$instance->whereIn('id', $servers);
|
||||
} elseif (!empty($nodes) && empty($servers)) { // @phpstan-ignore empty.variable
|
||||
} elseif (!empty($nodes) && empty($servers)) {
|
||||
$instance->whereIn('node_id', $nodes);
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Console\Commands;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Console\Command;
|
||||
use Pterodactyl\Console\Kernel;
|
||||
use Symfony\Component\Process\Process;
|
||||
@ -39,8 +40,8 @@ class UpgradeCommand extends Command
|
||||
$this->line($this->getUrl());
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '8.2.0', '<')) {
|
||||
$this->error('Cannot execute self-upgrade process. The minimum required PHP version required is 8.2.0, you have [' . PHP_VERSION . '].');
|
||||
if (version_compare(PHP_VERSION, '7.4.0') < 0) {
|
||||
$this->error('Cannot execute self-upgrade process. The minimum required PHP version required is 7.4.0, you have [' . PHP_VERSION . '].');
|
||||
}
|
||||
|
||||
$user = 'www-data';
|
||||
@ -133,7 +134,7 @@ class UpgradeCommand extends Command
|
||||
|
||||
/** @var \Illuminate\Foundation\Application $app */
|
||||
$app = require __DIR__ . '/../../../bootstrap/app.php';
|
||||
/** @var Kernel $kernel */
|
||||
/** @var \Pterodactyl\Console\Kernel $kernel */
|
||||
$kernel = $app->make(Kernel::class);
|
||||
$kernel->bootstrap();
|
||||
$this->setLaravel($app);
|
||||
@ -176,7 +177,7 @@ class UpgradeCommand extends Command
|
||||
$this->info('Panel has been successfully upgraded. Please ensure you also update any Wings instances: https://pterodactyl.io/wings/1.0/upgrading.html');
|
||||
}
|
||||
|
||||
protected function withProgress(ProgressBar $bar, \Closure $callback)
|
||||
protected function withProgress(ProgressBar $bar, Closure $callback)
|
||||
{
|
||||
$bar->clear();
|
||||
$callback();
|
||||
|
||||
@ -18,7 +18,7 @@ class Kernel extends ConsoleKernel
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
*/
|
||||
protected function commands(): void
|
||||
protected function commands()
|
||||
{
|
||||
$this->load(__DIR__ . '/Commands');
|
||||
}
|
||||
@ -26,11 +26,8 @@ class Kernel extends ConsoleKernel
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// https://laravel.com/docs/10.x/upgrade#redis-cache-tags
|
||||
$schedule->command('cache:prune-stale-tags')->hourly();
|
||||
|
||||
// Execute scheduled commands for servers every minute, as if there was a normal cron running.
|
||||
$schedule->command(ProcessRunnableCommand::class)->everyMinute()->withoutOverlapping();
|
||||
$schedule->command(CleanServiceBackupFilesCommand::class)->daily();
|
||||
|
||||
@ -11,5 +11,5 @@ interface HashidsInterface extends VendorHashidsInterface
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function decodeFirst(string $encoded, ?string $default = null): mixed;
|
||||
public function decodeFirst(string $encoded, string $default = null): mixed;
|
||||
}
|
||||
|
||||
@ -12,14 +12,14 @@ interface NestRepositoryInterface extends RepositoryInterface
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function getWithEggs(?int $id = null): Collection|Nest;
|
||||
public function getWithEggs(int $id = null): Collection|Nest;
|
||||
|
||||
/**
|
||||
* Return a nest or all nests and the count of eggs and servers for that nest.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function getWithCounts(?int $id = null): Collection|Nest;
|
||||
public function getWithCounts(int $id = null): Collection|Nest;
|
||||
|
||||
/**
|
||||
* Return a nest along with its associated eggs and the servers relation on those eggs.
|
||||
|
||||
@ -16,12 +16,12 @@ interface ServerRepositoryInterface extends RepositoryInterface
|
||||
/**
|
||||
* Return a collection of servers with their associated data for rebuild operations.
|
||||
*/
|
||||
public function getDataForRebuild(?int $server = null, ?int $node = null): Collection;
|
||||
public function getDataForRebuild(int $server = null, int $node = null): Collection;
|
||||
|
||||
/**
|
||||
* Return a collection of servers with their associated data for reinstall operations.
|
||||
*/
|
||||
public function getDataForReinstall(?int $server = null, ?int $node = null): Collection;
|
||||
public function getDataForReinstall(int $server = null, int $node = null): Collection;
|
||||
|
||||
/**
|
||||
* Return a server model and all variables associated with the server.
|
||||
|
||||
@ -10,7 +10,7 @@ interface SettingsRepositoryInterface extends RepositoryInterface
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function set(string $key, ?string $value = null);
|
||||
public function set(string $key, string $value = null);
|
||||
|
||||
/**
|
||||
* Retrieve a persistent setting from the database.
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Enum;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Webmozart\Assert\Assert;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
|
||||
/**
|
||||
* A basic resource throttler for individual servers. This is applied in addition
|
||||
* to existing rate limits and allows the code to slow down speedy users that might
|
||||
* be creating resources a little too quickly for comfort. This throttle generally
|
||||
* only applies to creation flows, and not general view/edit/delete flows.
|
||||
*/
|
||||
enum ResourceLimit
|
||||
{
|
||||
case Allocation;
|
||||
case Backup;
|
||||
case Database;
|
||||
case Schedule;
|
||||
case Subuser;
|
||||
case Websocket;
|
||||
case FilePull;
|
||||
|
||||
public function throttleKey(): string
|
||||
{
|
||||
return mb_strtolower("api.client:server-resource:{$this->name}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a middleware that will throttle the specific resource by server. This
|
||||
* throttle applies to any user making changes to that resource on the specific
|
||||
* server, it is NOT per-user.
|
||||
*/
|
||||
public function middleware(): string
|
||||
{
|
||||
return ThrottleRequests::using($this->throttleKey());
|
||||
}
|
||||
|
||||
public function limit(): Limit
|
||||
{
|
||||
return match($this) {
|
||||
self::Backup => Limit::perMinutes(15, 3),
|
||||
self::Database => Limit::perMinute(2),
|
||||
self::FilePull => Limit::perMinutes(10, 5),
|
||||
self::Subuser => Limit::perMinutes(15, 10),
|
||||
self::Websocket => Limit::perMinute(5),
|
||||
default => Limit::perMinute(2),
|
||||
};
|
||||
}
|
||||
|
||||
public static function boot(): void
|
||||
{
|
||||
foreach (self::cases() as $case) {
|
||||
RateLimiter::for($case->throttleKey(), function (Request $request) use ($case) {
|
||||
Assert::isInstanceOf($server = $request->route()->parameter('server'), Server::class);
|
||||
|
||||
return $case->limit()->by($server->uuid);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Pterodactyl\Exceptions;
|
||||
|
||||
class AccountNotFoundException extends \Exception
|
||||
use Exception;
|
||||
|
||||
class AccountNotFoundException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Pterodactyl\Exceptions;
|
||||
|
||||
class AutoDeploymentException extends \Exception
|
||||
use Exception;
|
||||
|
||||
class AutoDeploymentException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace Pterodactyl\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use Illuminate\Http\Request;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Illuminate\Http\Response;
|
||||
@ -22,7 +23,7 @@ class DisplayException extends PterodactylException implements HttpExceptionInte
|
||||
/**
|
||||
* DisplayException constructor.
|
||||
*/
|
||||
public function __construct(string $message, ?\Throwable $previous = null, protected string $level = self::LEVEL_ERROR, int $code = 0)
|
||||
public function __construct(string $message, ?Throwable $previous = null, protected string $level = self::LEVEL_ERROR, int $code = 0)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
@ -66,13 +67,13 @@ class DisplayException extends PterodactylException implements HttpExceptionInte
|
||||
*/
|
||||
public function report()
|
||||
{
|
||||
if (!$this->getPrevious() instanceof \Exception || !Handler::isReportable($this->getPrevious())) {
|
||||
if (!$this->getPrevious() instanceof Exception || !Handler::isReportable($this->getPrevious())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$logger = Container::getInstance()->make(LoggerInterface::class);
|
||||
} catch (\Exception) {
|
||||
} catch (Exception) {
|
||||
throw $this->getPrevious();
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
namespace Pterodactyl\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use PDOException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@ -73,13 +75,13 @@ class Handler extends ExceptionHandler
|
||||
*
|
||||
* @noinspection PhpUnusedLocalVariableInspection
|
||||
*/
|
||||
public function register(): void
|
||||
public function register()
|
||||
{
|
||||
if (config('app.exceptions.report_all', false)) {
|
||||
$this->dontReport = [];
|
||||
}
|
||||
|
||||
$this->reportable(function (\PDOException $ex) {
|
||||
$this->reportable(function (PDOException $ex) {
|
||||
$ex = $this->generateCleanedExceptionStack($ex);
|
||||
});
|
||||
|
||||
@ -88,7 +90,7 @@ class Handler extends ExceptionHandler
|
||||
});
|
||||
}
|
||||
|
||||
private function generateCleanedExceptionStack(\Throwable $exception): string
|
||||
private function generateCleanedExceptionStack(Throwable $exception): string
|
||||
{
|
||||
$cleanedStack = '';
|
||||
foreach ($exception->getTrace() as $index => $item) {
|
||||
@ -121,7 +123,7 @@ class Handler extends ExceptionHandler
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function render($request, \Throwable $e): Response
|
||||
public function render($request, Throwable $e): Response
|
||||
{
|
||||
$connections = $this->container->make(Connection::class);
|
||||
|
||||
@ -187,7 +189,7 @@ class Handler extends ExceptionHandler
|
||||
/**
|
||||
* Return the exception as a JSONAPI representation for use on API requests.
|
||||
*/
|
||||
protected function convertExceptionToArray(\Throwable $e, array $override = []): array
|
||||
protected function convertExceptionToArray(Throwable $e, array $override = []): array
|
||||
{
|
||||
$match = self::$exceptionResponseCodes[get_class($e)] ?? null;
|
||||
|
||||
@ -233,9 +235,9 @@ class Handler extends ExceptionHandler
|
||||
/**
|
||||
* Return an array of exceptions that should not be reported.
|
||||
*/
|
||||
public static function isReportable(\Exception $exception): bool
|
||||
public static function isReportable(Exception $exception): bool
|
||||
{
|
||||
return (new self(Container::getInstance()))->shouldReport($exception);
|
||||
return (new static(Container::getInstance()))->shouldReport($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,11 +260,11 @@ class Handler extends ExceptionHandler
|
||||
*
|
||||
* @return \Throwable[]
|
||||
*/
|
||||
protected function extractPrevious(\Throwable $e): array
|
||||
protected function extractPrevious(Throwable $e): array
|
||||
{
|
||||
$previous = [];
|
||||
while ($value = $e->getPrevious()) {
|
||||
if (!$value instanceof \Throwable) { // @phpstan-ignore instanceof.alwaysTrue
|
||||
if (!$value instanceof Throwable) {
|
||||
break;
|
||||
}
|
||||
$previous[] = $value;
|
||||
@ -276,7 +278,7 @@ class Handler extends ExceptionHandler
|
||||
* Helper method to allow reaching into the handler to convert an exception
|
||||
* into the expected array response type.
|
||||
*/
|
||||
public static function toArray(\Throwable $e): array
|
||||
public static function toArray(Throwable $e): array
|
||||
{
|
||||
return (new self(app()))->convertExceptionToArray($e);
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ class HttpForbiddenException extends HttpException
|
||||
/**
|
||||
* HttpForbiddenException constructor.
|
||||
*/
|
||||
public function __construct(?string $message = null, ?\Throwable $previous = null)
|
||||
public function __construct(string $message = null, \Throwable $previous = null)
|
||||
{
|
||||
parent::__construct(Response::HTTP_FORBIDDEN, $message, $previous);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Exceptions\Http\Server;
|
||||
|
||||
use Throwable;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
|
||||
|
||||
@ -11,7 +12,7 @@ class ServerStateConflictException extends ConflictHttpException
|
||||
* Exception thrown when the server is in an unsupported state for API access or
|
||||
* certain operations within the codebase.
|
||||
*/
|
||||
public function __construct(Server $server, ?\Throwable $previous = null)
|
||||
public function __construct(Server $server, Throwable $previous = null)
|
||||
{
|
||||
$message = 'This server is currently in an unsupported state, please try again later.';
|
||||
if ($server->isSuspended()) {
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Exceptions\Http;
|
||||
|
||||
use Throwable;
|
||||
use Illuminate\Http\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
@ -11,7 +12,7 @@ class TwoFactorAuthRequiredException extends HttpException implements HttpExcept
|
||||
/**
|
||||
* TwoFactorAuthRequiredException constructor.
|
||||
*/
|
||||
public function __construct(?\Throwable $previous = null)
|
||||
public function __construct(Throwable $previous = null)
|
||||
{
|
||||
parent::__construct(Response::HTTP_BAD_REQUEST, 'Two-factor authentication is required on this account in order to access this endpoint.', $previous);
|
||||
}
|
||||
|
||||
@ -2,10 +2,11 @@
|
||||
|
||||
namespace Pterodactyl\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Spatie\Ignition\Contracts\Solution;
|
||||
use Spatie\Ignition\Contracts\ProvidesSolution;
|
||||
|
||||
class ManifestDoesNotExistException extends \Exception implements ProvidesSolution
|
||||
class ManifestDoesNotExistException extends Exception implements ProvidesSolution
|
||||
{
|
||||
public function getSolution(): Solution
|
||||
{
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Pterodactyl\Exceptions;
|
||||
|
||||
class PterodactylException extends \Exception
|
||||
use Exception;
|
||||
|
||||
class PterodactylException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Pterodactyl\Exceptions\Service\Helper;
|
||||
|
||||
class CdnVersionFetchingException extends \Exception
|
||||
use Exception;
|
||||
|
||||
class CdnVersionFetchingException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Exceptions\Service;
|
||||
|
||||
use Throwable;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
|
||||
class ServiceLimitExceededException extends DisplayException
|
||||
@ -10,7 +11,7 @@ class ServiceLimitExceededException extends DisplayException
|
||||
* Exception thrown when something goes over a defined limit, such as allocated
|
||||
* ports, tasks, databases, etc.
|
||||
*/
|
||||
public function __construct(string $message, ?\Throwable $previous = null)
|
||||
public function __construct(string $message, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $previous, self::LEVEL_WARNING);
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ use Aws\S3\S3Client;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Webmozart\Assert\Assert;
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Foundation\Application;
|
||||
use League\Flysystem\FilesystemAdapter;
|
||||
use Pterodactyl\Extensions\Filesystem\S3Filesystem;
|
||||
@ -38,7 +39,7 @@ class BackupManager
|
||||
/**
|
||||
* Returns a backup adapter instance.
|
||||
*/
|
||||
public function adapter(?string $name = null): FilesystemAdapter
|
||||
public function adapter(string $name = null): FilesystemAdapter
|
||||
{
|
||||
return $this->get($name ?: $this->getDefaultAdapter());
|
||||
}
|
||||
@ -69,7 +70,7 @@ class BackupManager
|
||||
$config = $this->getConfig($name);
|
||||
|
||||
if (empty($config['adapter'])) {
|
||||
throw new \InvalidArgumentException("Backup disk [$name] does not have a configured adapter.");
|
||||
throw new InvalidArgumentException("Backup disk [$name] does not have a configured adapter.");
|
||||
}
|
||||
|
||||
$adapter = $config['adapter'];
|
||||
@ -87,7 +88,7 @@ class BackupManager
|
||||
return $instance;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Adapter [$adapter] is not supported.");
|
||||
throw new InvalidArgumentException("Adapter [$adapter] is not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,7 +164,7 @@ class BackupManager
|
||||
/**
|
||||
* Register a custom adapter creator closure.
|
||||
*/
|
||||
public function extend(string $adapter, \Closure $callback): self
|
||||
public function extend(string $adapter, Closure $callback): self
|
||||
{
|
||||
$this->customCreators[$adapter] = $callback;
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ class DynamicDatabaseConnection
|
||||
public function __construct(
|
||||
protected ConfigRepository $config,
|
||||
protected Encrypter $encrypter,
|
||||
protected DatabaseHostRepositoryInterface $repository,
|
||||
protected DatabaseHostRepositoryInterface $repository
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
@ -2,16 +2,21 @@
|
||||
|
||||
namespace Pterodactyl\Extensions;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Hashids\Hashids as VendorHashids;
|
||||
use Pterodactyl\Contracts\Extensions\HashidsInterface;
|
||||
|
||||
class Hashids extends VendorHashids implements HashidsInterface
|
||||
{
|
||||
public function decodeFirst(string $encoded, ?string $default = null): mixed
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function decodeFirst(string $encoded, string $default = null): mixed
|
||||
{
|
||||
$result = $this->decode($encoded);
|
||||
if (!is_array($result)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return Arr::first($result, null, $default);
|
||||
return array_first($result, null, $default);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ use Pterodactyl\Models\ApiKey;
|
||||
use Laravel\Sanctum\NewAccessToken as SanctumAccessToken;
|
||||
|
||||
/**
|
||||
* @property ApiKey $accessToken
|
||||
* @property \Pterodactyl\Models\ApiKey $accessToken
|
||||
*/
|
||||
class NewAccessToken extends SanctumAccessToken
|
||||
{
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Extensions\Lcobucci\JWT\Encoding;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Lcobucci\JWT\ClaimsFormatter;
|
||||
use Lcobucci\JWT\Token\RegisteredClaims;
|
||||
|
||||
@ -20,7 +21,7 @@ final class TimestampDates implements ClaimsFormatter
|
||||
continue;
|
||||
}
|
||||
|
||||
assert($claims[$claim] instanceof \DateTimeImmutable);
|
||||
assert($claims[$claim] instanceof DateTimeImmutable);
|
||||
$claims[$claim] = $claims[$claim]->getTimestamp();
|
||||
}
|
||||
|
||||
|
||||
@ -5,9 +5,6 @@ namespace Pterodactyl\Facades;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
use Pterodactyl\Services\Activity\ActivityLogTargetableService;
|
||||
|
||||
/**
|
||||
* @mixin \Pterodactyl\Services\Activity\ActivityLogTargetableService
|
||||
*/
|
||||
class LogTarget extends Facade
|
||||
{
|
||||
protected static function getFacadeAccessor(): string
|
||||
|
||||
@ -15,6 +15,8 @@ final class Time
|
||||
*/
|
||||
public static function getMySQLTimezoneOffset(string $timezone): string
|
||||
{
|
||||
return CarbonImmutable::now($timezone)->getTimezone()->toOffsetName();
|
||||
$offset = round(CarbonImmutable::now($timezone)->getTimezone()->getOffset(CarbonImmutable::now('UTC')) / 3600);
|
||||
|
||||
return sprintf('%s%s:00', $offset > 0 ? '+' : '-', str_pad((string) abs($offset), 2, '0', STR_PAD_LEFT));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Helpers;
|
||||
|
||||
use Exception;
|
||||
use Carbon\Carbon;
|
||||
use Cron\CronExpression;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@ -24,7 +25,7 @@ class Utilities
|
||||
|
||||
$string = substr_replace($string, $character, random_int(0, $length - 1), 1);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
} catch (Exception $exception) {
|
||||
// Just log the error and hope for the best at this point.
|
||||
Log::error($exception);
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ use Pterodactyl\Models\ApiKey;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Pterodactyl\Services\Acl\Api\AdminAcl;
|
||||
use Illuminate\View\Factory as ViewFactory;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Api\KeyCreationService;
|
||||
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
|
||||
@ -23,6 +24,7 @@ class ApiController extends Controller
|
||||
private AlertsMessageBag $alert,
|
||||
private ApiKeyRepositoryInterface $repository,
|
||||
private KeyCreationService $keyCreationService,
|
||||
private ViewFactory $view,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -31,7 +33,7 @@ class ApiController extends Controller
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
return view('admin.api.index', [
|
||||
return $this->view->make('admin.api.index', [
|
||||
'keys' => $this->repository->getApplicationKeys($request->user()),
|
||||
]);
|
||||
}
|
||||
@ -46,7 +48,7 @@ class ApiController extends Controller
|
||||
$resources = AdminAcl::getResourceList();
|
||||
sort($resources);
|
||||
|
||||
return view('admin.api.new', [
|
||||
return $this->view->make('admin.api.new', [
|
||||
'resources' => $resources,
|
||||
'permissions' => [
|
||||
'r' => AdminAcl::READ,
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\View\Factory as ViewFactory;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Helpers\SoftwareVersionService;
|
||||
|
||||
@ -11,7 +12,7 @@ class BaseController extends Controller
|
||||
/**
|
||||
* BaseController constructor.
|
||||
*/
|
||||
public function __construct(private SoftwareVersionService $version)
|
||||
public function __construct(private SoftwareVersionService $version, private ViewFactory $view)
|
||||
{
|
||||
}
|
||||
|
||||
@ -20,6 +21,6 @@ class BaseController extends Controller
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.index', ['version' => $this->version]);
|
||||
return $this->view->make('admin.index', ['version' => $this->version]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,13 @@
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin;
|
||||
|
||||
use Exception;
|
||||
use PDOException;
|
||||
use Illuminate\View\View;
|
||||
use Pterodactyl\Models\DatabaseHost;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Illuminate\View\Factory as ViewFactory;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Databases\Hosts\HostUpdateService;
|
||||
use Pterodactyl\Http\Requests\Admin\DatabaseHostFormRequest;
|
||||
@ -28,6 +31,7 @@ class DatabaseController extends Controller
|
||||
private HostDeletionService $deletionService,
|
||||
private HostUpdateService $updateService,
|
||||
private LocationRepositoryInterface $locationRepository,
|
||||
private ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -36,7 +40,7 @@ class DatabaseController extends Controller
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.databases.index', [
|
||||
return $this->view->make('admin.databases.index', [
|
||||
'locations' => $this->locationRepository->getAllWithNodes(),
|
||||
'hosts' => $this->repository->getWithViewDetails(),
|
||||
]);
|
||||
@ -49,7 +53,7 @@ class DatabaseController extends Controller
|
||||
*/
|
||||
public function view(int $host): View
|
||||
{
|
||||
return view('admin.databases.view', [
|
||||
return $this->view->make('admin.databases.view', [
|
||||
'locations' => $this->locationRepository->getAllWithNodes(),
|
||||
'host' => $this->repository->find($host),
|
||||
'databases' => $this->databaseRepository->getDatabasesForHost($host),
|
||||
@ -65,8 +69,8 @@ class DatabaseController extends Controller
|
||||
{
|
||||
try {
|
||||
$host = $this->creationService->handle($request->normalize());
|
||||
} catch (\Exception $exception) {
|
||||
if ($exception instanceof \PDOException || $exception->getPrevious() instanceof \PDOException) {
|
||||
} catch (Exception $exception) {
|
||||
if ($exception instanceof PDOException || $exception->getPrevious() instanceof PDOException) {
|
||||
$this->alert->danger(
|
||||
sprintf('There was an error while trying to connect to the host or while executing a query: "%s"', $exception->getMessage())
|
||||
)->flash();
|
||||
@ -94,10 +98,10 @@ class DatabaseController extends Controller
|
||||
try {
|
||||
$this->updateService->handle($host->id, $request->normalize());
|
||||
$this->alert->success('Database host was updated successfully.')->flash();
|
||||
} catch (\Exception $exception) {
|
||||
} catch (Exception $exception) {
|
||||
// Catch any SQL related exceptions and display them back to the user, otherwise just
|
||||
// throw the exception like normal and move on with it.
|
||||
if ($exception instanceof \PDOException || $exception->getPrevious() instanceof \PDOException) {
|
||||
if ($exception instanceof PDOException || $exception->getPrevious() instanceof PDOException) {
|
||||
$this->alert->danger(
|
||||
sprintf('There was an error while trying to connect to the host or while executing a query: "%s"', $exception->getMessage())
|
||||
)->flash();
|
||||
|
||||
@ -26,7 +26,7 @@ class LocationController extends Controller
|
||||
protected LocationDeletionService $deletionService,
|
||||
protected LocationRepositoryInterface $repository,
|
||||
protected LocationUpdateService $updateService,
|
||||
protected ViewFactory $view,
|
||||
protected ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ class LocationController extends Controller
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.locations.index', [
|
||||
return $this->view->make('admin.locations.index', [
|
||||
'locations' => $this->repository->getAllWithDetails(),
|
||||
]);
|
||||
}
|
||||
@ -47,7 +47,7 @@ class LocationController extends Controller
|
||||
*/
|
||||
public function view(int $id): View
|
||||
{
|
||||
return view('admin.locations.view', [
|
||||
return $this->view->make('admin.locations.view', [
|
||||
'location' => $this->repository->getWithNodes($id),
|
||||
]);
|
||||
}
|
||||
@ -86,7 +86,7 @@ class LocationController extends Controller
|
||||
* Delete a location from the system.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function delete(Location $location): RedirectResponse
|
||||
{
|
||||
|
||||
@ -28,7 +28,7 @@ class MountController extends Controller
|
||||
protected NestRepositoryInterface $nestRepository,
|
||||
protected LocationRepositoryInterface $locationRepository,
|
||||
protected MountRepository $repository,
|
||||
protected ViewFactory $view,
|
||||
protected ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ class MountController extends Controller
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.mounts.index', [
|
||||
return $this->view->make('admin.mounts.index', [
|
||||
'mounts' => $this->repository->getAllWithDetails(),
|
||||
]);
|
||||
}
|
||||
@ -52,7 +52,7 @@ class MountController extends Controller
|
||||
$nests = Nest::query()->with('eggs')->get();
|
||||
$locations = Location::query()->with('nodes')->get();
|
||||
|
||||
return view('admin.mounts.view', [
|
||||
return $this->view->make('admin.mounts.view', [
|
||||
'mount' => $this->repository->getWithRelations($id),
|
||||
'nests' => $nests,
|
||||
'locations' => $locations,
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Nests;
|
||||
|
||||
use JavaScript;
|
||||
use Illuminate\View\View;
|
||||
use Pterodactyl\Models\Egg;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
@ -27,7 +28,7 @@ class EggController extends Controller
|
||||
protected EggRepositoryInterface $repository,
|
||||
protected EggUpdateService $updateService,
|
||||
protected NestRepositoryInterface $nestRepository,
|
||||
protected ViewFactory $view,
|
||||
protected ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -39,9 +40,9 @@ class EggController extends Controller
|
||||
public function create(): View
|
||||
{
|
||||
$nests = $this->nestRepository->getWithEggs();
|
||||
\JavaScript::put(['nests' => $nests->keyBy('id')]);
|
||||
JavaScript::put(['nests' => $nests->keyBy('id')]);
|
||||
|
||||
return view('admin.eggs.new', ['nests' => $nests]);
|
||||
return $this->view->make('admin.eggs.new', ['nests' => $nests]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,7 +67,7 @@ class EggController extends Controller
|
||||
*/
|
||||
public function view(Egg $egg): View
|
||||
{
|
||||
return view('admin.eggs.view', [
|
||||
return $this->view->make('admin.eggs.view', [
|
||||
'egg' => $egg,
|
||||
'images' => array_map(
|
||||
fn ($key, $value) => $key === $value ? $value : "$key|$value",
|
||||
@ -111,7 +112,7 @@ class EggController extends Controller
|
||||
/**
|
||||
* Normalizes a string of docker image data into the expected egg format.
|
||||
*/
|
||||
protected function normalizeDockerImages(?string $input = null): array
|
||||
protected function normalizeDockerImages(string $input = null): array
|
||||
{
|
||||
$data = array_map(fn ($value) => trim($value), explode("\n", $input ?? ''));
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ class EggScriptController extends Controller
|
||||
protected AlertsMessageBag $alert,
|
||||
protected EggRepositoryInterface $repository,
|
||||
protected InstallScriptService $installScriptService,
|
||||
protected ViewFactory $view,
|
||||
protected ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ class EggScriptController extends Controller
|
||||
['copy_script_from', '=', $egg->id],
|
||||
]);
|
||||
|
||||
return view('admin.eggs.scripts', [
|
||||
return $this->view->make('admin.eggs.scripts', [
|
||||
'copyFromOptions' => $copy,
|
||||
'relyOnScript' => $rely,
|
||||
'egg' => $egg,
|
||||
|
||||
@ -21,7 +21,7 @@ class EggShareController extends Controller
|
||||
protected AlertsMessageBag $alert,
|
||||
protected EggExporterService $exporterService,
|
||||
protected EggImporterService $importerService,
|
||||
protected EggUpdateImporterService $updateImporterService,
|
||||
protected EggUpdateImporterService $updateImporterService
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ class EggVariableController extends Controller
|
||||
protected VariableUpdateService $updateService,
|
||||
protected EggRepositoryInterface $repository,
|
||||
protected EggVariableRepositoryInterface $variableRepository,
|
||||
protected ViewFactory $view,
|
||||
protected ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ class EggVariableController extends Controller
|
||||
{
|
||||
$egg = $this->repository->getWithVariables($egg);
|
||||
|
||||
return view('admin.eggs.variables', ['egg' => $egg]);
|
||||
return $this->view->make('admin.eggs.variables', ['egg' => $egg]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,7 +69,7 @@ class EggVariableController extends Controller
|
||||
{
|
||||
$this->updateService->handle($variable, $request->normalize());
|
||||
$this->alert->success(trans('admin/nests.variables.notices.variable_updated', [
|
||||
'variable' => htmlspecialchars($variable->name),
|
||||
'variable' => $variable->name,
|
||||
]))->flash();
|
||||
|
||||
return redirect()->route('admin.nests.egg.variables', $egg->id);
|
||||
@ -82,7 +82,7 @@ class EggVariableController extends Controller
|
||||
{
|
||||
$this->variableRepository->delete($variable->id);
|
||||
$this->alert->success(trans('admin/nests.variables.notices.variable_deleted', [
|
||||
'variable' => htmlspecialchars($variable->name),
|
||||
'variable' => $variable->name,
|
||||
]))->flash();
|
||||
|
||||
return redirect()->route('admin.nests.egg.variables', $egg);
|
||||
|
||||
@ -24,7 +24,7 @@ class NestController extends Controller
|
||||
protected NestDeletionService $nestDeletionService,
|
||||
protected NestRepositoryInterface $repository,
|
||||
protected NestUpdateService $nestUpdateService,
|
||||
protected ViewFactory $view,
|
||||
protected ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ class NestController extends Controller
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.nests.index', [
|
||||
return $this->view->make('admin.nests.index', [
|
||||
'nests' => $this->repository->getWithCounts(),
|
||||
]);
|
||||
}
|
||||
@ -45,7 +45,7 @@ class NestController extends Controller
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('admin.nests.new');
|
||||
return $this->view->make('admin.nests.new');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,7 +56,7 @@ class NestController extends Controller
|
||||
public function store(StoreNestFormRequest $request): RedirectResponse
|
||||
{
|
||||
$nest = $this->nestCreationService->handle($request->normalize());
|
||||
$this->alert->success(trans('admin/nests.notices.created', ['name' => htmlspecialchars($nest->name)]))->flash();
|
||||
$this->alert->success(trans('admin/nests.notices.created', ['name' => $nest->name]))->flash();
|
||||
|
||||
return redirect()->route('admin.nests.view', $nest->id);
|
||||
}
|
||||
@ -68,7 +68,7 @@ class NestController extends Controller
|
||||
*/
|
||||
public function view(int $nest): View
|
||||
{
|
||||
return view('admin.nests.view', [
|
||||
return $this->view->make('admin.nests.view', [
|
||||
'nest' => $this->repository->getWithEggServers($nest),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ class NodeAutoDeployController extends Controller
|
||||
public function __construct(
|
||||
private ApiKeyRepository $repository,
|
||||
private Encrypter $encrypter,
|
||||
private KeyCreationService $keyCreationService,
|
||||
private KeyCreationService $keyCreationService
|
||||
) {
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ class NodeAutoDeployController extends Controller
|
||||
*/
|
||||
public function __invoke(Request $request, Node $node): JsonResponse
|
||||
{
|
||||
/** @var ApiKey|null $key */
|
||||
/** @var \Pterodactyl\Models\ApiKey|null $key */
|
||||
$key = $this->repository->getApplicationKeys($request->user())
|
||||
->filter(function (ApiKey $key) {
|
||||
foreach ($key->getAttributes() as $permission => $value) {
|
||||
|
||||
@ -7,9 +7,17 @@ use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Spatie\QueryBuilder\QueryBuilder;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\View\Factory as ViewFactory;
|
||||
|
||||
class NodeController extends Controller
|
||||
{
|
||||
/**
|
||||
* NodeController constructor.
|
||||
*/
|
||||
public function __construct(private ViewFactory $view)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a listing of nodes on the system.
|
||||
*/
|
||||
@ -22,6 +30,6 @@ class NodeController extends Controller
|
||||
->allowedSorts(['id'])
|
||||
->paginate(25);
|
||||
|
||||
return view('admin.nodes.index', ['nodes' => $nodes]);
|
||||
return $this->view->make('admin.nodes.index', ['nodes' => $nodes]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,11 +8,13 @@ use Pterodactyl\Models\Node;
|
||||
use Illuminate\Support\Collection;
|
||||
use Pterodactyl\Models\Allocation;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\View\Factory as ViewFactory;
|
||||
use Pterodactyl\Repositories\Eloquent\NodeRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Traits\Controllers\JavascriptInjection;
|
||||
use Pterodactyl\Services\Helpers\SoftwareVersionService;
|
||||
use Pterodactyl\Repositories\Eloquent\LocationRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\AllocationRepository;
|
||||
|
||||
class NodeViewController extends Controller
|
||||
{
|
||||
@ -22,10 +24,12 @@ class NodeViewController extends Controller
|
||||
* NodeViewController constructor.
|
||||
*/
|
||||
public function __construct(
|
||||
private AllocationRepository $allocationRepository,
|
||||
private LocationRepository $locationRepository,
|
||||
private NodeRepository $repository,
|
||||
private ServerRepository $serverRepository,
|
||||
private SoftwareVersionService $versionService,
|
||||
private ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -36,7 +40,7 @@ class NodeViewController extends Controller
|
||||
{
|
||||
$node = $this->repository->loadLocationAndServerCount($node);
|
||||
|
||||
return view('admin.nodes.view.index', [
|
||||
return $this->view->make('admin.nodes.view.index', [
|
||||
'node' => $node,
|
||||
'stats' => $this->repository->getUsageStats($node),
|
||||
'version' => $this->versionService,
|
||||
@ -48,7 +52,7 @@ class NodeViewController extends Controller
|
||||
*/
|
||||
public function settings(Request $request, Node $node): View
|
||||
{
|
||||
return view('admin.nodes.view.settings', [
|
||||
return $this->view->make('admin.nodes.view.settings', [
|
||||
'node' => $node,
|
||||
'locations' => $this->locationRepository->all(),
|
||||
]);
|
||||
@ -59,7 +63,7 @@ class NodeViewController extends Controller
|
||||
*/
|
||||
public function configuration(Request $request, Node $node): View
|
||||
{
|
||||
return view('admin.nodes.view.configuration', compact('node'));
|
||||
return $this->view->make('admin.nodes.view.configuration', compact('node'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,9 +73,9 @@ class NodeViewController extends Controller
|
||||
{
|
||||
$node = $this->repository->loadNodeAllocations($node);
|
||||
|
||||
$this->plainInject(['node' => Collection::make([$node])->only(['id'])]);
|
||||
$this->plainInject(['node' => Collection::wrap($node)->only(['id'])]);
|
||||
|
||||
return view('admin.nodes.view.allocation', [
|
||||
return $this->view->make('admin.nodes.view.allocation', [
|
||||
'node' => $node,
|
||||
'allocations' => Allocation::query()->where('node_id', $node->id)
|
||||
->groupBy('ip')
|
||||
@ -86,11 +90,11 @@ class NodeViewController extends Controller
|
||||
public function servers(Request $request, Node $node): View
|
||||
{
|
||||
$this->plainInject([
|
||||
'node' => Collection::make([$node->makeVisible(['daemon_token_id', 'daemon_token'])])
|
||||
'node' => Collection::wrap($node->makeVisible(['daemon_token_id', 'daemon_token']))
|
||||
->only(['scheme', 'fqdn', 'daemonListen', 'daemon_token_id', 'daemon_token']),
|
||||
]);
|
||||
|
||||
return view('admin.nodes.view.servers', [
|
||||
return $this->view->make('admin.nodes.view.servers', [
|
||||
'node' => $node,
|
||||
'servers' => $this->serverRepository->loadAllServersForNode($node->id, 25),
|
||||
]);
|
||||
|
||||
@ -44,7 +44,7 @@ class NodesController extends Controller
|
||||
protected ServerRepositoryInterface $serverRepository,
|
||||
protected NodeUpdateService $updateService,
|
||||
protected SoftwareVersionService $versionService,
|
||||
protected ViewFactory $view,
|
||||
protected ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ class NodesController extends Controller
|
||||
return redirect()->route('admin.locations');
|
||||
}
|
||||
|
||||
return view('admin.nodes.new', ['locations' => $locations]);
|
||||
return $this->view->make('admin.nodes.new', ['locations' => $locations]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,7 +131,7 @@ class NodesController extends Controller
|
||||
['ip', '=', $request->input('ip')],
|
||||
]);
|
||||
|
||||
$this->alert->success(trans('admin/node.notices.unallocated_deleted', ['ip' => htmlspecialchars($request->input('ip'))]))
|
||||
$this->alert->success(trans('admin/node.notices.unallocated_deleted', ['ip' => $request->input('ip')]))
|
||||
->flash();
|
||||
|
||||
return redirect()->route('admin.nodes.view.allocation', $node);
|
||||
|
||||
@ -2,12 +2,13 @@
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Servers;
|
||||
|
||||
use JavaScript;
|
||||
use Illuminate\View\View;
|
||||
use Pterodactyl\Models\Nest;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Pterodactyl\Models\Location;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Illuminate\View\Factory as ViewFactory;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Repositories\Eloquent\NestRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\NodeRepository;
|
||||
@ -24,6 +25,7 @@ class CreateServerController extends Controller
|
||||
private NestRepository $nestRepository,
|
||||
private NodeRepository $nodeRepository,
|
||||
private ServerCreationService $creationService,
|
||||
private ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -43,16 +45,16 @@ class CreateServerController extends Controller
|
||||
|
||||
$nests = $this->nestRepository->getWithEggs();
|
||||
|
||||
\JavaScript::put([
|
||||
JavaScript::put([
|
||||
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
|
||||
'nests' => $nests->map(function (Nest $item) {
|
||||
'nests' => $nests->map(function ($item) {
|
||||
return array_merge($item->toArray(), [
|
||||
'eggs' => $item->eggs->keyBy('id')->toArray(),
|
||||
]);
|
||||
})->keyBy('id'),
|
||||
]);
|
||||
|
||||
return view('admin.servers.new', [
|
||||
return $this->view->make('admin.servers.new', [
|
||||
'locations' => Location::all(),
|
||||
'nests' => $nests,
|
||||
]);
|
||||
|
||||
@ -9,9 +9,17 @@ use Spatie\QueryBuilder\QueryBuilder;
|
||||
use Spatie\QueryBuilder\AllowedFilter;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Models\Filters\AdminServerFilter;
|
||||
use Illuminate\Contracts\View\Factory as ViewFactory;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
/**
|
||||
* ServerController constructor.
|
||||
*/
|
||||
public function __construct(private ViewFactory $view)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the servers that exist on the system using a paginated result set. If
|
||||
* a query is passed along in the request it is also passed to the repository function.
|
||||
@ -25,6 +33,6 @@ class ServerController extends Controller
|
||||
])
|
||||
->paginate(config()->get('pterodactyl.paginate.admin.servers'));
|
||||
|
||||
return view('admin.servers.index', ['servers' => $servers]);
|
||||
return $this->view->make('admin.servers.index', ['servers' => $servers]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ class ServerTransferController extends Controller
|
||||
private ConnectionInterface $connection,
|
||||
private DaemonTransferRepository $daemonTransferRepository,
|
||||
private NodeJWTService $nodeJWTService,
|
||||
private NodeRepository $nodeRepository,
|
||||
private NodeRepository $nodeRepository
|
||||
) {
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ class ServerTransferController extends Controller
|
||||
$transfer->new_node = $node_id;
|
||||
$transfer->old_allocation = $server->allocation_id;
|
||||
$transfer->new_allocation = $allocation_id;
|
||||
$transfer->old_additional_allocations = $server->allocations->where('id', '!=', $server->allocation_id)->pluck('id')->values()->toArray();
|
||||
$transfer->old_additional_allocations = $server->allocations->where('id', '!=', $server->allocation_id)->pluck('id');
|
||||
$transfer->new_additional_allocations = $additional_allocations;
|
||||
|
||||
$transfer->save();
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Servers;
|
||||
|
||||
use JavaScript;
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Nest;
|
||||
@ -9,9 +10,11 @@ use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Services\Servers\EnvironmentService;
|
||||
use Illuminate\Contracts\View\Factory as ViewFactory;
|
||||
use Pterodactyl\Repositories\Eloquent\NestRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\NodeRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\MountRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Traits\Controllers\JavascriptInjection;
|
||||
use Pterodactyl\Repositories\Eloquent\LocationRepository;
|
||||
use Pterodactyl\Repositories\Eloquent\DatabaseHostRepository;
|
||||
@ -29,7 +32,9 @@ class ServerViewController extends Controller
|
||||
private MountRepository $mountRepository,
|
||||
private NestRepository $nestRepository,
|
||||
private NodeRepository $nodeRepository,
|
||||
private ServerRepository $repository,
|
||||
private EnvironmentService $environmentService,
|
||||
private ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -38,7 +43,7 @@ class ServerViewController extends Controller
|
||||
*/
|
||||
public function index(Request $request, Server $server): View
|
||||
{
|
||||
return view('admin.servers.view.index', compact('server'));
|
||||
return $this->view->make('admin.servers.view.index', compact('server'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,7 +51,7 @@ class ServerViewController extends Controller
|
||||
*/
|
||||
public function details(Request $request, Server $server): View
|
||||
{
|
||||
return view('admin.servers.view.details', compact('server'));
|
||||
return $this->view->make('admin.servers.view.details', compact('server'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,7 +61,7 @@ class ServerViewController extends Controller
|
||||
{
|
||||
$allocations = $server->node->allocations->toBase();
|
||||
|
||||
return view('admin.servers.view.build', [
|
||||
return $this->view->make('admin.servers.view.build', [
|
||||
'server' => $server,
|
||||
'assigned' => $allocations->where('server_id', $server->id)->sortBy('port')->sortBy('ip'),
|
||||
'unassigned' => $allocations->where('server_id', null)->sortBy('port')->sortBy('ip'),
|
||||
@ -83,7 +88,7 @@ class ServerViewController extends Controller
|
||||
})->keyBy('id'),
|
||||
]);
|
||||
|
||||
return view('admin.servers.view.startup', compact('server', 'nests'));
|
||||
return $this->view->make('admin.servers.view.startup', compact('server', 'nests'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,7 +96,7 @@ class ServerViewController extends Controller
|
||||
*/
|
||||
public function database(Request $request, Server $server): View
|
||||
{
|
||||
return view('admin.servers.view.database', [
|
||||
return $this->view->make('admin.servers.view.database', [
|
||||
'hosts' => $this->databaseHostRepository->all(),
|
||||
'server' => $server,
|
||||
]);
|
||||
@ -104,7 +109,7 @@ class ServerViewController extends Controller
|
||||
{
|
||||
$server->load('mounts');
|
||||
|
||||
return view('admin.servers.view.mounts', [
|
||||
return $this->view->make('admin.servers.view.mounts', [
|
||||
'mounts' => $this->mountRepository->getMountListForServer($server),
|
||||
'server' => $server,
|
||||
]);
|
||||
@ -114,7 +119,7 @@ class ServerViewController extends Controller
|
||||
* Returns the base server management page, or an exception if the server
|
||||
* is in a state that cannot be recovered from.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function manage(Request $request, Server $server): View
|
||||
{
|
||||
@ -129,11 +134,11 @@ class ServerViewController extends Controller
|
||||
$canTransfer = true;
|
||||
}
|
||||
|
||||
\JavaScript::put([
|
||||
JavaScript::put([
|
||||
'nodeData' => $this->nodeRepository->getNodesForServerCreation(),
|
||||
]);
|
||||
|
||||
return view('admin.servers.view.manage', [
|
||||
return $this->view->make('admin.servers.view.manage', [
|
||||
'server' => $server,
|
||||
'locations' => $this->locationRepository->all(),
|
||||
'canTransfer' => $canTransfer,
|
||||
@ -145,6 +150,6 @@ class ServerViewController extends Controller
|
||||
*/
|
||||
public function delete(Request $request, Server $server): View
|
||||
{
|
||||
return view('admin.servers.view.delete', compact('server'));
|
||||
return $this->view->make('admin.servers.view.delete', compact('server'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,14 +57,14 @@ class ServersController extends Controller
|
||||
protected NestRepositoryInterface $nestRepository,
|
||||
protected ServerConfigurationStructureService $serverConfigurationStructureService,
|
||||
protected StartupModificationService $startupModificationService,
|
||||
protected SuspensionService $suspensionService,
|
||||
protected SuspensionService $suspensionService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the details for a server.
|
||||
*
|
||||
* @throws DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function setDetails(Request $request, Server $server): RedirectResponse
|
||||
@ -81,8 +81,8 @@ class ServersController extends Controller
|
||||
/**
|
||||
* Toggles the installation status for a server.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function toggleInstall(Server $server): RedirectResponse
|
||||
@ -103,8 +103,8 @@ class ServersController extends Controller
|
||||
/**
|
||||
* Reinstalls the server with the currently assigned service.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function reinstallServer(Server $server): RedirectResponse
|
||||
@ -118,8 +118,8 @@ class ServersController extends Controller
|
||||
/**
|
||||
* Manage the suspension status for a server.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function manageSuspension(Request $request, Server $server): RedirectResponse
|
||||
@ -135,9 +135,9 @@ class ServersController extends Controller
|
||||
/**
|
||||
* Update the build configuration for a server.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws ValidationException
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function updateBuild(Request $request, Server $server): RedirectResponse
|
||||
{
|
||||
@ -159,7 +159,7 @@ class ServersController extends Controller
|
||||
/**
|
||||
* Start the server deletion process.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function delete(Request $request, Server $server): RedirectResponse
|
||||
@ -173,7 +173,7 @@ class ServersController extends Controller
|
||||
/**
|
||||
* Update the startup command as well as variables.
|
||||
*
|
||||
* @throws ValidationException
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function saveStartup(Request $request, Server $server): RedirectResponse
|
||||
{
|
||||
@ -220,7 +220,7 @@ class ServersController extends Controller
|
||||
*/
|
||||
public function resetDatabasePassword(Request $request, Server $server): Response
|
||||
{
|
||||
/** @var Database $database */
|
||||
/** @var \Pterodactyl\Models\Database $database */
|
||||
$database = $server->databases()->findOrFail($request->input('database'));
|
||||
|
||||
$this->databasePasswordService->handle($database);
|
||||
|
||||
@ -6,6 +6,7 @@ use Illuminate\View\View;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Illuminate\View\Factory as ViewFactory;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
use Pterodactyl\Contracts\Repository\SettingsRepositoryInterface;
|
||||
@ -21,6 +22,7 @@ class AdvancedController extends Controller
|
||||
private ConfigRepository $config,
|
||||
private Kernel $kernel,
|
||||
private SettingsRepositoryInterface $settings,
|
||||
private ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -37,7 +39,7 @@ class AdvancedController extends Controller
|
||||
$showRecaptchaWarning = true;
|
||||
}
|
||||
|
||||
return view('admin.settings.advanced', [
|
||||
return $this->view->make('admin.settings.advanced', [
|
||||
'showRecaptchaWarning' => $showRecaptchaWarning,
|
||||
]);
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ use Illuminate\View\View;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Illuminate\View\Factory as ViewFactory;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
use Pterodactyl\Traits\Helpers\AvailableLanguages;
|
||||
use Pterodactyl\Services\Helpers\SoftwareVersionService;
|
||||
@ -24,6 +25,7 @@ class IndexController extends Controller
|
||||
private Kernel $kernel,
|
||||
private SettingsRepositoryInterface $settings,
|
||||
private SoftwareVersionService $versionService,
|
||||
private ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -32,7 +34,7 @@ class IndexController extends Controller
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.settings.index', [
|
||||
return $this->view->make('admin.settings.index', [
|
||||
'version' => $this->versionService,
|
||||
'languages' => $this->getAvailableLanguages(true),
|
||||
]);
|
||||
|
||||
@ -2,11 +2,13 @@
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Admin\Settings;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\View\View;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Pterodactyl\Notifications\MailTested;
|
||||
use Illuminate\View\Factory as ViewFactory;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Http\Controllers\Controller;
|
||||
@ -26,6 +28,7 @@ class MailController extends Controller
|
||||
private Encrypter $encrypter,
|
||||
private Kernel $kernel,
|
||||
private SettingsRepositoryInterface $settings,
|
||||
private ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -35,7 +38,7 @@ class MailController extends Controller
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin.settings.mail', [
|
||||
return $this->view->make('admin.settings.mail', [
|
||||
'disabled' => $this->config->get('mail.default') !== 'smtp',
|
||||
]);
|
||||
}
|
||||
@ -79,7 +82,7 @@ class MailController extends Controller
|
||||
try {
|
||||
Notification::route('mail', $request->user()->email)
|
||||
->notify(new MailTested($request->user()));
|
||||
} catch (\Exception $exception) {
|
||||
} catch (Exception $exception) {
|
||||
return response($exception->getMessage(), 500);
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ class UserController extends Controller
|
||||
protected Translator $translator,
|
||||
protected UserUpdateService $updateService,
|
||||
protected UserRepositoryInterface $repository,
|
||||
protected ViewFactory $view,
|
||||
protected ViewFactory $view
|
||||
) {
|
||||
}
|
||||
|
||||
@ -54,11 +54,10 @@ class UserController extends Controller
|
||||
->groupBy('users.id')
|
||||
)
|
||||
->allowedFilters(['username', 'email', 'uuid'])
|
||||
->defaultSort('-root_admin')
|
||||
->allowedSorts(['id', 'uuid'])
|
||||
->paginate(50);
|
||||
|
||||
return view('admin.users.index', ['users' => $users]);
|
||||
return $this->view->make('admin.users.index', ['users' => $users]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,7 +65,7 @@ class UserController extends Controller
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('admin.users.new', [
|
||||
return $this->view->make('admin.users.new', [
|
||||
'languages' => $this->getAvailableLanguages(true),
|
||||
]);
|
||||
}
|
||||
@ -76,7 +75,7 @@ class UserController extends Controller
|
||||
*/
|
||||
public function view(User $user): View
|
||||
{
|
||||
return view('admin.users.view', [
|
||||
return $this->view->make('admin.users.view', [
|
||||
'user' => $user,
|
||||
'languages' => $this->getAvailableLanguages(true),
|
||||
]);
|
||||
@ -86,12 +85,12 @@ class UserController extends Controller
|
||||
* Delete a user from the system.
|
||||
*
|
||||
* @throws \Exception
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function delete(Request $request, User $user): RedirectResponse
|
||||
{
|
||||
if ($request->user()->is($user)) {
|
||||
throw new DisplayException(__('admin/user.exceptions.delete_self'));
|
||||
if ($request->user()->id === $user->id) {
|
||||
throw new DisplayException($this->translator->get('admin/user.exceptions.user_has_servers'));
|
||||
}
|
||||
|
||||
$this->deletionService->handle($user);
|
||||
@ -140,14 +139,12 @@ class UserController extends Controller
|
||||
// Handle single user requests.
|
||||
if ($request->query('user_id')) {
|
||||
$user = User::query()->findOrFail($request->input('user_id'));
|
||||
// @phpstan-ignore-next-line property.notFound
|
||||
$user->md5 = md5(strtolower($user->email));
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
return $users->map(function ($item) {
|
||||
// @phpstan-ignore-next-line property.notFound
|
||||
$item->md5 = md5(strtolower($item->email));
|
||||
|
||||
return $item;
|
||||
|
||||
@ -59,7 +59,7 @@ abstract class ApplicationApiController extends Controller
|
||||
*/
|
||||
public function getTransformer(string $abstract)
|
||||
{
|
||||
Assert::subclassOf($abstract, BaseTransformer::class); // @phpstan-ignore staticMethod.alreadyNarrowedType
|
||||
Assert::subclassOf($abstract, BaseTransformer::class);
|
||||
|
||||
return $abstract::fromRequest($this->request);
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ class LocationController extends ApplicationApiController
|
||||
public function __construct(
|
||||
private LocationCreationService $creationService,
|
||||
private LocationDeletionService $deletionService,
|
||||
private LocationUpdateService $updateService,
|
||||
private LocationUpdateService $updateService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ class AllocationController extends ApplicationApiController
|
||||
*/
|
||||
public function __construct(
|
||||
private AssignmentService $assignmentService,
|
||||
private AllocationDeletionService $deletionService,
|
||||
private AllocationDeletionService $deletionService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ class NodeController extends ApplicationApiController
|
||||
public function __construct(
|
||||
private NodeCreationService $creationService,
|
||||
private NodeDeletionService $deletionService,
|
||||
private NodeUpdateService $updateService,
|
||||
private NodeUpdateService $updateService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ class DatabaseController extends ApplicationApiController
|
||||
*/
|
||||
public function __construct(
|
||||
private DatabaseManagementService $databaseManagementService,
|
||||
private DatabasePasswordService $databasePasswordService,
|
||||
private DatabasePasswordService $databasePasswordService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ class ServerController extends ApplicationApiController
|
||||
*/
|
||||
public function __construct(
|
||||
private ServerCreationService $creationService,
|
||||
private ServerDeletionService $deletionService,
|
||||
private ServerDeletionService $deletionService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ class ServerDetailsController extends ApplicationApiController
|
||||
*/
|
||||
public function __construct(
|
||||
private BuildModificationService $buildModificationService,
|
||||
private DetailsModificationService $detailsModificationService,
|
||||
private DetailsModificationService $detailsModificationService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ class ServerManagementController extends ApplicationApiController
|
||||
*/
|
||||
public function __construct(
|
||||
private ReinstallServerService $reinstallServerService,
|
||||
private SuspensionService $suspensionService,
|
||||
private SuspensionService $suspensionService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ class UserController extends ApplicationApiController
|
||||
public function __construct(
|
||||
private UserCreationService $creationService,
|
||||
private UserDeletionService $deletionService,
|
||||
private UserUpdateService $updateService,
|
||||
private UserUpdateService $updateService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ class AccountController extends ClientApiController
|
||||
$guard->setUser($user);
|
||||
|
||||
// This method doesn't exist in the stateless Sanctum world.
|
||||
if (method_exists($guard, 'logoutOtherDevices')) { // @phpstan-ignore function.alreadyNarrowedType
|
||||
if (method_exists($guard, 'logoutOtherDevices')) {
|
||||
$guard->logoutOtherDevices($request->input('password'));
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ class ApiKeyController extends ClientApiController
|
||||
/**
|
||||
* Store a new API key for a user's account.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function store(StoreApiKeyRequest $request): array
|
||||
{
|
||||
@ -54,7 +54,7 @@ class ApiKeyController extends ClientApiController
|
||||
*/
|
||||
public function delete(ClientApiRequest $request, string $identifier): JsonResponse
|
||||
{
|
||||
/** @var ApiKey $key */
|
||||
/** @var \Pterodactyl\Models\ApiKey $key */
|
||||
$key = $request->user()->apiKeys()
|
||||
->where('key_type', ApiKey::TYPE_ACCOUNT)
|
||||
->where('identifier', $identifier)
|
||||
|
||||
@ -49,7 +49,7 @@ abstract class ClientApiController extends ApplicationApiController
|
||||
*/
|
||||
public function getTransformer(string $abstract)
|
||||
{
|
||||
Assert::subclassOf($abstract, BaseClientTransformer::class); // @phpstan-ignore staticMethod.alreadyNarrowedType
|
||||
Assert::subclassOf($abstract, BaseClientTransformer::class);
|
||||
|
||||
return $abstract::fromRequest($this->request);
|
||||
}
|
||||
|
||||
@ -18,7 +18,6 @@ use Pterodactyl\Transformers\Api\Client\BackupTransformer;
|
||||
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\StoreBackupRequest;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\RestoreBackupRequest;
|
||||
|
||||
class BackupController extends ClientApiController
|
||||
{
|
||||
@ -30,7 +29,7 @@ class BackupController extends ClientApiController
|
||||
private DeleteBackupService $deleteBackupService,
|
||||
private InitiateBackupService $initiateBackupService,
|
||||
private DownloadLinkService $downloadLinkService,
|
||||
private BackupRepository $repository,
|
||||
private BackupRepository $repository
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
@ -39,7 +38,7 @@ class BackupController extends ClientApiController
|
||||
* Returns all the backups for a given server instance in a paginated
|
||||
* result set.
|
||||
*
|
||||
* @throws AuthorizationException
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function index(Request $request, Server $server): array
|
||||
{
|
||||
@ -74,21 +73,15 @@ class BackupController extends ClientApiController
|
||||
// how best to allow a user to create a backup that is locked without also preventing
|
||||
// them from just filling up a server with backups that can never be deleted?
|
||||
if ($request->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) {
|
||||
$action->setIsLocked($request->boolean('is_locked'));
|
||||
$action->setIsLocked((bool) $request->input('is_locked'));
|
||||
}
|
||||
|
||||
$backup = Activity::event('server:backup.start')->transaction(function ($log) use ($action, $server, $request) {
|
||||
$server->backups()->lockForUpdate();
|
||||
$backup = $action->handle($server, $request->input('name'));
|
||||
|
||||
$backup = $action->handle($server, $request->input('name'));
|
||||
|
||||
$log->subject($backup)->property([
|
||||
'name' => $backup->name,
|
||||
'locked' => $request->boolean('is_locked'),
|
||||
]);
|
||||
|
||||
return $backup;
|
||||
});
|
||||
Activity::event('server:backup.start')
|
||||
->subject($backup)
|
||||
->property(['name' => $backup->name, 'locked' => (bool) $request->input('is_locked')])
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($backup)
|
||||
->transformWith($this->getTransformer(BackupTransformer::class))
|
||||
@ -99,7 +92,7 @@ class BackupController extends ClientApiController
|
||||
* Toggles the lock status of a given backup for a server.
|
||||
*
|
||||
* @throws \Throwable
|
||||
* @throws AuthorizationException
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function toggleLock(Request $request, Server $server, Backup $backup): array
|
||||
{
|
||||
@ -121,7 +114,7 @@ class BackupController extends ClientApiController
|
||||
/**
|
||||
* Returns information about a single backup.
|
||||
*
|
||||
* @throws AuthorizationException
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function view(Request $request, Server $server, Backup $backup): array
|
||||
{
|
||||
@ -162,7 +155,7 @@ class BackupController extends ClientApiController
|
||||
* which the user is redirected to.
|
||||
*
|
||||
* @throws \Throwable
|
||||
* @throws AuthorizationException
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function download(Request $request, Server $server, Backup $backup): JsonResponse
|
||||
{
|
||||
@ -195,8 +188,12 @@ class BackupController extends ClientApiController
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function restore(RestoreBackupRequest $request, Server $server, Backup $backup): JsonResponse
|
||||
public function restore(Request $request, Server $server, Backup $backup): JsonResponse
|
||||
{
|
||||
if (!$request->user()->can(Permission::ACTION_BACKUP_RESTORE, $server)) {
|
||||
throw new AuthorizationException();
|
||||
}
|
||||
|
||||
// Cannot restore a backup unless a server is fully installed and not currently
|
||||
// processing a different backup restoration request.
|
||||
if (!is_null($server->status)) {
|
||||
|
||||
@ -5,6 +5,7 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
||||
use Illuminate\Http\Response;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Facades\Activity;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use GuzzleHttp\Exception\BadResponseException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Pterodactyl\Repositories\Wings\DaemonCommandRepository;
|
||||
@ -25,7 +26,7 @@ class CommandController extends ClientApiController
|
||||
/**
|
||||
* Send a command to a running server.
|
||||
*
|
||||
* @throws DaemonConnectionException
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function index(SendCommandRequest $request, Server $server): Response
|
||||
{
|
||||
@ -35,7 +36,10 @@ class CommandController extends ClientApiController
|
||||
$previous = $exception->getPrevious();
|
||||
|
||||
if ($previous instanceof BadResponseException) {
|
||||
if ($previous->getResponse()->getStatusCode() === Response::HTTP_BAD_GATEWAY) {
|
||||
if (
|
||||
$previous->getResponse() instanceof ResponseInterface
|
||||
&& $previous->getResponse()->getStatusCode() === Response::HTTP_BAD_GATEWAY
|
||||
) {
|
||||
throw new HttpException(Response::HTTP_BAD_GATEWAY, 'Server must be online in order to send commands.', $exception);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ class DatabaseController extends ClientApiController
|
||||
public function __construct(
|
||||
private DeployServerDatabaseService $deployDatabaseService,
|
||||
private DatabaseManagementService $managementService,
|
||||
private DatabasePasswordService $passwordService,
|
||||
private DatabasePasswordService $passwordService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
@ -48,15 +48,12 @@ class DatabaseController extends ClientApiController
|
||||
*/
|
||||
public function store(StoreDatabaseRequest $request, Server $server): array
|
||||
{
|
||||
$database = Activity::event('server:database.create')->transaction(function ($log) use ($request, $server) {
|
||||
$server->databases()->lockForUpdate();
|
||||
$database = $this->deployDatabaseService->handle($server, $request->validated());
|
||||
|
||||
$database = $this->deployDatabaseService->handle($server, $request->validated());
|
||||
|
||||
$log->subject($database)->property('name', $database->database);
|
||||
|
||||
return $database;
|
||||
});
|
||||
Activity::event('server:database.create')
|
||||
->subject($database)
|
||||
->property('name', $database->database)
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($database)
|
||||
->parseIncludes(['password'])
|
||||
@ -72,16 +69,15 @@ class DatabaseController extends ClientApiController
|
||||
*/
|
||||
public function rotatePassword(RotatePasswordRequest $request, Server $server, Database $database): array
|
||||
{
|
||||
$this->passwordService->handle($database);
|
||||
$database->refresh();
|
||||
|
||||
Activity::event('server:database.rotate-password')
|
||||
->subject($database)
|
||||
->property('name', $database->database)
|
||||
->transaction(function () use ($database) {
|
||||
$database->lockForUpdate();
|
||||
->log();
|
||||
|
||||
$this->passwordService->handle($database);
|
||||
});
|
||||
|
||||
return $this->fractal->item($database->refresh())
|
||||
return $this->fractal->item($database)
|
||||
->parseIncludes(['password'])
|
||||
->transformWith($this->getTransformer(DatabaseTransformer::class))
|
||||
->toArray();
|
||||
|
||||
@ -30,7 +30,7 @@ class FileController extends ClientApiController
|
||||
*/
|
||||
public function __construct(
|
||||
private NodeJWTService $jwtService,
|
||||
private DaemonFileRepository $fileRepository,
|
||||
private DaemonFileRepository $fileRepository
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ class FileUploadController extends ClientApiController
|
||||
* FileUploadController constructor.
|
||||
*/
|
||||
public function __construct(
|
||||
private NodeJWTService $jwtService,
|
||||
private NodeJWTService $jwtService
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ use Pterodactyl\Models\Server;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Pterodactyl\Facades\Activity;
|
||||
use Pterodactyl\Models\Allocation;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Repositories\Eloquent\ServerRepository;
|
||||
use Pterodactyl\Transformers\Api\Client\AllocationTransformer;
|
||||
@ -24,9 +23,8 @@ class NetworkAllocationController extends ClientApiController
|
||||
* NetworkAllocationController constructor.
|
||||
*/
|
||||
public function __construct(
|
||||
protected readonly ConnectionInterface $connection,
|
||||
private FindAssignableAllocationService $assignableAllocationService,
|
||||
private ServerRepository $serverRepository,
|
||||
private ServerRepository $serverRepository
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
@ -90,21 +88,20 @@ class NetworkAllocationController extends ClientApiController
|
||||
* Set the notes for the allocation for a server.
|
||||
*s.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function store(NewAllocationRequest $request, Server $server): array
|
||||
{
|
||||
$allocation = Activity::event('server:allocation.create')->transaction(function ($log) use ($server) {
|
||||
if ($server->allocations()->lockForUpdate()->count() >= $server->allocation_limit) {
|
||||
throw new DisplayException('Cannot assign additional allocations to this server: limit has been reached.');
|
||||
}
|
||||
if ($server->allocations()->count() >= $server->allocation_limit) {
|
||||
throw new DisplayException('Cannot assign additional allocations to this server: limit has been reached.');
|
||||
}
|
||||
|
||||
$allocation = $this->assignableAllocationService->handle($server);
|
||||
$allocation = $this->assignableAllocationService->handle($server);
|
||||
|
||||
$log->subject($allocation)->property('allocation', $allocation->toString());
|
||||
|
||||
return $allocation;
|
||||
});
|
||||
Activity::event('server:allocation.create')
|
||||
->subject($allocation)
|
||||
->property('allocation', $allocation->toString())
|
||||
->log();
|
||||
|
||||
return $this->fractal->item($allocation)
|
||||
->transformWith($this->getTransformer(AllocationTransformer::class))
|
||||
@ -114,7 +111,7 @@ class NetworkAllocationController extends ClientApiController
|
||||
/**
|
||||
* Delete an allocation from a server.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function delete(DeleteAllocationRequest $request, Server $server, Allocation $allocation): JsonResponse
|
||||
{
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
|
||||
|
||||
use Exception;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
@ -47,12 +48,12 @@ class ScheduleController extends ClientApiController
|
||||
/**
|
||||
* Store a new schedule for a server.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function store(StoreScheduleRequest $request, Server $server): array
|
||||
{
|
||||
/** @var Schedule $model */
|
||||
/** @var \Pterodactyl\Models\Schedule $model */
|
||||
$model = $this->repository->create([
|
||||
'server_id' => $server->id,
|
||||
'name' => $request->input('name'),
|
||||
@ -95,7 +96,7 @@ class ScheduleController extends ClientApiController
|
||||
/**
|
||||
* Updates a given schedule with the new data provided.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
@ -165,7 +166,7 @@ class ScheduleController extends ClientApiController
|
||||
/**
|
||||
* Get the next run timestamp based on the cron data provided.
|
||||
*
|
||||
* @throws DisplayException
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
protected function getNextRunAt(Request $request): Carbon
|
||||
{
|
||||
@ -177,7 +178,7 @@ class ScheduleController extends ClientApiController
|
||||
$request->input('month'),
|
||||
$request->input('day_of_week')
|
||||
);
|
||||
} catch (\Exception $exception) {
|
||||
} catch (Exception $exception) {
|
||||
throw new DisplayException('The cron data provided does not evaluate to a valid expression.');
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ class ScheduleTaskController extends ClientApiController
|
||||
*/
|
||||
public function __construct(
|
||||
private ConnectionInterface $connection,
|
||||
private TaskRepository $repository,
|
||||
private TaskRepository $repository
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
@ -35,7 +35,7 @@ class ScheduleTaskController extends ClientApiController
|
||||
* Create a new task for a given schedule and store it in the database.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws ServiceLimitExceededException
|
||||
* @throws \Pterodactyl\Exceptions\Service\ServiceLimitExceededException
|
||||
*/
|
||||
public function store(StoreTaskRequest $request, Server $server, Schedule $schedule): array
|
||||
{
|
||||
@ -48,10 +48,10 @@ class ScheduleTaskController extends ClientApiController
|
||||
throw new HttpForbiddenException("A backup task cannot be created when the server's backup limit is set to 0.");
|
||||
}
|
||||
|
||||
/** @var Task|null $lastTask */
|
||||
/** @var \Pterodactyl\Models\Task|null $lastTask */
|
||||
$lastTask = $schedule->tasks()->orderByDesc('sequence_id')->first();
|
||||
|
||||
/** @var Task $task */
|
||||
/** @var \Pterodactyl\Models\Task $task */
|
||||
$task = $this->connection->transaction(function () use ($request, $schedule, $lastTask) {
|
||||
$sequenceId = ($lastTask->sequence_id ?? 0) + 1;
|
||||
$requestSequenceId = $request->integer('sequence_id', $sequenceId);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user