From c9e874d3aea3d67808794c33cc141130f1d89357 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 6 Mar 2018 21:53:05 -0600 Subject: [PATCH 01/33] Fix UI error changing a server's service, closes #1019 --- CHANGELOG.md | 4 +++ .../admin/servers/view/startup.blade.php | 30 ++++++++++--------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d9126443..be3ab7c2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ 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. +## v0.7.6 (Derelict Dermodactylus) +### Fixed +* Fixes a UI error when attempting to change the default Nest and Egg for an existing server. + ## v0.7.5 (Derelict Dermodactylus) ### Fixed * Fixes application API keys being created as a client API key. diff --git a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php index ab2ac46f7..5b5a12c4c 100644 --- a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php +++ b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php @@ -134,13 +134,8 @@ {!! Theme::js('vendor/lodash/lodash.js') !!} - @endsection From d3f797bf2ab6f4c8af7c40f910e9d7287f16a369 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 6 Mar 2018 21:57:00 -0600 Subject: [PATCH 02/33] fix view-allocations permissions check in templates, closes #1021 --- CHANGELOG.md | 1 + resources/themes/pterodactyl/layouts/master.blade.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be3ab7c2b..3efa09910 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ## v0.7.6 (Derelict Dermodactylus) ### Fixed * Fixes a UI error when attempting to change the default Nest and Egg for an existing server. +* Correct permissions check in UI to allow subusers with permission to `view-allocations` the ability to actually see the sidebar link. ## v0.7.5 (Derelict Dermodactylus) ### Fixed diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 060c76ced..1d8cd8380 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -170,7 +170,7 @@ @endcan - @if(Gate::allows('view-startup', $server) || Gate::allows('access-sftp', $server) || Gate::allows('view-allocation', $server)) + @if(Gate::allows('view-startup', $server) || Gate::allows('access-sftp', $server) || Gate::allows('view-allocations', $server))
  • - @can('view-allocation', $server) + @can('view-allocations', $server)
  • @lang('navigation.server.port_allocations')
  • @endcan @can('access-sftp', $server) From 4964d294f6b23208a00a9f153b616632dd5acebd Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 6 Mar 2018 22:17:01 -0600 Subject: [PATCH 03/33] Throw 504 where necessary --- CHANGELOG.md | 3 +++ app/Http/Controllers/Base/IndexController.php | 4 ++++ public/themes/pterodactyl/js/frontend/serverlist.js | 7 +++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3efa09910..104d2fb87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Fixes a UI error when attempting to change the default Nest and Egg for an existing server. * Correct permissions check in UI to allow subusers with permission to `view-allocations` the ability to actually see the sidebar link. +### Changed +* Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. + ## v0.7.5 (Derelict Dermodactylus) ### Fixed * Fixes application API keys being created as a client API key. diff --git a/app/Http/Controllers/Base/IndexController.php b/app/Http/Controllers/Base/IndexController.php index 70b5250f0..f5272935f 100644 --- a/app/Http/Controllers/Base/IndexController.php +++ b/app/Http/Controllers/Base/IndexController.php @@ -4,6 +4,8 @@ namespace Pterodactyl\Http\Controllers\Base; use Illuminate\Http\Request; use Pterodactyl\Models\User; +use Illuminate\Http\Response; +use GuzzleHttp\Exception\ConnectException; use GuzzleHttp\Exception\RequestException; use Pterodactyl\Http\Controllers\Controller; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -81,6 +83,8 @@ class IndexController extends Controller try { $response = $this->daemonRepository->setServer($server)->setToken($token)->details(); + } catch (ConnectException $exception) { + throw new HttpException(Response::HTTP_GATEWAY_TIMEOUT, $exception->getMessage()); } catch (RequestException $exception) { throw new HttpException(500, $exception->getMessage()); } diff --git a/public/themes/pterodactyl/js/frontend/serverlist.js b/public/themes/pterodactyl/js/frontend/serverlist.js index 4b1d09197..1c6865a9b 100644 --- a/public/themes/pterodactyl/js/frontend/serverlist.js +++ b/public/themes/pterodactyl/js/frontend/serverlist.js @@ -80,8 +80,11 @@ } } }).fail(function (jqXHR) { - console.error(jqXHR); - element.find('[data-action="status"]').html('Error'); + if (jqXHR.status === 504) { + element.find('[data-action="status"]').html('Gateway Timeout'); + } else { + element.find('[data-action="status"]').html('Error'); + } }); }).promise().done(function () { setTimeout(updateServerStatus, 10000); From 4952a27903b5529223b0459d1234c28bdc66b16c Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 6 Mar 2018 22:58:38 -0600 Subject: [PATCH 04/33] Add session specific redis cache --- CHANGELOG.md | 1 + config/cache.php | 6 ++++++ config/database.php | 8 ++++++++ config/session.php | 2 +- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 104d2fb87..926da0d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Changed * Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. +* Sessions handled through redis now use a seperate database (default `1`) to store session database to avoid logging users out when flushing the cache. ## v0.7.5 (Derelict Dermodactylus) ### Fixed diff --git a/config/cache.php b/config/cache.php index 86bbeb61e..bf429c4bf 100644 --- a/config/cache.php +++ b/config/cache.php @@ -70,6 +70,12 @@ return [ 'driver' => 'redis', 'connection' => 'default', ], + + 'sessions' => [ + 'driver' => env('SESSION_DRIVER', 'database'), + 'table' => 'sessions', + 'connection' => env('SESSION_DRIVER') === 'redis' ? 'sessions' : null, + ], ], /* diff --git a/config/database.php b/config/database.php index acbc8627b..e03a09767 100644 --- a/config/database.php +++ b/config/database.php @@ -71,11 +71,19 @@ return [ 'redis' => [ 'client' => 'predis', + 'default' => [ 'host' => env('REDIS_HOST', 'localhost'), 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => env('REDIS_DATBASE', 0), ], + + 'sessions' => [ + 'host' => env('REDIS_HOST', 'localhost'), + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), + 'database' => env('REDIS_DATBASE_SESSIONS', 1), + ], ], ]; diff --git a/config/session.php b/config/session.php index 837809f66..4f3a2e6de 100644 --- a/config/session.php +++ b/config/session.php @@ -69,7 +69,7 @@ return [ | */ - 'connection' => null, + 'connection' => env('SESSION_DRIVER') === 'redis' ? 'sessions' : null, /* |-------------------------------------------------------------------------- From 5839034e8fe23582820de294e3488e8c2af18eb4 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 6 Mar 2018 23:07:00 -0600 Subject: [PATCH 05/33] Fix egg copy from, closes #995 --- CHANGELOG.md | 1 + app/Models/Egg.php | 42 +++++++++++++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 926da0d20..ac930b8c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * Fixes a UI error when attempting to change the default Nest and Egg for an existing server. * Correct permissions check in UI to allow subusers with permission to `view-allocations` the ability to actually see the sidebar link. +* Fixes improper behavior when marking an egg as copying the configuration from another. ### Changed * Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. diff --git a/app/Models/Egg.php b/app/Models/Egg.php index c9b2d9767..ade28239d 100644 --- a/app/Models/Egg.php +++ b/app/Models/Egg.php @@ -113,7 +113,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract */ public function getCopyScriptInstallAttribute() { - return (is_null($this->copy_script_from)) ? $this->script_install : $this->scriptFrom->script_install; + if (! is_null($this->script_install) || is_null($this->copy_script_from)) { + return $this->script_install; + } + + return $this->scriptFrom->script_install; } /** @@ -124,7 +128,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract */ public function getCopyScriptEntryAttribute() { - return (is_null($this->copy_script_from)) ? $this->script_entry : $this->scriptFrom->script_entry; + if (! is_null($this->script_entry) || is_null($this->copy_script_from)) { + return $this->script_entry; + } + + return $this->scriptFrom->script_entry; } /** @@ -135,7 +143,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract */ public function getCopyScriptContainerAttribute() { - return (is_null($this->copy_script_from)) ? $this->script_container : $this->scriptFrom->script_container; + if (! is_null($this->script_container) || is_null($this->copy_script_from)) { + return $this->script_container; + } + + return $this->scriptFrom->script_container; } /** @@ -145,7 +157,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract */ public function getInheritConfigFilesAttribute() { - return is_null($this->config_from) ? $this->config_files : $this->configFrom->config_files; + if (! is_null($this->config_files) || is_null($this->config_from)) { + return $this->config_files; + } + + return $this->configFrom->config_files; } /** @@ -155,7 +171,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract */ public function getInheritConfigStartupAttribute() { - return is_null($this->config_from) ? $this->config_startup : $this->configFrom->config_startup; + if (! is_null($this->config_startup) || is_null($this->config_from)) { + return $this->config_startup; + } + + return $this->configFrom->config_startup; } /** @@ -165,7 +185,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract */ public function getInheritConfigLogsAttribute() { - return is_null($this->config_from) ? $this->config_logs : $this->configFrom->config_logs; + if (! is_null($this->config_logs) || is_null($this->config_from)) { + return $this->config_logs; + } + + return $this->configFrom->config_logs; } /** @@ -175,7 +199,11 @@ class Egg extends Model implements CleansAttributes, ValidableContract */ public function getInheritConfigStopAttribute() { - return is_null($this->config_from) ? $this->config_stop : $this->configFrom->config_stop; + if (! is_null($this->config_stop) || is_null($this->config_from)) { + return $this->config_stop; + } + + return $this->configFrom->config_stop; } /** From b7b58d840e9fa0c80fb208525145203eefee78ab Mon Sep 17 00:00:00 2001 From: Jakob Date: Wed, 7 Mar 2018 06:10:43 +0100 Subject: [PATCH 06/33] Improve the Vagrantfile a little (#1025) --- Vagrantfile | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index ed4b5bd4c..1eb62f5dc 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,13 +1,9 @@ Vagrant.configure("2") do |config| - config.vm.box = "ubuntu/xenial64" + config.vm.box = "bento/ubuntu-16.04" config.vm.synced_folder "./", "/var/www/html/pterodactyl", owner: "www-data", group: "www-data" - #config.vm.provision :file, source: ".dev/vagrant/pterdactyl.conf", destination: "/etc/nginx/sites-available/pterodactyl.conf" - #config.vm.provision :file, source: ".dev/vagrant/pteroq.service", destination: "/etc/systemd/system/pteroq.service" - #config.vm.provision :file, source: ".dev/vagrant/mailhog.service", destination: "/etc/systemd/system/mailhog.service" - #config.vm.provision :file, source: ".dev/vagrant/.env", destination: "/var/www/html/pterodactyl/.env" config.vm.provision :shell, path: ".dev/vagrant/provision.sh" config.vm.network :private_network, ip: "192.168.50.2" @@ -16,6 +12,6 @@ Vagrant.configure("2") do |config| config.vm.network :forwarded_port, guest: 3306, host: 53306 # Config for the vagrant-dns plugin (https://github.com/BerlinVagrant/vagrant-dns) - config.dns.tld = "app" - config.dns.patterns = [/^pterodactyl.app$/] + config.dns.tld = "test" + config.dns.patterns = [/^pterodactyl.test$/] end From 1d623a319bd9b6997de40be29af575e860641147 Mon Sep 17 00:00:00 2001 From: arajdon Date: Wed, 7 Mar 2018 06:11:05 +0100 Subject: [PATCH 07/33] Update Teamspeak 3.1.1 (#1022) Added "\n\ntouch \/mnt\/server\/.ts3server_license_accepted" and changed version number. I've tested this changes on my installation. Works fine. Thats my first PR. Hope thats ok so. --- .../seeds/eggs/voice-servers/egg-teamspeak3-server.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/database/seeds/eggs/voice-servers/egg-teamspeak3-server.json b/database/seeds/eggs/voice-servers/egg-teamspeak3-server.json index fe73a1665..927978d23 100644 --- a/database/seeds/eggs/voice-servers/egg-teamspeak3-server.json +++ b/database/seeds/eggs/voice-servers/egg-teamspeak3-server.json @@ -17,7 +17,7 @@ }, "scripts": { "installation": { - "script": "#!\/bin\/ash\n# TS3 Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add tar curl\n\ncd \/tmp\n\ncurl -sSLO http:\/\/dl.4players.de\/ts\/releases\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\n\ntar -xjvf teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\ncp -r teamspeak3-server_linux_amd64\/* \/mnt\/server\n\necho \"machine_id=\ndefault_voice_port=${SERVER_PORT}\nvoice_ip=0.0.0.0\nlicensepath=\nfiletransfer_port=30033\nfiletransfer_ip=\nquery_port=${SERVER_PORT}\nquery_ip=0.0.0.0\nquery_ip_whitelist=query_ip_whitelist.txt\nquery_ip_blacklist=query_ip_blacklist.txt\ndbplugin=ts3db_sqlite3\ndbpluginparameter=\ndbsqlpath=sql\/\ndbsqlcreatepath=create_sqlite\/\ndbconnections=10\nlogpath=logs\nlogquerycommands=0\ndbclientkeepdays=30\nlogappend=0\nquery_skipbruteforcecheck=0\" > \/mnt\/server\/ts3server.ini", + "script": "#!\/bin\/ash\n# TS3 Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add tar curl\n\ncd \/tmp\n\ncurl -sSLO http:\/\/dl.4players.de\/ts\/releases\/${TS_VERSION}\/teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\n\ntar -xjvf teamspeak3-server_linux_amd64-${TS_VERSION}.tar.bz2\ncp -r teamspeak3-server_linux_amd64\/* \/mnt\/server\n\necho \"machine_id=\ndefault_voice_port=${SERVER_PORT}\nvoice_ip=0.0.0.0\nlicensepath=\nfiletransfer_port=30033\nfiletransfer_ip=\nquery_port=${SERVER_PORT}\nquery_ip=0.0.0.0\nquery_ip_whitelist=query_ip_whitelist.txt\nquery_ip_blacklist=query_ip_blacklist.txt\ndbplugin=ts3db_sqlite3\ndbpluginparameter=\ndbsqlpath=sql\/\ndbsqlcreatepath=create_sqlite\/\ndbconnections=10\nlogpath=logs\nlogquerycommands=0\ndbclientkeepdays=30\nlogappend=0\nquery_skipbruteforcecheck=0\" > \/mnt\/server\/ts3server.ini\n\ntouch \/mnt\/server\/.ts3server_license_accepted", "container": "alpine:3.4", "entrypoint": "ash" } @@ -27,10 +27,10 @@ "name": "Server Version", "description": "The version of Teamspeak 3 to use when running the server.", "env_variable": "TS_VERSION", - "default_value": "3.0.13.8", + "default_value": "3.1.1", "user_viewable": 1, "user_editable": 1, "rules": "required|regex:\/^([0-9_\\.-]{5,10})$\/" } ] -} \ No newline at end of file +} From 018a7a658c31eca5fec0100de7c93fddcce20344 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Wed, 7 Mar 2018 00:11:24 -0500 Subject: [PATCH 08/33] Fix #1018 with nav color change (#1020) --- resources/themes/pterodactyl/layouts/admin.blade.php | 2 +- resources/themes/pterodactyl/layouts/auth.blade.php | 2 +- resources/themes/pterodactyl/layouts/error.blade.php | 2 +- resources/themes/pterodactyl/layouts/master.blade.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/themes/pterodactyl/layouts/admin.blade.php b/resources/themes/pterodactyl/layouts/admin.blade.php index aac3507c2..d67eb6b41 100644 --- a/resources/themes/pterodactyl/layouts/admin.blade.php +++ b/resources/themes/pterodactyl/layouts/admin.blade.php @@ -19,7 +19,7 @@ - + @include('layouts.scripts') diff --git a/resources/themes/pterodactyl/layouts/auth.blade.php b/resources/themes/pterodactyl/layouts/auth.blade.php index 33664d074..0157864eb 100644 --- a/resources/themes/pterodactyl/layouts/auth.blade.php +++ b/resources/themes/pterodactyl/layouts/auth.blade.php @@ -18,7 +18,7 @@ - + @section('scripts') {!! Theme::css('vendor/bootstrap/bootstrap.min.css?t={cache-version}') !!} diff --git a/resources/themes/pterodactyl/layouts/error.blade.php b/resources/themes/pterodactyl/layouts/error.blade.php index f7c60b1bf..0ec1b00fa 100644 --- a/resources/themes/pterodactyl/layouts/error.blade.php +++ b/resources/themes/pterodactyl/layouts/error.blade.php @@ -19,7 +19,7 @@ - + @section('scripts') {!! Theme::css('vendor/bootstrap/bootstrap.min.css?t={cache-version}') !!} diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 1d8cd8380..32b75823a 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -19,7 +19,7 @@ - + @include('layouts.scripts') From 0c07577d3b210be53880f20378af16dbbba0704a Mon Sep 17 00:00:00 2001 From: William Cody Ardoin Date: Tue, 6 Mar 2018 23:11:58 -0600 Subject: [PATCH 09/33] Allow for 3 decimals, future proof (#999) The GET_VERSIONS Grep Command will fail with 1.12.2 but will work with 1.12. Added optional check for 3rd decimal place in the MC Version of Forge and future proofed the forge version for Double Numeric SubMinor version. --- database/seeds/eggs/minecraft/egg-forge-minecraft.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/database/seeds/eggs/minecraft/egg-forge-minecraft.json b/database/seeds/eggs/minecraft/egg-forge-minecraft.json index a4ab2c4b9..731d8844c 100644 --- a/database/seeds/eggs/minecraft/egg-forge-minecraft.json +++ b/database/seeds/eggs/minecraft/egg-forge-minecraft.json @@ -3,7 +3,7 @@ "meta": { "version": "PTDL_v1" }, - "exported_at": "2017-11-03T22:15:10-05:00", + "exported_at": "2018-02-27T00:57:04-06:00", "name": "Forge Minecraft", "author": "support@pterodactyl.io", "description": "Minecraft Forge Server. Minecraft Forge is a modding API (Application Programming Interface), which makes it easier to create mods, and also make sure mods are compatible with each other.", @@ -17,7 +17,7 @@ }, "scripts": { "installation": { - "script": "#!\/bin\/ash\n# Forge Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl\n\nGET_VERSIONS=$(curl -sl http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/ | grep -A1 Latest | grep -o -e '[1]\\.[0-9][0-9] - [0-9][0-9]\\.[0-9][0-9]\\.[0-9]\\.[0-9][0-9][0-9][0-9]')\nLATEST_VERSION=$(echo $GET_VERSIONS | sed 's\/ \/\/g')\n\ncd \/mnt\/server\n\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-installer.jar -o installer.jar\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-universal.jar -o server.jar\n\njava -jar installer.jar --installServer\nrm -rf installer.jar", + "script": "#!\/bin\/ash\r\n# Forge Installation Script\r\n#\r\n# Server Files: \/mnt\/server\r\napk update\r\napk add curl\r\n\r\nGET_VERSIONS=$(curl -sl http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/ | grep -A1 Latest | grep -o -e '[1]\\.[0-9][0-9]]\\?\\.\\?[0-9]\\?[0-9] - [0-9][0-9]\\.[0-9][0-9]\\.[0-9]\\?[0-9]\\.[0-9][0-9][0-9][0-9]')\r\nLATEST_VERSION=$(echo $GET_VERSIONS | sed 's\/ \/\/g')\r\n\r\ncd \/mnt\/server\r\n\r\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-installer.jar -o installer.jar\r\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-universal.jar -o server.jar\r\n\r\njava -jar installer.jar --installServer\r\nrm -rf installer.jar", "container": "frolvlad\/alpine-oraclejdk8:cleaned", "entrypoint": "ash" } @@ -33,4 +33,4 @@ "rules": "required|regex:\/^([\\w\\d._-]+)(\\.jar)$\/" } ] -} \ No newline at end of file +} From cee656fd5cc9d51eebd53a4629bb74f002461f97 Mon Sep 17 00:00:00 2001 From: CodeHat Date: Thu, 8 Mar 2018 16:21:55 +0100 Subject: [PATCH 10/33] Feature/PTDL-1030 (#1033) * Swap reCAPTCHA secret key position with website key --- CHANGELOG.md | 1 + .../pterodactyl/admin/settings/advanced.blade.php | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac930b8c9..80160f956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Changed * Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. * Sessions handled through redis now use a seperate database (default `1`) to store session database to avoid logging users out when flushing the cache. +* reCAPTCHA's secret key position swapped with website key in advanced panel settings to be consistent with Google's reCAPTCHA dashboard. ## v0.7.5 (Derelict Dermodactylus) ### Fixed diff --git a/resources/themes/pterodactyl/admin/settings/advanced.blade.php b/resources/themes/pterodactyl/admin/settings/advanced.blade.php index 5a7b4d724..7a1d616c5 100644 --- a/resources/themes/pterodactyl/admin/settings/advanced.blade.php +++ b/resources/themes/pterodactyl/admin/settings/advanced.blade.php @@ -34,6 +34,12 @@

    If enabled, login forms and password reset forms will do a silent captcha check and display a visible captcha if needed.

    +
    + +
    + +
    +
    @@ -41,12 +47,6 @@

    Used for communication between your site and Google. Be sure to keep it a secret.

    -
    - -
    - -
    -
    @if($showRecaptchaWarning)
    From 3a5d21f455bd061e037776c7bac3912eef7798d2 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 8 Mar 2018 21:30:07 -0600 Subject: [PATCH 11/33] Filemanager cleanup --- CHANGELOG.md | 1 + public/themes/pterodactyl/css/pterodactyl.css | 12 ++++ .../js/frontend/files/filemanager.min.js | 2 +- .../js/frontend/files/src/actions.js | 14 +++-- resources/lang/en/server.php | 4 +- .../pterodactyl/server/files/list.blade.php | 58 ++++++++++--------- 6 files changed, 58 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac930b8c9..53817391f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Changed * Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. * Sessions handled through redis now use a seperate database (default `1`) to store session database to avoid logging users out when flushing the cache. +* File manager UI improved to be clearer with buttons and cleaner on mobile. ## v0.7.5 (Derelict Dermodactylus) ### Fixed diff --git a/public/themes/pterodactyl/css/pterodactyl.css b/public/themes/pterodactyl/css/pterodactyl.css index 58003a338..a2ad69054 100644 --- a/public/themes/pterodactyl/css/pterodactyl.css +++ b/public/themes/pterodactyl/css/pterodactyl.css @@ -145,6 +145,18 @@ p.small { font-size: 14px !important; } +.table .min-size { + width:1px; + white-space: nowrap; +} + +@media (max-width:767px) { + .box-header > .box-tools { + position: relative !important; + padding: 0px 10px 10px; + } +} + .middle, .align-middle { vertical-align: middle !important; } diff --git a/public/themes/pterodactyl/js/frontend/files/filemanager.min.js b/public/themes/pterodactyl/js/frontend/files/filemanager.min.js index 9713f6587..2ac6b8bbc 100644 --- a/public/themes/pterodactyl/js/frontend/files/filemanager.min.js +++ b/public/themes/pterodactyl/js/frontend/files/filemanager.min.js @@ -1,4 +1,4 @@ -'use strict';var _createClass=function(){function defineProperties(target,props){for(var i=0;i\n \n ';nameBlock.html(attachEditor);var inputField=nameBlock.find('input');var inputLoader=nameBlock.find('.input-loader');inputField.focus();inputField.on('blur keydown',function(e){if(e.type==='keydown'&&e.which===27||e.type==='blur'||e.type==='keydown'&&e.which===13&¤tName===inputField.val()){if(!_.isEmpty(currentLink)){nameBlock.html(currentLink)}else{nameBlock.html(currentName)}inputField.remove();ContextMenu.unbind().run();return}if(e.type==='keydown'&&e.which!==13)return;inputLoader.show();var currentPath=decodeURIComponent(nameBlock.data('path'));$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/rename',timeout:10000,data:JSON.stringify({from:''+currentPath+currentName,to:''+currentPath+inputField.val()})}).done(function(data){nameBlock.attr('data-name',inputField.val());if(!_.isEmpty(currentLink)){var newLink=currentLink.attr('href');if(nameBlock.parent().data('type')!=='folder'){newLink=newLink.substr(0,newLink.lastIndexOf('/'))+'/'+inputField.val()}currentLink.attr('href',newLink);nameBlock.html(currentLink.html(inputField.val()))}else{nameBlock.html(inputField.val())}inputField.remove()}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}nameBlock.addClass('has-error').delay(2000).queue(function(){nameBlock.removeClass('has-error').dequeue()});inputField.popover({animation:true,placement:'top',content:error,title:'Save Error'}).popover('show')}).always(function(){inputLoader.remove();ContextMenu.unbind().run()})})}},{key:'copy',value:function copy(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var currentName=decodeURIComponent(nameBlock.attr('data-name'));var currentPath=decodeURIComponent(nameBlock.data('path'));swal({type:'input',title:'Copy File',text:'Please enter the new path for the copied file below.',showCancelButton:true,showConfirmButton:true,closeOnConfirm:false,showLoaderOnConfirm:true,inputValue:''+currentPath+currentName},function(val){$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/copy',timeout:10000,data:JSON.stringify({from:''+currentPath+currentName,to:''+val})}).done(function(data){swal({type:'success',title:'',text:'File successfully copied.'});Files.list()}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}swal({type:'error',title:'',text:error})})})}},{key:'download',value:function download(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var fileName=decodeURIComponent(nameBlock.attr('data-name'));var filePath=decodeURIComponent(nameBlock.data('path'));window.location='/server/'+Pterodactyl.server.uuidShort+'/files/download/'+filePath+fileName}},{key:'delete',value:function _delete(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var delPath=decodeURIComponent(nameBlock.data('path'));var delName=decodeURIComponent(nameBlock.data('name'));swal({type:'warning',title:'',text:'Are you sure you want to delete '+delName+'? There is no reversing this action.',html:true,showCancelButton:true,showConfirmButton:true,closeOnConfirm:false,showLoaderOnConfirm:true},function(){$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/delete',timeout:10000,data:JSON.stringify({items:[''+delPath+delName]})}).done(function(data){nameBlock.parent().addClass('warning').delay(200).fadeOut();swal({type:'success',title:'File Deleted'})}).fail(function(jqXHR){console.error(jqXHR);swal({type:'error',title:'Whoops!',html:true,text:'An error occured while attempting to delete this file. Please try again.'})})})}},{key:'toggleMassActions',value:function toggleMassActions(){if($('#file_listing input[type="checkbox"]:checked').length){$('#mass_actions').removeClass('disabled')}else{$('#mass_actions').addClass('disabled')}}},{key:'toggleHighlight',value:function toggleHighlight(event){var parent=$(event.currentTarget);var item=$(event.currentTarget).find('input');if($(item).is(':checked')){$(item).prop('checked',false);parent.removeClass('warning').delay(200)}else{$(item).prop('checked',true);parent.addClass('warning').delay(200)}}},{key:'highlightAll',value:function highlightAll(event){var parent=void 0;var item=$(event.currentTarget).find('input');if($(item).is(':checked')){$('#file_listing input[type=checkbox]').prop('checked',false);$('#file_listing input[data-action="addSelection"]').each(function(){parent=$(this).closest('tr');parent.removeClass('warning').delay(200)})}else{$('#file_listing input[type=checkbox]').prop('checked',true);$('#file_listing input[data-action="addSelection"]').each(function(){parent=$(this).closest('tr');parent.addClass('warning').delay(200)})}}},{key:'deleteSelected',value:function deleteSelected(){var selectedItems=[];var selectedItemsElements=[];var parent=void 0;var nameBlock=void 0;var delLocation=void 0;$('#file_listing input[data-action="addSelection"]:checked').each(function(){parent=$(this).closest('tr');nameBlock=$(parent).find('td[data-identifier="name"]');delLocation=decodeURIComponent(nameBlock.data('path'))+decodeURIComponent(nameBlock.data('name'));selectedItems.push(delLocation);selectedItemsElements.push(parent)});if(selectedItems.length!=0){var formattedItems='';$.each(selectedItems,function(key,value){formattedItems+=''+value+', '});formattedItems=formattedItems.slice(0,-2);swal({type:'warning',title:'',text:'Are you sure you want to delete:'+formattedItems+'? There is no reversing this action.',html:true,showCancelButton:true,showConfirmButton:true,closeOnConfirm:false,showLoaderOnConfirm:true},function(){$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/delete',timeout:10000,data:JSON.stringify({items:selectedItems})}).done(function(data){$('#file_listing input:checked').each(function(){$(this).prop('checked',false)});$.each(selectedItemsElements,function(){$(this).addClass('warning').delay(200).fadeOut()});swal({type:'success',title:'Files Deleted'})}).fail(function(jqXHR){console.error(jqXHR);swal({type:'error',title:'Whoops!',html:true,text:'An error occured while attempting to delete these files. Please try again.'})})})}else{swal({type:'warning',title:'',text:'Please select files/folders to delete.'})}}},{key:'decompress',value:function decompress(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var compPath=decodeURIComponent(nameBlock.data('path'));var compName=decodeURIComponent(nameBlock.data('name'));swal({title:' Decompressing...',text:'This might take a few seconds to complete.',html:true,allowOutsideClick:false,allowEscapeKey:false,showConfirmButton:false});$.ajax({type:'POST',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/decompress',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',data:JSON.stringify({files:''+compPath+compName})}).done(function(data){swal.close();Files.list(compPath)}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}swal({type:'error',title:'Whoops!',html:true,text:error})})}},{key:'compress',value:function compress(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var compPath=decodeURIComponent(nameBlock.data('path'));var compName=decodeURIComponent(nameBlock.data('name'));$.ajax({type:'POST',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/compress',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',data:JSON.stringify({files:''+compPath+compName,to:compPath.toString()})}).done(function(data){Files.list(compPath,function(err){if(err)return;var fileListing=$('#file_listing').find('[data-name="'+data.saved_as+'"]').parent();fileListing.addClass('success pulsate').delay(3000).queue(function(){fileListing.removeClass('success pulsate').dequeue()})})}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}swal({type:'error',title:'Whoops!',html:true,text:error})})}}]);return ActionsClass}(); +'use strict';var _createClass=function(){function defineProperties(target,props){for(var i=0;i\n \n ';nameBlock.html(attachEditor);var inputField=nameBlock.find('input');var inputLoader=nameBlock.find('.input-loader');inputField.focus();inputField.on('blur keydown',function(e){if(e.type==='keydown'&&e.which===27||e.type==='blur'||e.type==='keydown'&&e.which===13&¤tName===inputField.val()){if(!_.isEmpty(currentLink)){nameBlock.html(currentLink)}else{nameBlock.html(currentName)}inputField.remove();ContextMenu.unbind().run();return}if(e.type==='keydown'&&e.which!==13)return;inputLoader.show();var currentPath=decodeURIComponent(nameBlock.data('path'));$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/rename',timeout:10000,data:JSON.stringify({from:''+currentPath+currentName,to:''+currentPath+inputField.val()})}).done(function(data){nameBlock.attr('data-name',inputField.val());if(!_.isEmpty(currentLink)){var newLink=currentLink.attr('href');if(nameBlock.parent().data('type')!=='folder'){newLink=newLink.substr(0,newLink.lastIndexOf('/'))+'/'+inputField.val()}currentLink.attr('href',newLink);nameBlock.html(currentLink.html(inputField.val()))}else{nameBlock.html(inputField.val())}inputField.remove()}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}nameBlock.addClass('has-error').delay(2000).queue(function(){nameBlock.removeClass('has-error').dequeue()});inputField.popover({animation:true,placement:'top',content:error,title:'Save Error'}).popover('show')}).always(function(){inputLoader.remove();ContextMenu.unbind().run()})})}},{key:'copy',value:function copy(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var currentName=decodeURIComponent(nameBlock.attr('data-name'));var currentPath=decodeURIComponent(nameBlock.data('path'));swal({type:'input',title:'Copy File',text:'Please enter the new path for the copied file below.',showCancelButton:true,showConfirmButton:true,closeOnConfirm:false,showLoaderOnConfirm:true,inputValue:''+currentPath+currentName},function(val){$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/copy',timeout:10000,data:JSON.stringify({from:''+currentPath+currentName,to:''+val})}).done(function(data){swal({type:'success',title:'',text:'File successfully copied.'});Files.list()}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}swal({type:'error',title:'',text:error})})})}},{key:'download',value:function download(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var fileName=decodeURIComponent(nameBlock.attr('data-name'));var filePath=decodeURIComponent(nameBlock.data('path'));window.location='/server/'+Pterodactyl.server.uuidShort+'/files/download/'+filePath+fileName}},{key:'delete',value:function _delete(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var delPath=decodeURIComponent(nameBlock.data('path'));var delName=decodeURIComponent(nameBlock.data('name'));swal({type:'warning',title:'',text:'Are you sure you want to delete '+delName+'?',html:true,showCancelButton:true,showConfirmButton:true,closeOnConfirm:false,showLoaderOnConfirm:true},function(){$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/delete',timeout:10000,data:JSON.stringify({items:[''+delPath+delName]})}).done(function(data){nameBlock.parent().addClass('warning').delay(200).fadeOut();swal({type:'success',title:'File Deleted'})}).fail(function(jqXHR){console.error(jqXHR);swal({type:'error',title:'Whoops!',html:true,text:'An error occured while attempting to delete this file. Please try again.'})})})}},{key:'toggleMassActions',value:function toggleMassActions(){if($('#file_listing input[type="checkbox"]:checked').length){$('#mass_actions').removeClass('disabled')}else{$('#mass_actions').addClass('disabled')}}},{key:'toggleHighlight',value:function toggleHighlight(event){var parent=$(event.currentTarget);var item=$(event.currentTarget).find('input');if($(item).is(':checked')){$(item).prop('checked',false);parent.removeClass('warning').delay(200)}else{$(item).prop('checked',true);parent.addClass('warning').delay(200)}}},{key:'highlightAll',value:function highlightAll(event){var parent=void 0;var item=$(event.currentTarget).find('input');if($(item).is(':checked')){$('#file_listing input[type=checkbox]').prop('checked',false);$('#file_listing input[data-action="addSelection"]').each(function(){parent=$(this).closest('tr');parent.removeClass('warning').delay(200)})}else{$('#file_listing input[type=checkbox]').prop('checked',true);$('#file_listing input[data-action="addSelection"]').each(function(){parent=$(this).closest('tr');parent.addClass('warning').delay(200)})}}},{key:'deleteSelected',value:function deleteSelected(){var selectedItems=[];var selectedItemsElements=[];var parent=void 0;var nameBlock=void 0;var delLocation=void 0;$('#file_listing input[data-action="addSelection"]:checked').each(function(){parent=$(this).closest('tr');nameBlock=$(parent).find('td[data-identifier="name"]');delLocation=decodeURIComponent(nameBlock.data('path'))+decodeURIComponent(nameBlock.data('name'));selectedItems.push(delLocation);selectedItemsElements.push(parent)});if(selectedItems.length!=0){var formattedItems='';var i=0;$.each(selectedItems,function(key,value){formattedItems+=''+value+', ';i++;return i<5});formattedItems=formattedItems.slice(0,-2);if(selectedItems.length>5){formattedItems+=', and '+(selectedItems.length-5)+' other(s)'}swal({type:'warning',title:'',text:'Are you sure you want to delete the following files: '+formattedItems+'?',html:true,showCancelButton:true,showConfirmButton:true,closeOnConfirm:false,showLoaderOnConfirm:true},function(){$.ajax({type:'POST',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/delete',timeout:10000,data:JSON.stringify({items:selectedItems})}).done(function(data){$('#file_listing input:checked').each(function(){$(this).prop('checked',false)});$.each(selectedItemsElements,function(){$(this).addClass('warning').delay(200).fadeOut()});swal({type:'success',title:'Files Deleted'})}).fail(function(jqXHR){console.error(jqXHR);swal({type:'error',title:'Whoops!',html:true,text:'An error occured while attempting to delete these files. Please try again.'})})})}else{swal({type:'warning',title:'',text:'Please select files/folders to delete.'})}}},{key:'decompress',value:function decompress(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var compPath=decodeURIComponent(nameBlock.data('path'));var compName=decodeURIComponent(nameBlock.data('name'));swal({title:' Decompressing...',text:'This might take a few seconds to complete.',html:true,allowOutsideClick:false,allowEscapeKey:false,showConfirmButton:false});$.ajax({type:'POST',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/decompress',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',data:JSON.stringify({files:''+compPath+compName})}).done(function(data){swal.close();Files.list(compPath)}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}swal({type:'error',title:'Whoops!',html:true,text:error})})}},{key:'compress',value:function compress(){var nameBlock=$(this.element).find('td[data-identifier="name"]');var compPath=decodeURIComponent(nameBlock.data('path'));var compName=decodeURIComponent(nameBlock.data('name'));$.ajax({type:'POST',url:Pterodactyl.node.scheme+'://'+Pterodactyl.node.fqdn+':'+Pterodactyl.node.daemonListen+'/v1/server/file/compress',headers:{'X-Access-Token':Pterodactyl.server.daemonSecret,'X-Access-Server':Pterodactyl.server.uuid},contentType:'application/json; charset=utf-8',data:JSON.stringify({files:''+compPath+compName,to:compPath.toString()})}).done(function(data){Files.list(compPath,function(err){if(err)return;var fileListing=$('#file_listing').find('[data-name="'+data.saved_as+'"]').parent();fileListing.addClass('success pulsate').delay(3000).queue(function(){fileListing.removeClass('success pulsate').dequeue()})})}).fail(function(jqXHR){console.error(jqXHR);var error='An error occured while trying to process this request.';if(typeof jqXHR.responseJSON!=='undefined'&&typeof jqXHR.responseJSON.error!=='undefined'){error=jqXHR.responseJSON.error}swal({type:'error',title:'Whoops!',html:true,text:error})})}}]);return ActionsClass}(); 'use strict';var _createClass=function(){function defineProperties(target,props){for(var i=0;i New File
  • New Folder
  • '}if(Pterodactyl.permissions.downloadFiles||Pterodactyl.permissions.deleteFiles){buildMenu+='
  • '}if(Pterodactyl.permissions.downloadFiles){buildMenu+=''}if(Pterodactyl.permissions.deleteFiles){buildMenu+='
  • Delete
  • '}buildMenu+='';return buildMenu}},{key:'rightClick',value:function rightClick(){var _this=this;$('[data-action="toggleMenu"]').on('mousedown',function(event){event.preventDefault();if($(document).find('#fileOptionMenu').is(':visible')){$('body').trigger('click');return}_this.showMenu(event)});$('#file_listing > tbody td').on('contextmenu',function(event){_this.showMenu(event)})}},{key:'showMenu',value:function showMenu(event){var _this2=this;var parent=$(event.target).closest('tr');var menu=$(this.makeMenu(parent));if(parent.data('type')==='disabled')return;event.preventDefault();$(menu).appendTo('body');$(menu).data('invokedOn',$(event.target)).show().css({position:'absolute',left:event.pageX-150,top:event.pageY});this.activeLine=parent;this.activeLine.addClass('active');var Actions=new ActionsClass(parent,menu);if(Pterodactyl.permissions.moveFiles){$(menu).find('li[data-action="move"]').unbind().on('click',function(e){e.preventDefault();Actions.move()});$(menu).find('li[data-action="rename"]').unbind().on('click',function(e){e.preventDefault();Actions.rename()})}if(Pterodactyl.permissions.copyFiles){$(menu).find('li[data-action="copy"]').unbind().on('click',function(e){e.preventDefault();Actions.copy()})}if(Pterodactyl.permissions.compressFiles){if(parent.data('type')==='folder'){$(menu).find('li[data-action="compress"]').removeClass('hidden')}$(menu).find('li[data-action="compress"]').unbind().on('click',function(e){e.preventDefault();Actions.compress()})}if(Pterodactyl.permissions.decompressFiles){if(_.without(['application/zip','application/gzip','application/x-gzip'],parent.data('mime')).length<3){$(menu).find('li[data-action="decompress"]').removeClass('hidden')}$(menu).find('li[data-action="decompress"]').unbind().on('click',function(e){e.preventDefault();Actions.decompress()})}if(Pterodactyl.permissions.createFiles){$(menu).find('li[data-action="folder"]').unbind().on('click',function(e){e.preventDefault();Actions.folder()})}if(Pterodactyl.permissions.downloadFiles){if(parent.data('type')==='file'){$(menu).find('li[data-action="download"]').removeClass('hidden')}$(menu).find('li[data-action="download"]').unbind().on('click',function(e){e.preventDefault();Actions.download()})}if(Pterodactyl.permissions.deleteFiles){$(menu).find('li[data-action="delete"]').unbind().on('click',function(e){e.preventDefault();Actions.delete()})}$(window).unbind().on('click',function(event){if($(event.target).is('.disable-menu-hide')){event.preventDefault();return}$(menu).unbind().remove();if(!_.isNull(_this2.activeLine))_this2.activeLine.removeClass('active')})}},{key:'directoryClick',value:function directoryClick(){$('a[data-action="directory-view"]').on('click',function(event){event.preventDefault();var path=$(this).parent().data('path')||'';var name=$(this).parent().data('name')||'';window.location.hash=encodeURIComponent(path+name);Files.list()})}}]);return ContextMenuClass}();window.ContextMenu=new ContextMenuClass; 'use strict';var _typeof=typeof Symbol==='function'&&typeof Symbol.iterator==='symbol'?function(obj){return typeof obj}:function(obj){return obj&&typeof Symbol==='function'&&obj.constructor===Symbol&&obj!==Symbol.prototype?'symbol':typeof obj};var _createClass=function(){function defineProperties(target,props){for(var i=0;i' + delName + '? There is no reversing this action.', + text: 'Are you sure you want to delete ' + delName + '?', html: true, showCancelButton: true, showConfirmButton: true, @@ -380,16 +380,22 @@ class ActionsClass { if (selectedItems.length != 0) { let formattedItems = ""; + let i = 0; $.each(selectedItems, function(key, value) { - formattedItems += ("" + value + ", "); - }) + formattedItems += ("" + value + ", "); + i++; + return i < 5; + }); formattedItems = formattedItems.slice(0, -2); + if (selectedItems.length > 5) { + formattedItems += ', and ' + (selectedItems.length - 5) + ' other(s)'; + } swal({ type: 'warning', title: '', - text: 'Are you sure you want to delete:' + formattedItems + '? There is no reversing this action.', + text: 'Are you sure you want to delete the following files: ' + formattedItems + '?', html: true, showCancelButton: true, showConfirmButton: true, diff --git a/resources/lang/en/server.php b/resources/lang/en/server.php index 8941c4793..76002aedf 100644 --- a/resources/lang/en/server.php +++ b/resources/lang/en/server.php @@ -273,8 +273,8 @@ return [ 'last_modified' => 'Last Modified', 'add_new' => 'Add New File', 'add_folder' => 'Add New Folder', - 'mass_actions' => 'Mass actions', - 'delete' => 'Delete', + 'mass_actions' => 'Mass Actions', + 'delete' => 'Delete Files', 'edit' => [ 'header' => 'Edit File', 'header_sub' => 'Make modifications to a file from the web.', diff --git a/resources/themes/pterodactyl/server/files/list.blade.php b/resources/themes/pterodactyl/server/files/list.blade.php index bbe2b24d8..18d5481df 100644 --- a/resources/themes/pterodactyl/server/files/list.blade.php +++ b/resources/themes/pterodactyl/server/files/list.blade.php @@ -6,45 +6,45 @@

    /home/container{{ $directory['header'] }}

    -
    -
    - - -
    - +
    + +
    - - - - - + + + + @if (isset($directory['first']) && $directory['first'] === true) - + @@ -53,7 +53,7 @@ @endif @if (isset($directory['show']) && $directory['show'] === true) - + @@ -64,7 +64,9 @@ @endif @foreach ($folders as $folder) - + @@ -79,12 +81,14 @@ {{ $carbon->diffForHumans() }} @endif - + @endforeach @foreach ($files as $file) - - + @endforeach From 4c26d0914527686def9be0e57b29c8c51b859df7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 8 Mar 2018 21:33:44 -0600 Subject: [PATCH 12/33] Wait for window load to set the egg --- .../themes/pterodactyl/admin/servers/view/startup.blade.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php index 5b5a12c4c..3d4cd83f6 100644 --- a/resources/themes/pterodactyl/admin/servers/view/startup.blade.php +++ b/resources/themes/pterodactyl/admin/servers/view/startup.blade.php @@ -133,6 +133,9 @@ @parent {!! Theme::js('vendor/lodash/lodash.js') !!} @endsection From dfb002fb337a9efe684a1e95b3abfb7b98f83bcd Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 8 Mar 2018 23:35:36 -0600 Subject: [PATCH 14/33] Change config value for daemon --- app/Models/Node.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Node.php b/app/Models/Node.php index 0134b7c7a..f978bcf77 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -164,7 +164,7 @@ class Node extends Model implements CleansAttributes, ValidableContract 'enabled' => true, 'kill_at_count' => 5, 'decay' => 10, - 'bytes' => 30720, + 'lines' => 1000, 'check_interval_ms' => 100, ], ], From ef371a508da6765f5ac543e96ab7d43c6b6b03a6 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 10 Mar 2018 12:03:23 -0600 Subject: [PATCH 15/33] Change check on debugbar to use debug not environment --- CHANGELOG.md | 1 + app/Http/Middleware/Api/SetSessionDriver.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57419d185..68d057df8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Fixes a UI error when attempting to change the default Nest and Egg for an existing server. * Correct permissions check in UI to allow subusers with permission to `view-allocations` the ability to actually see the sidebar link. * Fixes improper behavior when marking an egg as copying the configuration from another. +* Debug bar is only checked when the app is set to debug mode in the API session handler, rather than when it is in local mode to match the plugin settings. ### Changed * Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. diff --git a/app/Http/Middleware/Api/SetSessionDriver.php b/app/Http/Middleware/Api/SetSessionDriver.php index c69311a65..3d5c16617 100644 --- a/app/Http/Middleware/Api/SetSessionDriver.php +++ b/app/Http/Middleware/Api/SetSessionDriver.php @@ -41,7 +41,7 @@ class SetSessionDriver */ public function handle(Request $request, Closure $next) { - if ($this->app->environment() !== 'production') { + if ($this->config->get('app.debug')) { $this->app->make(LaravelDebugbar::class)->disable(); } From e5c59c498494dd2a868b84096cdaf3b330dbde3e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 10 Mar 2018 13:02:41 -0600 Subject: [PATCH 16/33] Change exception handling for display exception --- CHANGELOG.md | 1 + app/Exceptions/DisplayException.php | 33 +++++++++++++++++++++++------ app/Exceptions/Handler.php | 13 +++++++++++- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68d057df8..17ab8f05c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Sessions handled through redis now use a seperate database (default `1`) to store session database to avoid logging users out when flushing the cache. * File manager UI improved to be clearer with buttons and cleaner on mobile. * reCAPTCHA's secret key position swapped with website key in advanced panel settings to be consistent with Google's reCAPTCHA dashboard. +* Changed DisplayException to handle its own logging correctly and check if the previous exception is marked as one that should not be logged. ## v0.7.5 (Derelict Dermodactylus) ### Fixed diff --git a/app/Exceptions/DisplayException.php b/app/Exceptions/DisplayException.php index e3a839c5e..a00939711 100644 --- a/app/Exceptions/DisplayException.php +++ b/app/Exceptions/DisplayException.php @@ -2,9 +2,11 @@ namespace Pterodactyl\Exceptions; -use Log; +use Exception; use Throwable; +use Psr\Log\LoggerInterface; use Illuminate\Http\Response; +use Illuminate\Container\Container; use Prologue\Alerts\AlertsMessageBag; class DisplayException extends PterodactylException @@ -31,10 +33,6 @@ class DisplayException extends PterodactylException { parent::__construct($message, $code, $previous); - if (! is_null($previous)) { - Log::{$level}($previous); - } - $this->level = $level; } @@ -70,8 +68,31 @@ class DisplayException extends PterodactylException ]), method_exists($this, 'getStatusCode') ? $this->getStatusCode() : Response::HTTP_BAD_REQUEST); } - app()->make(AlertsMessageBag::class)->danger($this->getMessage())->flash(); + Container::getInstance()->make(AlertsMessageBag::class)->danger($this->getMessage())->flash(); return redirect()->back()->withInput(); } + + /** + * Log the exception to the logs using the defined error level only if the previous + * exception is set. + * + * @return mixed + * + * @throws \Exception + */ + public function report() + { + if (! $this->getPrevious() instanceof Exception || ! Handler::isReportable($this->getPrevious())) { + return null; + } + + try { + $logger = Container::getInstance()->make(LoggerInterface::class); + } catch (Exception $ex) { + throw $this->getPrevious(); + } + + return $logger->{$this->getErrorLevel()}($this->getPrevious()); + } } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 500f2d0ca..be8a4e556 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -5,6 +5,7 @@ namespace Pterodactyl\Exceptions; use Exception; use PDOException; use Psr\Log\LoggerInterface; +use Illuminate\Container\Container; use Illuminate\Auth\AuthenticationException; use Illuminate\Session\TokenMismatchException; use Illuminate\Validation\ValidationException; @@ -24,7 +25,6 @@ class Handler extends ExceptionHandler protected $dontReport = [ AuthenticationException::class, AuthorizationException::class, - DisplayException::class, HttpException::class, ModelNotFoundException::class, RecordNotFoundException::class, @@ -201,6 +201,17 @@ class Handler extends ExceptionHandler return ['errors' => [array_merge($error, $override)]]; } + /** + * Return an array of exceptions that should not be reported. + * + * @param \Exception $exception + * @return bool + */ + public static function isReportable(Exception $exception): bool + { + return (new static(Container::getInstance()))->shouldReport($exception); + } + /** * Convert an authentication exception into an unauthenticated response. * From bc3cb7bfd5131f43fb9a47e18b7a3d6aba396ed6 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 10 Mar 2018 13:02:49 -0600 Subject: [PATCH 17/33] Fix broken session driver test --- .../Http/Middleware/API/SetSessionDriverTest.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/Unit/Http/Middleware/API/SetSessionDriverTest.php b/tests/Unit/Http/Middleware/API/SetSessionDriverTest.php index 0f33f6735..36f1bc0b8 100644 --- a/tests/Unit/Http/Middleware/API/SetSessionDriverTest.php +++ b/tests/Unit/Http/Middleware/API/SetSessionDriverTest.php @@ -37,8 +37,8 @@ class SetSessionDriverTest extends MiddlewareTestCase */ public function testProductionEnvironment() { - $this->appMock->shouldReceive('environment')->withNoArgs()->once()->andReturn('production'); - $this->config->shouldReceive('set')->with('session.driver', 'array')->once()->andReturnNull(); + $this->config->shouldReceive('get')->once()->with('app.debug')->andReturn(false); + $this->config->shouldReceive('set')->once()->with('session.driver', 'array')->andReturnNull(); $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); } @@ -48,11 +48,10 @@ class SetSessionDriverTest extends MiddlewareTestCase */ public function testLocalEnvironment() { - $this->appMock->shouldReceive('environment')->withNoArgs()->once()->andReturn('local'); - $this->appMock->shouldReceive('make')->with(LaravelDebugbar::class)->once()->andReturnSelf(); - $this->appMock->shouldReceive('disable')->withNoArgs()->once()->andReturnNull(); - - $this->config->shouldReceive('set')->with('session.driver', 'array')->once()->andReturnNull(); + $this->config->shouldReceive('get')->once()->with('app.debug')->andReturn(true); + $this->appMock->shouldReceive('make')->once()->with(LaravelDebugbar::class)->andReturnSelf(); + $this->appMock->shouldReceive('disable')->once()->withNoArgs()->andReturnNull(); + $this->config->shouldReceive('set')->once()->with('session.driver', 'array')->andReturnNull(); $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); } From 40c74ae1e7d67fd2ed319191bec10ce38df321fd Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 10 Mar 2018 13:10:40 -0600 Subject: [PATCH 18/33] Add validation to prevent invalid ports, closes #1034 --- CHANGELOG.md | 1 + .../Allocation/CidrOutOfRangeException.php | 16 ++ .../InvalidPortMappingException.php | 18 ++ .../Allocation/PortOutOfRangeException.php | 16 ++ .../TooManyPortsInRangeException.php | 16 ++ .../Controllers/Admin/NodesController.php | 5 +- .../Nodes/AllocationController.php | 5 +- .../Allocations/AssignmentService.php | 55 +++-- resources/lang/en/exceptions.php | 3 +- .../Allocations/AssignmentServiceTest.php | 222 ++++++++---------- 10 files changed, 205 insertions(+), 152 deletions(-) create mode 100644 app/Exceptions/Service/Allocation/CidrOutOfRangeException.php create mode 100644 app/Exceptions/Service/Allocation/InvalidPortMappingException.php create mode 100644 app/Exceptions/Service/Allocation/PortOutOfRangeException.php create mode 100644 app/Exceptions/Service/Allocation/TooManyPortsInRangeException.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 17ab8f05c..1c7c91194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Correct permissions check in UI to allow subusers with permission to `view-allocations` the ability to actually see the sidebar link. * Fixes improper behavior when marking an egg as copying the configuration from another. * Debug bar is only checked when the app is set to debug mode in the API session handler, rather than when it is in local mode to match the plugin settings. +* Added validation to port allocations to prevent allocation of restricted or invalid ports. ### Changed * Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. diff --git a/app/Exceptions/Service/Allocation/CidrOutOfRangeException.php b/app/Exceptions/Service/Allocation/CidrOutOfRangeException.php new file mode 100644 index 000000000..4852dc106 --- /dev/null +++ b/app/Exceptions/Service/Allocation/CidrOutOfRangeException.php @@ -0,0 +1,16 @@ + $port])); + } +} diff --git a/app/Exceptions/Service/Allocation/PortOutOfRangeException.php b/app/Exceptions/Service/Allocation/PortOutOfRangeException.php new file mode 100644 index 000000000..695925f89 --- /dev/null +++ b/app/Exceptions/Service/Allocation/PortOutOfRangeException.php @@ -0,0 +1,16 @@ +. - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ namespace Pterodactyl\Services\Allocations; use IPTools\Network; use Pterodactyl\Models\Node; use Illuminate\Database\ConnectionInterface; -use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface; +use Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException; +use Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException; +use Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException; +use Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException; class AssignmentService { const CIDR_MAX_BITS = 27; const CIDR_MIN_BITS = 32; + const PORT_FLOOR = 1024; + const PORT_CEIL = 65535; const PORT_RANGE_LIMIT = 1000; - const PORT_RANGE_REGEX = '/^(\d{1,5})-(\d{1,5})$/'; + const PORT_RANGE_REGEX = '/^(\d{4,5})-(\d{4,5})$/'; /** * @var \Illuminate\Database\ConnectionInterface @@ -38,10 +36,8 @@ class AssignmentService * @param \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface $repository * @param \Illuminate\Database\ConnectionInterface $connection */ - public function __construct( - AllocationRepositoryInterface $repository, - ConnectionInterface $connection - ) { + public function __construct(AllocationRepositoryInterface $repository, ConnectionInterface $connection) + { $this->connection = $connection; $this->repository = $repository; } @@ -49,21 +45,20 @@ class AssignmentService /** * Insert allocations into the database and link them to a specific node. * - * @param int|\Pterodactyl\Models\Node $node - * @param array $data + * @param \Pterodactyl\Models\Node $node + * @param array $data * - * @throws \Pterodactyl\Exceptions\DisplayException + * @throws \Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException + * @throws \Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException + * @throws \Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException + * @throws \Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException */ - public function handle($node, array $data) + public function handle(Node $node, array $data) { - if ($node instanceof Node) { - $node = $node->id; - } - $explode = explode('/', $data['allocation_ip']); if (count($explode) !== 1) { if (! ctype_digit($explode[1]) || ($explode[1] > self::CIDR_MIN_BITS || $explode[1] < self::CIDR_MAX_BITS)) { - throw new DisplayException(trans('exceptions.allocations.cidr_out_of_range')); + throw new CidrOutOfRangeException; } } @@ -71,7 +66,7 @@ class AssignmentService foreach (Network::parse(gethostbyname($data['allocation_ip'])) as $ip) { foreach ($data['allocation_ports'] as $port) { if (! is_digit($port) && ! preg_match(self::PORT_RANGE_REGEX, $port)) { - throw new DisplayException(trans('exceptions.allocations.invalid_mapping', ['port' => $port])); + throw new InvalidPortMappingException($port); } $insertData = []; @@ -79,12 +74,16 @@ class AssignmentService $block = range($matches[1], $matches[2]); if (count($block) > self::PORT_RANGE_LIMIT) { - throw new DisplayException(trans('exceptions.allocations.too_many_ports')); + throw new TooManyPortsInRangeException; + } + + if ((int) $matches[1] <= self::PORT_FLOOR || (int) $matches[2] > self::PORT_CEIL) { + throw new PortOutOfRangeException; } foreach ($block as $unit) { $insertData[] = [ - 'node_id' => $node, + 'node_id' => $node->id, 'ip' => $ip->__toString(), 'port' => (int) $unit, 'ip_alias' => array_get($data, 'allocation_alias'), @@ -92,8 +91,12 @@ class AssignmentService ]; } } else { + if ((int) $port <= self::PORT_FLOOR || (int) $port > self::PORT_CEIL) { + throw new PortOutOfRangeException; + } + $insertData[] = [ - 'node_id' => $node, + 'node_id' => $node->id, 'ip' => $ip->__toString(), 'port' => (int) $port, 'ip_alias' => array_get($data, 'allocation_alias'), diff --git a/resources/lang/en/exceptions.php b/resources/lang/en/exceptions.php index 73b910d0d..96395baed 100644 --- a/resources/lang/en/exceptions.php +++ b/resources/lang/en/exceptions.php @@ -8,9 +8,10 @@ return [ ], 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', - 'too_many_ports' => 'Adding more than 1000 ports at a single time is not supported. Please use a smaller range.', + 'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.', 'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.', 'cidr_out_of_range' => 'CIDR notation only allows masks between /25 and /32.', + 'port_out_of_range' => 'Ports in an allocation must be greater than 1024 and less than or equal to 65535.', ], 'nest' => [ 'delete_has_servers' => 'A Nest with active servers attached to it cannot be deleted from the Panel.', diff --git a/tests/Unit/Services/Allocations/AssignmentServiceTest.php b/tests/Unit/Services/Allocations/AssignmentServiceTest.php index 805b789a3..7a4eb067c 100644 --- a/tests/Unit/Services/Allocations/AssignmentServiceTest.php +++ b/tests/Unit/Services/Allocations/AssignmentServiceTest.php @@ -1,30 +1,19 @@ . - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ namespace Tests\Unit\Services\Allocations; use Exception; use Mockery as m; use Tests\TestCase; -use phpmock\phpunit\PHPMock; use Pterodactyl\Models\Node; use Illuminate\Database\ConnectionInterface; -use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Services\Allocations\AssignmentService; use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface; class AssignmentServiceTest extends TestCase { - use PHPMock; - /** - * @var \Illuminate\Database\ConnectionInterface + * @var \Illuminate\Database\ConnectionInterface|\Mockery\Mock */ protected $connection; @@ -34,15 +23,10 @@ class AssignmentServiceTest extends TestCase protected $node; /** - * @var \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface + * @var \Pterodactyl\Contracts\Repository\AllocationRepositoryInterface|\Mockery\Mock */ protected $repository; - /** - * @var \Pterodactyl\Services\Allocations\AssignmentService - */ - protected $service; - /** * Setup tests. */ @@ -50,19 +34,9 @@ class AssignmentServiceTest extends TestCase { parent::setUp(); - // Due to a bug in PHP, this is necessary since we only have a single test - // that relies on this mock. If this does not exist the test will fail to register - // correctly. - // - // This can also be avoided if tests were run in isolated processes, or if that test - // came first, but neither of those are good solutions, so this is the next best option. - PHPMock::defineFunctionMock('\\Pterodactyl\\Services\\Allocations', 'gethostbyname'); - $this->node = factory(Node::class)->make(); $this->connection = m::mock(ConnectionInterface::class); $this->repository = m::mock(AllocationRepositoryInterface::class); - - $this->service = new AssignmentService($this->repository, $this->connection); } /** @@ -72,22 +46,22 @@ class AssignmentServiceTest extends TestCase { $data = [ 'allocation_ip' => '192.168.1.1', - 'allocation_ports' => ['1024'], + 'allocation_ports' => ['2222'], ]; - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); + $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); $this->repository->shouldReceive('insertIgnore')->with([ [ 'node_id' => $this->node->id, 'ip' => '192.168.1.1', - 'port' => 1024, + 'port' => 2222, 'ip_alias' => null, 'server_id' => null, ], ])->once()->andReturn(true); - $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); + $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - $this->service->handle($this->node->id, $data); + $this->getService()->handle($this->node, $data); } /** @@ -97,18 +71,11 @@ class AssignmentServiceTest extends TestCase { $data = [ 'allocation_ip' => '192.168.1.1', - 'allocation_ports' => ['1024-1026'], + 'allocation_ports' => ['1025-1027'], ]; - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->with([ - [ - 'node_id' => $this->node->id, - 'ip' => '192.168.1.1', - 'port' => 1024, - 'ip_alias' => null, - 'server_id' => null, - ], + $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); + $this->repository->shouldReceive('insertIgnore')->once()->with([ [ 'node_id' => $this->node->id, 'ip' => '192.168.1.1', @@ -123,10 +90,17 @@ class AssignmentServiceTest extends TestCase 'ip_alias' => null, 'server_id' => null, ], - ])->once()->andReturn(true); - $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); + [ + 'node_id' => $this->node->id, + 'ip' => '192.168.1.1', + 'port' => 1027, + 'ip_alias' => null, + 'server_id' => null, + ], + ])->andReturn(true); + $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - $this->service->handle($this->node->id, $data); + $this->getService()->handle($this->node, $data); } /** @@ -136,23 +110,23 @@ class AssignmentServiceTest extends TestCase { $data = [ 'allocation_ip' => '192.168.1.1', - 'allocation_ports' => ['1024'], + 'allocation_ports' => ['2222'], 'allocation_alias' => 'my.alias.net', ]; - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->with([ + $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); + $this->repository->shouldReceive('insertIgnore')->once()->with([ [ 'node_id' => $this->node->id, 'ip' => '192.168.1.1', - 'port' => 1024, + 'port' => 2222, 'ip_alias' => 'my.alias.net', 'server_id' => null, ], - ])->once()->andReturn(true); - $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); + ])->andReturn(true); + $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - $this->service->handle($this->node->id, $data); + $this->getService()->handle($this->node, $data); } /** @@ -161,26 +135,23 @@ class AssignmentServiceTest extends TestCase public function testDomainNamePassedInPlaceOfIPAddress() { $data = [ - 'allocation_ip' => 'test-domain.com', - 'allocation_ports' => ['1024'], + 'allocation_ip' => 'unit-test-static.pterodactyl.io', + 'allocation_ports' => ['2222'], ]; - $this->getFunctionMock('\\Pterodactyl\\Services\\Allocations', 'gethostbyname') - ->expects($this->once())->willReturn('192.168.1.1'); - - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->with([ + $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); + $this->repository->shouldReceive('insertIgnore')->once()->with([ [ 'node_id' => $this->node->id, - 'ip' => '192.168.1.1', - 'port' => 1024, + 'ip' => '127.0.0.1', + 'port' => 2222, 'ip_alias' => null, 'server_id' => null, ], - ])->once()->andReturn(true); - $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); + ])->andReturn(true); + $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - $this->service->handle($this->node->id, $data); + $this->getService()->handle($this->node, $data); } /** @@ -190,54 +161,55 @@ class AssignmentServiceTest extends TestCase { $data = [ 'allocation_ip' => '192.168.1.100/31', - 'allocation_ports' => ['1024'], + 'allocation_ports' => ['2222'], ]; - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->with([ + $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); + $this->repository->shouldReceive('insertIgnore')->once()->with([ [ 'node_id' => $this->node->id, 'ip' => '192.168.1.100', - 'port' => 1024, + 'port' => 2222, 'ip_alias' => null, 'server_id' => null, ], - ])->once()->andReturn(true); + ])->andReturn(true); - $this->repository->shouldReceive('insertIgnore')->with([ + $this->repository->shouldReceive('insertIgnore')->once()->with([ [ 'node_id' => $this->node->id, 'ip' => '192.168.1.101', - 'port' => 1024, + 'port' => 2222, 'ip_alias' => null, 'server_id' => null, ], - ])->once()->andReturn(true); - $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); + ])->andReturn(true); + $this->connection->shouldReceive('commit')->once()->withNoArgs()->andReturnNull(); - $this->service->handle($this->node->id, $data); + $this->getService()->handle($this->node, $data); } /** * Test that a CIDR IP address with a range works properly. + * + * @expectedException \Pterodactyl\Exceptions\Service\Allocation\CidrOutOfRangeException + * @expectedExceptionMessage CIDR notation only allows masks between /25 and /32. */ public function testCIDRNotatedIPAddressOutsideRangeLimit() { $data = [ 'allocation_ip' => '192.168.1.100/20', - 'allocation_ports' => ['1024'], + 'allocation_ports' => ['2222'], ]; - try { - $this->service->handle($this->node->id, $data); - } catch (Exception $exception) { - $this->assertInstanceOf(DisplayException::class, $exception); - $this->assertEquals(trans('exceptions.allocations.cidr_out_of_range'), $exception->getMessage()); - } + $this->getService()->handle($this->node, $data); } /** * Test that an exception is thrown if there are too many ports. + * + * @expectedException \Pterodactyl\Exceptions\Service\Allocation\TooManyPortsInRangeException + * @expectedExceptionMessage Adding more than 1000 ports in a single range at once is not supported. */ public function testAllocationWithPortsExceedingLimit() { @@ -246,22 +218,16 @@ class AssignmentServiceTest extends TestCase 'allocation_ports' => ['5000-7000'], ]; - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); + $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); - try { - $this->service->handle($this->node->id, $data); - } catch (Exception $exception) { - if (! $exception instanceof DisplayException) { - throw $exception; - } - - $this->assertInstanceOf(DisplayException::class, $exception); - $this->assertEquals(trans('exceptions.allocations.too_many_ports'), $exception->getMessage()); - } + $this->getService()->handle($this->node, $data); } /** * Test that an exception is thrown if an invalid port is provided. + * + * @expectedException \Pterodactyl\Exceptions\Service\Allocation\InvalidPortMappingException + * @expectedExceptionMessage The mapping provided for test123 was invalid and could not be processed. */ public function testInvalidPortProvided() { @@ -270,42 +236,52 @@ class AssignmentServiceTest extends TestCase 'allocation_ports' => ['test123'], ]; - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); - - try { - $this->service->handle($this->node->id, $data); - } catch (Exception $exception) { - if (! $exception instanceof DisplayException) { - throw $exception; - } - - $this->assertInstanceOf(DisplayException::class, $exception); - $this->assertEquals(trans('exceptions.allocations.invalid_mapping', ['port' => 'test123']), $exception->getMessage()); - } + $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); + $this->getService()->handle($this->node, $data); } /** - * Test that a model can be passed in place of an ID. + * Test that ports outside of defined limits throw an error. + * + * @param array $ports + * + * @dataProvider invalidPortsDataProvider + * @expectedException \Pterodactyl\Exceptions\Service\Allocation\PortOutOfRangeException + * @expectedExceptionMessage Ports in an allocation must be greater than 1024 and less than or equal to 65535. */ - public function testModelCanBePassedInPlaceOfNodeModel() + public function testPortRangeOutsideOfRangeLimits(array $ports) { - $data = [ - 'allocation_ip' => '192.168.1.1', - 'allocation_ports' => ['1024'], + $data = ['allocation_ip' => '192.168.1.1', 'allocation_ports' => $ports]; + + $this->connection->shouldReceive('beginTransaction')->once()->withNoArgs()->andReturnNull(); + $this->getService()->handle($this->node, $data); + } + + /** + * Provide ports and ranges of ports that exceed the viable port limits for the software. + * + * @return array + */ + public function invalidPortsDataProvider(): array + { + return [ + [['65536']], + [['1024']], + [['1000']], + [['0']], + [['65530-65540']], + [['65540-65560']], + [[PHP_INT_MAX]], ]; + } - $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); - $this->repository->shouldReceive('insertIgnore')->with([ - [ - 'node_id' => $this->node->id, - 'ip' => '192.168.1.1', - 'port' => 1024, - 'ip_alias' => null, - 'server_id' => null, - ], - ])->once()->andReturn(true); - $this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull(); - - $this->service->handle($this->node, $data); + /** + * Returns an instance of the service with mocked dependencies for testing. + * + * @return \Pterodactyl\Services\Allocations\AssignmentService + */ + private function getService(): AssignmentService + { + return new AssignmentService($this->repository, $this->connection); } } From 08a112f027a50852f4870643b656dbf093f101f9 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 10 Mar 2018 13:19:46 -0600 Subject: [PATCH 19/33] Include trailing slash on modal, closes #864 --- CHANGELOG.md | 1 + resources/themes/pterodactyl/server/files/list.blade.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c7c91194..75cb796c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * File manager UI improved to be clearer with buttons and cleaner on mobile. * reCAPTCHA's secret key position swapped with website key in advanced panel settings to be consistent with Google's reCAPTCHA dashboard. * Changed DisplayException to handle its own logging correctly and check if the previous exception is marked as one that should not be logged. +* Changed 'New Folder' modal in file manager to include a trailing slash. ## v0.7.5 (Derelict Dermodactylus) ### Fixed diff --git a/resources/themes/pterodactyl/server/files/list.blade.php b/resources/themes/pterodactyl/server/files/list.blade.php index 18d5481df..e4e88b606 100644 --- a/resources/themes/pterodactyl/server/files/list.blade.php +++ b/resources/themes/pterodactyl/server/files/list.blade.php @@ -29,7 +29,7 @@
    -
    - + + @lang('server.files.file_name')@lang('server.files.file_name')
    ← {{ $directory['link_show'] }}
    + + {{ $folder['entry'] }} + +
    + {{-- oh boy --}} @if(in_array($file['mime'], [ 'application/x-7z-compressed', @@ -156,7 +160,9 @@ {{ $carbon->diffForHumans() }} @endif + +
    +
    From abd2a4247141e0cc371bfd18ac4d04ac58bbbb03 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 10 Mar 2018 13:55:24 -0600 Subject: [PATCH 20/33] Fix data integrity exception thrown when attempting to store updated server egg variables --- CHANGELOG.md | 1 + app/Services/Servers/StartupModificationService.php | 2 +- .../Servers/StartupModificationServiceTest.php | 12 ++++++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75cb796c6..77cad6222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Fixes improper behavior when marking an egg as copying the configuration from another. * Debug bar is only checked when the app is set to debug mode in the API session handler, rather than when it is in local mode to match the plugin settings. * Added validation to port allocations to prevent allocation of restricted or invalid ports. +* Fix data integrity exception thrown when attempting to store updated server egg variables. ### Changed * Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. diff --git a/app/Services/Servers/StartupModificationService.php b/app/Services/Servers/StartupModificationService.php index 4e954ae1f..9fa1390db 100644 --- a/app/Services/Servers/StartupModificationService.php +++ b/app/Services/Servers/StartupModificationService.php @@ -105,7 +105,7 @@ class StartupModificationService 'server_id' => $server->id, 'variable_id' => $result->id, ], [ - 'variable_value' => $result->value, + 'variable_value' => $result->value ?? '', ]); }); } diff --git a/tests/Unit/Services/Servers/StartupModificationServiceTest.php b/tests/Unit/Services/Servers/StartupModificationServiceTest.php index 99453e515..5b6046753 100644 --- a/tests/Unit/Services/Servers/StartupModificationServiceTest.php +++ b/tests/Unit/Services/Servers/StartupModificationServiceTest.php @@ -121,14 +121,18 @@ class StartupModificationServiceTest extends TestCase $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); $this->validatorService->shouldReceive('setUserLevel')->with(User::USER_LEVEL_ADMIN)->once()->andReturnNull(); $this->validatorService->shouldReceive('handle')->with(456, ['test' => 'abcd1234'])->once()->andReturn( - collect([(object) ['id' => 1, 'value' => 'stored-value']]) + collect([(object) ['id' => 1, 'value' => 'stored-value'], (object) ['id' => 2, 'value' => null]]) ); - $this->serverVariableRepository->shouldReceive('withoutFreshModel')->withNoArgs()->once()->andReturnSelf(); - $this->serverVariableRepository->shouldReceive('updateOrCreate')->with([ + $this->serverVariableRepository->shouldReceive('withoutFreshModel->updateOrCreate')->once()->with([ 'server_id' => $model->id, 'variable_id' => 1, - ], ['variable_value' => 'stored-value'])->once()->andReturnNull(); + ], ['variable_value' => 'stored-value'])->andReturnNull(); + + $this->serverVariableRepository->shouldReceive('withoutFreshModel->updateOrCreate')->once()->with([ + 'server_id' => $model->id, + 'variable_id' => 2, + ], ['variable_value' => ''])->andReturnNull(); $this->eggRepository->shouldReceive('setColumns->find')->once()->with($eggModel->id)->andReturn($eggModel); From e55d3c1a9a0d1e8a8cafc07a1d32244fac3b089b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 10 Mar 2018 14:26:00 -0600 Subject: [PATCH 21/33] Add check on SFTP page to make sure the permission is assigned before showing --- CHANGELOG.md | 1 + app/Http/Controllers/Server/Settings/SftpController.php | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77cad6222..e6e4e33d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Debug bar is only checked when the app is set to debug mode in the API session handler, rather than when it is in local mode to match the plugin settings. * Added validation to port allocations to prevent allocation of restricted or invalid ports. * Fix data integrity exception thrown when attempting to store updated server egg variables. +* Added missing permissions check on 'SFTP Configuration' page to ensure user has permission to access a server's SFTP server before showing a user credentials. ### Changed * Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. diff --git a/app/Http/Controllers/Server/Settings/SftpController.php b/app/Http/Controllers/Server/Settings/SftpController.php index b128ba5c9..58b110bd3 100644 --- a/app/Http/Controllers/Server/Settings/SftpController.php +++ b/app/Http/Controllers/Server/Settings/SftpController.php @@ -16,9 +16,12 @@ class SftpController extends Controller * * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View + * + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function index(Request $request): View { + $this->authorize('access-sftp', $request->attributes->get('server')); $this->setRequest($request)->injectJavascript(); return view('server.settings.sftp'); From f8e98e9c9ea6d5729d0e940e7ac477e7c86a60bd Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 10 Mar 2018 14:44:21 -0600 Subject: [PATCH 22/33] Add ability to change server name, closes #563 --- CHANGELOG.md | 3 + .../Server/Settings/NameController.php | 59 +++++++++++++++++++ .../Settings/ChangeServerNameRequest.php | 31 ++++++++++ resources/lang/en/navigation.php | 1 + resources/lang/en/server.php | 5 ++ .../pterodactyl/layouts/master.blade.php | 3 + .../server/settings/name.blade.php | 50 ++++++++++++++++ routes/server.php | 7 ++- 8 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 app/Http/Controllers/Server/Settings/NameController.php create mode 100644 app/Http/Requests/Server/Settings/ChangeServerNameRequest.php create mode 100644 resources/themes/pterodactyl/server/settings/name.blade.php diff --git a/CHANGELOG.md b/CHANGELOG.md index e6e4e33d0..e8a60ce46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Fix data integrity exception thrown when attempting to store updated server egg variables. * Added missing permissions check on 'SFTP Configuration' page to ensure user has permission to access a server's SFTP server before showing a user credentials. +### Added +* Added ability for end users to change the name of their server through the UI. This option is only open to the server owner or an admin. + ### Changed * Panel now throws proper 504: Gateway Timeout errors on server listing when daemon is offline. * Sessions handled through redis now use a seperate database (default `1`) to store session database to avoid logging users out when flushing the cache. diff --git a/app/Http/Controllers/Server/Settings/NameController.php b/app/Http/Controllers/Server/Settings/NameController.php new file mode 100644 index 000000000..29cdb9ed9 --- /dev/null +++ b/app/Http/Controllers/Server/Settings/NameController.php @@ -0,0 +1,59 @@ +repository = $repository; + } + + /** + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function index(Request $request) + { + $this->authorize('view-name', $request->attributes->get('server')); + $this->setRequest($request)->injectJavascript(); + + return view('server.settings.name'); + } + + /** + * Update the stored name for a specific server. + * + * @param \Pterodactyl\Http\Requests\Server\Settings\ChangeServerNameRequest $request + * @return \Illuminate\Http\RedirectResponse + * + * @throws \Pterodactyl\Exceptions\Model\DataValidationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function update(ChangeServerNameRequest $request): RedirectResponse + { + $this->repository->update($request->getServer()->id, $request->validated()); + + return redirect()->route('server.settings.name', $request->getServer()->uuidShort); + } +} diff --git a/app/Http/Requests/Server/Settings/ChangeServerNameRequest.php b/app/Http/Requests/Server/Settings/ChangeServerNameRequest.php new file mode 100644 index 000000000..c969cb0e2 --- /dev/null +++ b/app/Http/Requests/Server/Settings/ChangeServerNameRequest.php @@ -0,0 +1,31 @@ + Server::getCreateRules()['name'], + ]; + } +} diff --git a/resources/lang/en/navigation.php b/resources/lang/en/navigation.php index f8a9deebb..c97c18a78 100644 --- a/resources/lang/en/navigation.php +++ b/resources/lang/en/navigation.php @@ -27,5 +27,6 @@ return [ 'edit_file' => 'Edit File', 'admin_header' => 'ADMINISTRATIVE', 'admin' => 'Server Configuration', + 'server_name' => 'Server Name', ], ]; diff --git a/resources/lang/en/server.php b/resources/lang/en/server.php index 76002aedf..b84f76387 100644 --- a/resources/lang/en/server.php +++ b/resources/lang/en/server.php @@ -289,6 +289,11 @@ return [ ], ], 'config' => [ + 'name' => [ + 'header' => 'Server Name', + 'header_sub' => 'Change this server\'s name.', + 'details' => 'The server name is only a reference to this server on the panel, and will not affect any server specific configurations that may display to users in games.', + ], 'startup' => [ 'header' => 'Start Configuration', 'header_sub' => 'Control server startup arguments.', diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 32b75823a..020f8b637 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -184,6 +184,9 @@