From e576eb27bf1ea47d8151020d9d8c4db5466ea15e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 29 Aug 2020 15:48:57 -0700 Subject: [PATCH 01/46] Update README.md --- README.md | 75 +++++++++++++++++++++++-------------------------------- 1 file changed, 31 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 3fab319b..18121a3f 100644 --- a/README.md +++ b/README.md @@ -6,48 +6,40 @@ [![Discord](https://img.shields.io/discord/122900397965705216.svg?style=flat-square&label=Discord)](https://pterodactyl.io/discord) # Pterodactyl Panel +Pterodactyl is an open-source game server management panel built with PHP 7, React, and Go. Designed with security +in mind, Pterodactyl runs all game servers in isolated Docker container while exposing a beautiful and intuitive +UI to end users. -Pterodactyl is the open-source game server management panel built with PHP7, Nodejs, and Go. Designed with security in mind, Pterodactyl runs all game servers in isolated Docker containers while exposing a beautiful and intuitive UI to administrators and users. -What more are you waiting for? Make game servers a first class citizen on your platform today. +Stop settling for less. Make game servers a first class citizen on your platform. ![Image](https://cdn.pterodactyl.io/site-assets/mockup-macbook-grey.png) ## Sponsors -I would like to extend my sincere thanks to the following sponsors for funding Pterodactyl's developement. [Interested -in becoming a sponsor?](https://github.com/sponsors/DaneEveritt) +I would like to extend my sincere thanks to the following sponsors for helping find Pterodactyl's developement. +[Interested in becoming a sponsor?](https://github.com/sponsors/DaneEveritt) -#### [BloomVPS](https://bloomvps.com) -> BloomVPS offers dedicated core VPS and Minecraft hosting with Ryzen 9 processors. With owned-hardware, we offer truly -> unbeatable prices on high-performance hosting. +| Company | About | +| ------- | ----- | +| [**BloomVPS**](https://bloomvps.com) | BloomVPS offers dedicated core VPS and Minecraft hosting with Ryzen 9 processors. With owned-hardware, we offer truly unbeatable prices on high-performance hosting. | +| [**VersatileNode**](https://versatilenode.com/) | Looking to host a minecraft server, vps, or a website? VersatileNode is one of the most affordable hosting providers to provide quality yet cheap services with incredible support. | +| [**MineStrator**](https://minestrator.com/) | Looking for a French highend hosting company for you minecraft server? More than 14,000 members on our discord, trust us. | +| [**DedicatedMC**](https://dedicatedmc.io/) | DedicatedMC provides Raw Power hosting at affordable pricing, making sure to never compromise on your performance and giving you the best performance money can buy. | +| [**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! | +| [**XCORE-SERVER.de**](https://xcore-server.de/) | XCORE-SERVER.de offers High-End Servers for hosting and gaming since 2012. Fast, excellent and well-known for eSports Gaming. | -#### [VersatileNode](https://versatilenode.com/) -> Looking to host a minecraft server, vps, or a website? VersatileNode is one of the most affordable hosting providers -> to provide quality yet cheap services with incredible support. - -#### [MineStrator](https://minestrator.com/) -> Looking for a French highend hosting company for you minecraft server? More than 14,000 members on our discord -> trust us. - -#### [DedicatedMC](https://dedicatedmc.io/) -> DedicatedMC provides Raw Power hosting at affordable pricing, making sure to never compromise on your performance -> and giving you the best performance money can buy. - -#### [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! - -#### [XCORE-SERVER.de](https://xcore-server.de) -> XCORE-SERVER.de offers High-End Servers for hosting and gaming since 2012. Fast, excellent and well known for eSports Gaming. - -## Support & Documentation -Support for using Pterodactyl can be found on our [Documentation Website](https://pterodactyl.io/project/introduction.html), [Guides Website](https://pterodactyl.io/community/about.html), or via our [Discord Chat](https://discord.gg/QRDZvVm). +## Documentation +* [Panel Documentation](https://pterodactyl.io/panel/1.0/getting_started.html) +* [Wings Documentation](https://pterodactyl.io/wings/1.0/installing.html) +* [Community Guides](https://pterodactyl.io/community/about.html) +* Or, get additional help [via Discord](https://discord.gg/pterodactyl) ### Supported Games -We support a huge variety of games by utilizing Docker containers to isolate each instance, giving you the power to host your games across the world without having to bloat each physical machine with additional dependencies. +We support a huge variety of games by utilizing Docker containers to isolate each instance, giving you the power to +host your games across the world without having to bloat each physical machine with additional dependencies. Some of our core supported games include: -* Minecraft — including Spigot, Sponge, Bungeecord, Waterfall, and more +* Minecraft — including Paper, Sponge, Bungeecord, Waterfall, and more * Rust * Terraria * Teamspeak @@ -57,7 +49,8 @@ Some of our core supported games include: * Garry's Mod * ARK: Survival Evolved -In addition to our standard nest of supported games, our community is constantly pushing the limits of this software and there are plenty more games available provided by the community. Some of these games include: +In addition to our standard nest of supported games, our community is constantly pushing the limits of this software +and there are plenty more games available provided by the community. Some of these games include: * Factorio * San Andreas: MP @@ -65,22 +58,13 @@ In addition to our standard nest of supported games, our community is constantly * Squad * FiveM * Xonotic -* Discord ATLBot - -## Credits -This software would not be possible without the work of other open-source authors who provide tools such as: - -[Ace Editor](https://ace.c9.io), [AdminLTE](https://adminlte.io), [Animate.css](http://daneden.github.io/animate.css/), [AnsiUp](https://github.com/drudru/ansi_up), [Async.js](https://github.com/caolan/async), -[Bootstrap](http://getbootstrap.com), [Bootstrap Notify](http://bootstrap-notify.remabledesigns.com), [Chart.js](http://www.chartjs.org), [FontAwesome](http://fontawesome.io), -[FontAwesome Animations](https://github.com/l-lin/font-awesome-animation), [jQuery](http://jquery.com), [Laravel](https://laravel.com), [Lodash](https://lodash.com), -[Select2](https://select2.github.io), [Socket.io](http://socket.io), [Socket.io File Upload](https://github.com/vote539/socketio-file-upload), [SweetAlert](http://t4t5.github.io/sweetalert), -[Typeahead](https://github.com/bassjobsen/Bootstrap-3-Typeahead), and [Particles.js](http://vincentgarreau.com/particles.js). - -Some Javascript and CSS used within the panel is licensed under a `MIT` or `Apache 2.0` license. Please check their respective header files for more information. +* Starmade +* Discord ATLBot, and most other Node.js/Python discord bots +* [and many more...](https://github.com/parkervcp/eggs) ## License ``` -Copyright (c) 2015 - 2018 Dane Everitt . +Copyright (c) 2015 - 2020 Dane Everitt & Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -100,3 +84,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` + +Some Javascript and CSS used within the panel are licensed under a `MIT` or `Apache 2.0` license. Please check their +respective header files for more information. From 0f6a307bc9a493fe82099f9367f9555895ea455b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 29 Aug 2020 16:08:22 -0700 Subject: [PATCH 02/46] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 18121a3f..c1fa644e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ UI to end users. Stop settling for less. Make game servers a first class citizen on your platform. -![Image](https://cdn.pterodactyl.io/site-assets/mockup-macbook-grey.png) +![Image](https://cdn.pterodactyl.io/site-assets/pterodactyl_v1_demo.gif) ## Sponsors I would like to extend my sincere thanks to the following sponsors for helping find Pterodactyl's developement. From cd9494251b224aef8f3d5cca6c55704a960e2314 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 29 Aug 2020 16:09:51 -0700 Subject: [PATCH 03/46] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c1fa644e..861df265 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ [![Logo Image](https://cdn.pterodactyl.io/logos/new/pterodactyl_logo.png)](https://pterodactyl.io) [![Build status](https://img.shields.io/travis/pterodactyl/panel/develop.svg?style=flat-square)](https://travis-ci.org/pterodactyl/panel) -[![StyleCI](https://styleci.io/repos/47508644/shield?branch=develop)](https://styleci.io/repos/47508644) [![Codecov](https://img.shields.io/codecov/c/github/pterodactyl/panel/develop.svg?style=flat-square)](https://codecov.io/gh/Pterodactyl/Panel) [![Discord](https://img.shields.io/discord/122900397965705216.svg?style=flat-square&label=Discord)](https://pterodactyl.io/discord) From 4ee19b6847e5117bb0e828e821db26476c21659a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 29 Aug 2020 18:20:12 -0700 Subject: [PATCH 04/46] Tweak UI for dashboard --- .../components/dashboard/ServerRow.tsx | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/resources/scripts/components/dashboard/ServerRow.tsx b/resources/scripts/components/dashboard/ServerRow.tsx index a504f195..819e6663 100644 --- a/resources/scripts/components/dashboard/ServerRow.tsx +++ b/resources/scripts/components/dashboard/ServerRow.tsx @@ -59,20 +59,13 @@ export default ({ server, className }: { server: Server; className?: string }) =
-
-
-

{server.name}

-
+

{server.name}

+ {!!server.description && +

{server.description}

+ }
-
-
+
+

{ From 6a442c1fd3f838f73eba426c9f787cf6c931bf06 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 30 Aug 2020 09:40:19 -0700 Subject: [PATCH 05/46] Don't send along egg information unecessarily --- .../Servers/ServerConfigurationStructureService.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/Services/Servers/ServerConfigurationStructureService.php b/app/Services/Servers/ServerConfigurationStructureService.php index fea2eaac..f975f7e8 100644 --- a/app/Services/Servers/ServerConfigurationStructureService.php +++ b/app/Services/Servers/ServerConfigurationStructureService.php @@ -87,6 +87,7 @@ class ServerConfigurationStructureService 'suspended' => (bool) $server->suspended, 'environment' => $this->environment->handle($server), 'invocation' => $server->startup, + 'skip_egg_scripts' => $server->skip_scripts, 'build' => [ 'memory_limit' => $server->memory, 'swap' => $server->swap, @@ -95,11 +96,6 @@ class ServerConfigurationStructureService 'threads' => $server->threads, 'disk_space' => $server->disk, ], - 'service' => [ - 'egg' => $server->egg->uuid, - 'pack' => $server->pack ? $server->pack->uuid : null, - 'skip_scripts' => $server->skip_scripts, - ], 'container' => [ 'image' => $server->image, 'oom_disabled' => $server->oom_disabled, From 906cfce81cce62f1693a8de77b7a6b396faf5a8b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 30 Aug 2020 09:54:59 -0700 Subject: [PATCH 06/46] Don't return a 403 when returning resources for a suspended server; closes #2279 --- .../Api/Client/Server/AuthenticateServerAccess.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/Http/Middleware/Api/Client/Server/AuthenticateServerAccess.php b/app/Http/Middleware/Api/Client/Server/AuthenticateServerAccess.php index 8c10b22d..505f1a30 100644 --- a/app/Http/Middleware/Api/Client/Server/AuthenticateServerAccess.php +++ b/app/Http/Middleware/Api/Client/Server/AuthenticateServerAccess.php @@ -8,6 +8,7 @@ use Pterodactyl\Models\Server; use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Symfony\Component\HttpKernel\Exception\ConflictHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class AuthenticateServerAccess @@ -64,8 +65,10 @@ class AuthenticateServerAccess } } - if ($server->suspended) { - throw new AccessDeniedHttpException('This server is currently suspended and the functionality requested is unavailable.'); + if ($server->suspended && !$request->routeIs('api:client:server.resources')) { + throw new BadRequestHttpException( + 'This server is currently suspended and the functionality requested is unavailable.' + ); } if (! $server->isInstalled()) { From d87438621f69fa46e1cfd2198256afd3ea54a287 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 30 Aug 2020 10:25:48 -0700 Subject: [PATCH 07/46] Don't allow opening of files we know cannot be edited; closes #2286 --- .../Daemon/FileObjectTransformer.php | 11 +-- config/pterodactyl.php | 14 --- .../scripts/api/server/files/loadDirectory.ts | 2 +- resources/scripts/api/transformers.ts | 14 ++- .../components/server/files/FileObjectRow.tsx | 87 +++++++++++-------- .../server/files/NewDirectoryButton.tsx | 2 +- 6 files changed, 65 insertions(+), 65 deletions(-) diff --git a/app/Transformers/Daemon/FileObjectTransformer.php b/app/Transformers/Daemon/FileObjectTransformer.php index acaba0c4..84fcaf2d 100644 --- a/app/Transformers/Daemon/FileObjectTransformer.php +++ b/app/Transformers/Daemon/FileObjectTransformer.php @@ -14,14 +14,6 @@ class FileObjectTransformer extends BaseDaemonTransformer */ private $editable = []; - /** - * FileObjectTransformer constructor. - */ - public function __construct() - { - $this->editable = config('pterodactyl.files.editable', []); - } - /** * Transform a file object response from the daemon into a standardized response. * @@ -36,8 +28,7 @@ class FileObjectTransformer extends BaseDaemonTransformer 'size' => Arr::get($item, 'size'), 'is_file' => Arr::get($item, 'file', true), 'is_symlink' => Arr::get($item, 'symlink', false), - 'is_editable' => in_array(Arr::get($item, 'mime', ''), $this->editable), - 'mimetype' => Arr::get($item, 'mime'), + 'mimetype' => Arr::get($item, 'mime', 'application/octet-stream'), 'created_at' => Carbon::parse(Arr::get($item, 'created', ''))->toIso8601String(), 'modified_at' => Carbon::parse(Arr::get($item, 'modified', ''))->toIso8601String(), ]; diff --git a/config/pterodactyl.php b/config/pterodactyl.php index 671a64fd..75ece65b 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -178,20 +178,6 @@ return [ */ 'files' => [ 'max_edit_size' => env('PTERODACTYL_FILES_MAX_EDIT_SIZE', 1024 * 1024 * 4), - 'editable' => [ - 'application/json', - 'application/javascript', - 'application/xml', - 'application/xhtml+xml', - 'inode/x-empty', - 'text/xml', - 'text/css', - 'text/html', - 'text/plain', - 'text/x-perl', - 'text/x-shellscript', - 'text/x-python', - ], ], /* diff --git a/resources/scripts/api/server/files/loadDirectory.ts b/resources/scripts/api/server/files/loadDirectory.ts index 77e44bce..1caf6bf9 100644 --- a/resources/scripts/api/server/files/loadDirectory.ts +++ b/resources/scripts/api/server/files/loadDirectory.ts @@ -8,11 +8,11 @@ export interface FileObject { size: number; isFile: boolean; isSymlink: boolean; - isEditable: boolean; mimetype: string; createdAt: Date; modifiedAt: Date; isArchiveType: () => boolean; + isEditable: () => boolean; } export default async (uuid: string, directory?: string): Promise => { diff --git a/resources/scripts/api/transformers.ts b/resources/scripts/api/transformers.ts index 595f2b9c..f17787e0 100644 --- a/resources/scripts/api/transformers.ts +++ b/resources/scripts/api/transformers.ts @@ -19,7 +19,6 @@ export const rawDataToFileObject = (data: FractalResponseData): FileObject => ({ size: Number(data.attributes.size), isFile: data.attributes.is_file, isSymlink: data.attributes.is_symlink, - isEditable: data.attributes.is_editable, mimetype: data.attributes.mimetype, createdAt: new Date(data.attributes.created_at), modifiedAt: new Date(data.attributes.modified_at), @@ -39,6 +38,19 @@ export const rawDataToFileObject = (data: FractalResponseData): FileObject => ({ 'application/zip', // .zip ].indexOf(this.mimetype) >= 0; }, + + isEditable: function () { + if (this.isArchiveType() || !this.isFile) return false; + + const matches = [ + 'application/jar', + 'application/octet-stream', + 'inode/directory', + /^image\//, + ]; + + return matches.every(m => !this.mimetype.match(m)); + }, }); export const rawDataToServerBackup = ({ attributes }: FractalResponseData): ServerBackup => ({ diff --git a/resources/scripts/components/server/files/FileObjectRow.tsx b/resources/scripts/components/server/files/FileObjectRow.tsx index 0a14aca8..bb893574 100644 --- a/resources/scripts/components/server/files/FileObjectRow.tsx +++ b/resources/scripts/components/server/files/FileObjectRow.tsx @@ -16,7 +16,7 @@ const Row = styled.div` ${tw`flex bg-neutral-700 rounded-sm mb-px text-sm hover:text-neutral-100 cursor-pointer items-center no-underline hover:bg-neutral-600`}; `; -const FileObjectRow = ({ file }: { file: FileObject }) => { +const Clickable: React.FC<{ file: FileObject }> = memo(({ file, children }) => { const directory = ServerContext.useStoreState(state => state.files.directory); const history = useHistory(); @@ -35,48 +35,59 @@ const FileObjectRow = ({ file }: { file: FileObject }) => { }; return ( - { - e.preventDefault(); - window.dispatchEvent(new CustomEvent(`pterodactyl:files:ctx:${file.key}`, { detail: e.clientX })); - }} - > - + file.isFile && !file.isEditable() ? +

+ {children} +
+ : -
- {file.isFile ? - - : - - } -
-
- {file.name} -
- {file.isFile && -
- {bytesToHuman(file.size)} -
- } -
- {Math.abs(differenceInHours(file.modifiedAt, new Date())) > 48 ? - format(file.modifiedAt, 'MMM do, yyyy h:mma') - : - formatDistanceToNow(file.modifiedAt, { addSuffix: true }) - } -
+ {children}
- - ); -}; +}, isEqual); -export default memo(FileObjectRow, (prevProps, nextProps) => isEqual(prevProps.file, nextProps.file)); +const FileObjectRow = ({ file }: { file: FileObject }) => ( + { + e.preventDefault(); + window.dispatchEvent(new CustomEvent(`pterodactyl:files:ctx:${file.key}`, { detail: e.clientX })); + }} + > + + +
+ {file.isFile ? + + : + + } +
+
+ {file.name} +
+ {file.isFile && +
+ {bytesToHuman(file.size)} +
+ } +
+ {Math.abs(differenceInHours(file.modifiedAt, new Date())) > 48 ? + format(file.modifiedAt, 'MMM do, yyyy h:mma') + : + formatDistanceToNow(file.modifiedAt, { addSuffix: true }) + } +
+
+ +
+); + +export default memo(FileObjectRow, isEqual); diff --git a/resources/scripts/components/server/files/NewDirectoryButton.tsx b/resources/scripts/components/server/files/NewDirectoryButton.tsx index 709fdd5e..8cb82dd9 100644 --- a/resources/scripts/components/server/files/NewDirectoryButton.tsx +++ b/resources/scripts/components/server/files/NewDirectoryButton.tsx @@ -26,12 +26,12 @@ const generateDirectoryData = (name: string): FileObject => ({ mode: '0644', size: 0, isFile: false, - isEditable: false, isSymlink: false, mimetype: '', createdAt: new Date(), modifiedAt: new Date(), isArchiveType: () => false, + isEditable: () => false, }); export default () => { From 981edb0d640e79e111506c9be0f6c1e44503c81a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Mon, 31 Aug 2020 19:36:30 -0700 Subject: [PATCH 08/46] Require specific permission for reading the actual contents of a file; ref #2288 --- .../Api/Remote/FileDownloadController.php | 50 ------------------- .../Servers/Files/GetFileContentsRequest.php | 2 +- app/Models/Permission.php | 4 +- .../components/server/files/FileObjectRow.tsx | 4 +- 4 files changed, 7 insertions(+), 53 deletions(-) delete mode 100644 app/Http/Controllers/Api/Remote/FileDownloadController.php diff --git a/app/Http/Controllers/Api/Remote/FileDownloadController.php b/app/Http/Controllers/Api/Remote/FileDownloadController.php deleted file mode 100644 index fa4818fc..00000000 --- a/app/Http/Controllers/Api/Remote/FileDownloadController.php +++ /dev/null @@ -1,50 +0,0 @@ -cache = $cache; - } - - /** - * Handle a request to authenticate a download using a token and return - * the path of the file to the daemon. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\JsonResponse - * - * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException - */ - public function index(Request $request): JsonResponse - { - $download = $this->cache->pull('Server:Downloads:' . $request->input('token', '')); - - if (is_null($download)) { - throw new NotFoundHttpException('No file was found using the token provided.'); - } - - return response()->json([ - 'path' => array_get($download, 'path'), - 'server' => array_get($download, 'server'), - ]); - } -} diff --git a/app/Http/Requests/Api/Client/Servers/Files/GetFileContentsRequest.php b/app/Http/Requests/Api/Client/Servers/Files/GetFileContentsRequest.php index 25dc4f1e..008b4443 100644 --- a/app/Http/Requests/Api/Client/Servers/Files/GetFileContentsRequest.php +++ b/app/Http/Requests/Api/Client/Servers/Files/GetFileContentsRequest.php @@ -17,7 +17,7 @@ class GetFileContentsRequest extends ClientApiRequest implements ClientPermissio */ public function permission(): string { - return Permission::ACTION_FILE_READ; + return Permission::ACTION_FILE_READ_CONTENT; } /** diff --git a/app/Models/Permission.php b/app/Models/Permission.php index a7eb2709..f870866e 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -49,6 +49,7 @@ class Permission extends Model const ACTION_ALLOCATION_DELETE = 'allocation.delete'; const ACTION_FILE_READ = 'file.read'; + const ACTION_FILE_READ_CONTENT = 'file.read-content'; const ACTION_FILE_CREATE = 'file.create'; const ACTION_FILE_UPDATE = 'file.update'; const ACTION_FILE_DELETE = 'file.delete'; @@ -138,7 +139,8 @@ class Permission extends Model 'description' => 'Permissions that control a user\'s ability to modify the filesystem for this server.', 'keys' => [ 'create' => 'Allows a user to create additional files and folders via the Panel or direct upload.', - 'read' => 'Allows a user to view the contents of a directory and read the contents of a file. Users with this permission can also download files.', + 'read' => 'Allows a user to view the contents of a directory, but not view the contents of or download files.', + 'read-content' => 'Allows a user to view the contents of a given file. This will also allow the user to download files.', 'update' => 'Allows a user to update the contents of an existing file or directory.', 'delete' => 'Allows a user to delete files or directories.', 'archive' => 'Allows a user to archive the contents of a directory as well as decompress existing archives on the system.', diff --git a/resources/scripts/components/server/files/FileObjectRow.tsx b/resources/scripts/components/server/files/FileObjectRow.tsx index bb893574..cf717569 100644 --- a/resources/scripts/components/server/files/FileObjectRow.tsx +++ b/resources/scripts/components/server/files/FileObjectRow.tsx @@ -11,12 +11,14 @@ import tw from 'twin.macro'; import isEqual from 'react-fast-compare'; import styled from 'styled-components/macro'; import SelectFileCheckbox from '@/components/server/files/SelectFileCheckbox'; +import { usePermissions } from '@/plugins/usePermissions'; const Row = styled.div` ${tw`flex bg-neutral-700 rounded-sm mb-px text-sm hover:text-neutral-100 cursor-pointer items-center no-underline hover:bg-neutral-600`}; `; const Clickable: React.FC<{ file: FileObject }> = memo(({ file, children }) => { + const [ canReadContents ] = usePermissions([ 'file.read-content' ]); const directory = ServerContext.useStoreState(state => state.files.directory); const history = useHistory(); @@ -35,7 +37,7 @@ const Clickable: React.FC<{ file: FileObject }> = memo(({ file, children }) => { }; return ( - file.isFile && !file.isEditable() ? + (!canReadContents || (file.isFile && !file.isEditable())) ?
{children}
From de9ec1eba646a3efcd0d102d5be460fe23f590d8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Mon, 31 Aug 2020 21:05:52 -0700 Subject: [PATCH 09/46] Confirmation when deleting files via dropdown menu; closes #2293 --- .../server/files/FileDropdownMenu.tsx | 89 +++++++++++-------- 1 file changed, 51 insertions(+), 38 deletions(-) diff --git a/resources/scripts/components/server/files/FileDropdownMenu.tsx b/resources/scripts/components/server/files/FileDropdownMenu.tsx index 66b2fbb3..1ccf4b60 100644 --- a/resources/scripts/components/server/files/FileDropdownMenu.tsx +++ b/resources/scripts/components/server/files/FileDropdownMenu.tsx @@ -29,6 +29,7 @@ import useEventListener from '@/plugins/useEventListener'; import compressFiles from '@/api/server/files/compressFiles'; import decompressFiles from '@/api/server/files/decompressFiles'; import isEqual from 'react-fast-compare'; +import ConfirmationModal from '@/components/elements/ConfirmationModal'; type ModalType = 'rename' | 'move'; @@ -54,6 +55,7 @@ const FileDropdownMenu = ({ file }: { file: FileObject }) => { const onClickRef = useRef(null); const [ showSpinner, setShowSpinner ] = useState(false); const [ modal, setModal ] = useState(null); + const [ showConfirmation, setShowConfirmation ] = useState(false); const uuid = ServerContext.useStoreState(state => state.server.data!.uuid); const { mutate } = useFileManagerSwr(); @@ -123,47 +125,58 @@ const FileDropdownMenu = ({ file }: { file: FileObject }) => { }; return ( - ( -
- - {!!modal && - setModal(null)} - /> - } - -
- )} - > - - setModal('rename')} icon={faPencilAlt} title={'Rename'}/> - setModal('move')} icon={faLevelUpAlt} title={'Move'}/> - - {file.isFile && - - - - } - {file.isArchiveType() ? + <> + setShowConfirmation(false)} + > + Deleting files is a permanent operation, you cannot undo this action. + + ( +
+ + {!!modal && + setModal(null)} + /> + } + +
+ )} + > + + setModal('rename')} icon={faPencilAlt} title={'Rename'}/> + setModal('move')} icon={faLevelUpAlt} title={'Move'}/> + + {file.isFile && - + - : - - + } + {file.isArchiveType() ? + + + + : + + + + } + + + setShowConfirmation(true)} icon={faTrashAlt} title={'Delete'} $danger/> - } - - - - -
+
+ ); }; From 6ac12fc156075f3102613011d3fbdff58779d7f3 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 1 Sep 2020 19:37:05 -0700 Subject: [PATCH 10/46] Disable integrity hashes by default, allow enabling with environment Cloudflare auto-minifies our minified code even more (wat), which leads to issues with the resource hash, and then nothing loads. This is less likely to lead to support requests now. --- app/Services/Helpers/AssetHashService.php | 42 ++++++++++++++++++----- config/pterodactyl.php | 36 +++++++------------ 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/app/Services/Helpers/AssetHashService.php b/app/Services/Helpers/AssetHashService.php index f9b6a2cd..25aa3318 100644 --- a/app/Services/Helpers/AssetHashService.php +++ b/app/Services/Helpers/AssetHashService.php @@ -82,12 +82,24 @@ class AssetHashService */ public function css(string $resource): string { - return ''; + $attributes = [ + 'href' => $this->url($resource), + 'rel' => 'stylesheet preload', + 'as' => 'style', + 'crossorigin' => 'anonymous', + 'referrerpolicy' => 'no-referrer', + ]; + + if (config('pterodactyl.assets.use_hash')) { + $attributes['integrity'] = $this->integrity($resource); + } + + $output = ' $value) { + $output .= " $key=\"$value\""; + } + + return $output . '>'; } /** @@ -100,9 +112,21 @@ class AssetHashService */ public function js(string $resource): string { - return ''; + $attributes = [ + 'src' => $this->url($resource), + 'crossorigin' => 'anonymous', + ]; + + if (config('pterodactyl.assets.use_hash')) { + $attributes['integrity'] = $this->integrity($resource); + } + + $output = ' $value) { + $output .= " $key=\"$value\""; + } + + return $output . '>'; } /** diff --git a/config/pterodactyl.php b/config/pterodactyl.php index 75ece65b..5721277c 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -10,7 +10,7 @@ return [ | setup on the panel. When set to true, configurations stored in the | database will not be applied. */ - 'load_environment_only' => (bool) env('APP_ENVIRONMENT_ONLY', false), + 'load_environment_only' => (bool)env('APP_ENVIRONMENT_ONLY', false), /* |-------------------------------------------------------------------------- @@ -102,29 +102,6 @@ return [ 'high' => env('QUEUE_HIGH', 'high'), ], - /* - |-------------------------------------------------------------------------- - | Console Configuration - |-------------------------------------------------------------------------- - | - | Configure the speed at which data is rendered to the console. - */ - 'console' => [ - 'count' => env('CONSOLE_PUSH_COUNT', 10), - 'frequency' => env('CONSOLE_PUSH_FREQ', 200), - ], - - /* - |-------------------------------------------------------------------------- - | Daemon Connection Details - |-------------------------------------------------------------------------- - | - | Configuration for support of the new Golang based daemon. - */ - 'daemon' => [ - 'use_new_daemon' => (bool) env('APP_USE_NEW_DAEMON', false), - ], - /* |-------------------------------------------------------------------------- | Task Timers @@ -212,4 +189,15 @@ return [ 'environment_variables' => [ 'P_SERVER_ALLOCATION_LIMIT' => 'allocation_limit', ], + + /* + |-------------------------------------------------------------------------- + | Asset Verification + |-------------------------------------------------------------------------- + | + | This section controls the output format for JS & CSS assets. + */ + 'assets' => [ + 'use_hash' => env('PTERODACTYL_USE_ASSET_HASH', false), + ], ]; From b707147b73f0adeb35ab39f53008d02d689aff86 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 1 Sep 2020 19:45:24 -0700 Subject: [PATCH 11/46] Better handling of values that may need to be wrapped in quotes within the environment file, closes #2304 --- app/Traits/Commands/EnvironmentWriterTrait.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Traits/Commands/EnvironmentWriterTrait.php b/app/Traits/Commands/EnvironmentWriterTrait.php index bc4d2486..6726e931 100644 --- a/app/Traits/Commands/EnvironmentWriterTrait.php +++ b/app/Traits/Commands/EnvironmentWriterTrait.php @@ -30,7 +30,10 @@ trait EnvironmentWriterTrait $saveContents = file_get_contents($path); collect($values)->each(function ($value, $key) use (&$saveContents) { $key = strtoupper($key); - if (str_contains($value, ' ') && ! preg_match('/\"(.*)\"/', $value)) { + // If the key value is not sorrounded by quotation marks, and contains anything that could reasonably + // cause environment parsing issues, wrap it in quotes before writing it. This also adds slashes to the + // value to ensure quotes within it don't cause us issues. + if (! preg_match('/^\"(.*)\"$/', $value) && preg_match('/([^\w.\-+\/])+/', $value)) { $value = sprintf('"%s"', addslashes($value)); } From 631885d60c1a0f38fee99162ec21cf25324c0a53 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Tue, 1 Sep 2020 20:24:25 -0700 Subject: [PATCH 12/46] Handle a plugin not properly namespacing itself and causing migration errors; ref #2291 --- ...2020_04_03_230614_create_backups_table.php | 16 ++++++++++++++ ..._26_111208_add_backup_limit_to_servers.php | 21 ++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/database/migrations/2020_04_03_230614_create_backups_table.php b/database/migrations/2020_04_03_230614_create_backups_table.php index ead68105..10d0794d 100644 --- a/database/migrations/2020_04_03_230614_create_backups_table.php +++ b/database/migrations/2020_04_03_230614_create_backups_table.php @@ -1,5 +1,6 @@ bigIncrements('id'); $table->unsignedInteger('server_id'); diff --git a/database/migrations/2020_04_26_111208_add_backup_limit_to_servers.php b/database/migrations/2020_04_26_111208_add_backup_limit_to_servers.php index 689da89b..92121b7d 100644 --- a/database/migrations/2020_04_26_111208_add_backup_limit_to_servers.php +++ b/database/migrations/2020_04_26_111208_add_backup_limit_to_servers.php @@ -1,5 +1,6 @@ unsignedInteger('backup_limit')->default(0)->after('database_limit'); - }); + $db = config('database.default'); + // Same as in the backups migration, we need to handle that plugin messing with the data structure + // here. If we find a result we'll actually keep the column around since we can maintain that backup + // limit, but we need to correct the column definition a bit. + $results = DB::select('SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = \'servers\' AND COLUMN_NAME = \'backup_limit\'', [ + config("database.connections.{$db}.database") + ]); + + if (count($results) === 1) { + Schema::table('servers', function (Blueprint $table) { + $table->unsignedInteger('backup_limit')->default(0)->change(); + }); + } else { + Schema::table('servers', function (Blueprint $table) { + $table->unsignedInteger('backup_limit')->default(0)->after('database_limit'); + }); + } } /** From ed83ab8fe985d7483bfb5857cb005639c2950938 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Mon, 7 Sep 2020 15:03:26 -0700 Subject: [PATCH 13/46] Clear error when navigating through file manager; closes #2314 --- .../scripts/components/server/files/FileManagerContainer.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/scripts/components/server/files/FileManagerContainer.tsx b/resources/scripts/components/server/files/FileManagerContainer.tsx index 2c90e992..aae93a89 100644 --- a/resources/scripts/components/server/files/FileManagerContainer.tsx +++ b/resources/scripts/components/server/files/FileManagerContainer.tsx @@ -16,6 +16,7 @@ import useFileManagerSwr from '@/plugins/useFileManagerSwr'; import MassActionsBar from '@/components/server/files/MassActionsBar'; import UploadButton from '@/components/server/files/UploadButton'; import ServerContentBlock from '@/components/elements/ServerContentBlock'; +import { useStoreActions } from '@/state/hooks'; const sortFiles = (files: FileObject[]): FileObject[] => { return files.sort((a, b) => a.name.localeCompare(b.name)) @@ -26,11 +27,12 @@ export default () => { const id = ServerContext.useStoreState(state => state.server.data!.id); const { hash } = useLocation(); const { data: files, error, mutate } = useFileManagerSwr(); - + const clearFlashes = useStoreActions(actions => actions.flashes.clearFlashes); const setDirectory = ServerContext.useStoreActions(actions => actions.files.setDirectory); const setSelectedFiles = ServerContext.useStoreActions(actions => actions.files.setSelectedFiles); useEffect(() => { + clearFlashes('files'); setSelectedFiles([]); setDirectory(hash.length > 0 ? hash : '/'); }, [ hash ]); From 861911ca49f537a69c623d24237f5a3bb309b50b Mon Sep 17 00:00:00 2001 From: Charles Morgan Date: Mon, 7 Sep 2020 23:26:18 -0400 Subject: [PATCH 14/46] Move page titles to PageContentBlocks --- .../scripts/components/dashboard/AccountApiContainer.tsx | 9 ++------- .../components/dashboard/AccountOverviewContainer.tsx | 9 +-------- .../scripts/components/dashboard/DashboardContainer.tsx | 8 +------- .../scripts/components/server/users/UsersContainer.tsx | 7 +------ 4 files changed, 5 insertions(+), 28 deletions(-) diff --git a/resources/scripts/components/dashboard/AccountApiContainer.tsx b/resources/scripts/components/dashboard/AccountApiContainer.tsx index 304fe563..6b459502 100644 --- a/resources/scripts/components/dashboard/AccountApiContainer.tsx +++ b/resources/scripts/components/dashboard/AccountApiContainer.tsx @@ -1,5 +1,4 @@ import React, { useEffect, useState } from 'react'; -import { Helmet } from 'react-helmet'; import ContentBox from '@/components/elements/ContentBox'; import CreateApiKeyForm from '@/components/dashboard/forms/CreateApiKeyForm'; import getApiKeys, { ApiKey } from '@/api/account/getApiKeys'; @@ -8,7 +7,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faKey, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import ConfirmationModal from '@/components/elements/ConfirmationModal'; import deleteApiKey from '@/api/account/deleteApiKey'; -import { Actions, useStoreActions, useStoreState } from 'easy-peasy'; +import { Actions, useStoreActions } from 'easy-peasy'; import { ApplicationStore } from '@/state'; import FlashMessageRender from '@/components/FlashMessageRender'; import { httpErrorToHuman } from '@/api/http'; @@ -22,7 +21,6 @@ export default () => { const [ keys, setKeys ] = useState([]); const [ loading, setLoading ] = useState(true); const { addError, clearFlashes } = useStoreActions((actions: Actions) => actions.flashes); - const name = useStoreState((state: ApplicationStore) => state.settings.data!.name); useEffect(() => { clearFlashes('account'); @@ -50,10 +48,7 @@ export default () => { }; return ( - - - {name} | API - +
diff --git a/resources/scripts/components/dashboard/AccountOverviewContainer.tsx b/resources/scripts/components/dashboard/AccountOverviewContainer.tsx index d495400b..98e7a8d5 100644 --- a/resources/scripts/components/dashboard/AccountOverviewContainer.tsx +++ b/resources/scripts/components/dashboard/AccountOverviewContainer.tsx @@ -1,6 +1,4 @@ import * as React from 'react'; -import { Helmet } from 'react-helmet'; -import { ApplicationStore } from '@/state'; import ContentBox from '@/components/elements/ContentBox'; import UpdatePasswordForm from '@/components/dashboard/forms/UpdatePasswordForm'; import UpdateEmailAddressForm from '@/components/dashboard/forms/UpdateEmailAddressForm'; @@ -9,7 +7,6 @@ import PageContentBlock from '@/components/elements/PageContentBlock'; import tw from 'twin.macro'; import { breakpoint } from '@/theme'; import styled from 'styled-components/macro'; -import { useStoreState } from 'easy-peasy'; const Container = styled.div` ${tw`flex flex-wrap my-10`}; @@ -28,12 +25,8 @@ const Container = styled.div` `; export default () => { - const name = useStoreState((state: ApplicationStore) => state.settings.data!.name); return ( - - - {name} | Account Overview - + diff --git a/resources/scripts/components/dashboard/DashboardContainer.tsx b/resources/scripts/components/dashboard/DashboardContainer.tsx index 1e1e702c..f8b13eda 100644 --- a/resources/scripts/components/dashboard/DashboardContainer.tsx +++ b/resources/scripts/components/dashboard/DashboardContainer.tsx @@ -1,7 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { Helmet } from 'react-helmet'; import { Server } from '@/api/server/getServer'; -import { ApplicationStore } from '@/state'; import getServers from '@/api/getServers'; import ServerRow from '@/components/dashboard/ServerRow'; import Spinner from '@/components/elements/Spinner'; @@ -20,7 +18,6 @@ export default () => { const [ page, setPage ] = useState(1); const { rootAdmin } = useStoreState(state => state.user.data!); const [ showOnlyAdmin, setShowOnlyAdmin ] = usePersistedState('show_all_servers', false); - const name = useStoreState((state: ApplicationStore) => state.settings.data!.name); const { data: servers, error } = useSWR>( [ '/api/client/servers', showOnlyAdmin, page ], @@ -33,10 +30,7 @@ export default () => { }, [ error ]); return ( - - - {name} | Dashboard - + {rootAdmin &&

diff --git a/resources/scripts/components/server/users/UsersContainer.tsx b/resources/scripts/components/server/users/UsersContainer.tsx index a58d9e90..06f95c0b 100644 --- a/resources/scripts/components/server/users/UsersContainer.tsx +++ b/resources/scripts/components/server/users/UsersContainer.tsx @@ -1,5 +1,4 @@ import React, { useEffect, useState } from 'react'; -import { Helmet } from 'react-helmet'; import { ServerContext } from '@/state/server'; import { Actions, useStoreActions, useStoreState } from 'easy-peasy'; import { ApplicationStore } from '@/state'; @@ -18,7 +17,6 @@ export default () => { const uuid = ServerContext.useStoreState(state => state.server.data!.uuid); const subusers = ServerContext.useStoreState(state => state.subusers.data); - const servername = ServerContext.useStoreState(state => state.server.data!.name); const setSubusers = ServerContext.useStoreActions(actions => actions.subusers.setSubusers); const permissions = useStoreState((state: ApplicationStore) => state.permissions.data); @@ -50,10 +48,7 @@ export default () => { } return ( - - - {servername} | Subusers - + {!subusers.length ?

From b4599a25613248ea1f0b13f413aeee48c41fa717 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 9 Sep 2020 19:00:11 -0700 Subject: [PATCH 15/46] Name changes for sponsor --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 861df265..a88f1803 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ I would like to extend my sincere thanks to the following sponsors for helping f | Company | About | | ------- | ----- | -| [**BloomVPS**](https://bloomvps.com) | BloomVPS offers dedicated core VPS and Minecraft hosting with Ryzen 9 processors. With owned-hardware, we offer truly unbeatable prices on high-performance hosting. | +| [**Bloom.host**](https://bloom.host) | Bloom.host offers dedicated core VPS and Minecraft hosting with Ryzen 9 processors. With owned-hardware, we offer truly unbeatable prices on high-performance hosting. | | [**VersatileNode**](https://versatilenode.com/) | Looking to host a minecraft server, vps, or a website? VersatileNode is one of the most affordable hosting providers to provide quality yet cheap services with incredible support. | | [**MineStrator**](https://minestrator.com/) | Looking for a French highend hosting company for you minecraft server? More than 14,000 members on our discord, trust us. | | [**DedicatedMC**](https://dedicatedmc.io/) | DedicatedMC provides Raw Power hosting at affordable pricing, making sure to never compromise on your performance and giving you the best performance money can buy. | From 6139b4e479ee09f3f910c110399ed1719b407a0d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 9 Sep 2020 20:55:23 -0700 Subject: [PATCH 16/46] Fix chrome dismissing modals when dragging out of it; closes #2295 --- .../scripts/components/elements/Modal.tsx | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/resources/scripts/components/elements/Modal.tsx b/resources/scripts/components/elements/Modal.tsx index b6291805..896a3256 100644 --- a/resources/scripts/components/elements/Modal.tsx +++ b/resources/scripts/components/elements/Modal.tsx @@ -47,20 +47,21 @@ const Modal: React.FC = ({ visible, appear, dismissable, showSpinner return (dismissable || true) && !(showSpinnerOverlay || false); }, [ dismissable, showSpinnerOverlay ]); - const handleEscapeEvent = (e: KeyboardEvent) => { - if (isDismissable && closeOnEscape && e.key === 'Escape') { - setRender(false); - } - }; + useEffect(() => { + if (!isDismissable || !closeOnEscape) return; + + const handler = (e: KeyboardEvent) => { + if (e.key === 'Escape') setRender(false); + }; + + window.addEventListener('keydown', handler); + return () => { + window.removeEventListener('keydown', handler); + }; + }, [ isDismissable, closeOnEscape, render ]); useEffect(() => setRender(visible), [ visible ]); - useEffect(() => { - window.addEventListener('keydown', handleEscapeEvent); - - return () => window.removeEventListener('keydown', handleEscapeEvent); - }, [ render ]); - return ( = ({ visible, appear, dismissable, showSpinner onExited={() => onDismissed()} > { + onClick={e => e.stopPropagation()} + onMouseDown={e => { if (isDismissable && closeOnBackground) { e.stopPropagation(); if (e.target === e.currentTarget) { From 6d922a756327ed40704429629ec6ee53be74cc6c Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 9 Sep 2020 21:07:57 -0700 Subject: [PATCH 17/46] Show normal upload box when using upload button; closes #2294 --- .../components/server/files/UploadButton.tsx | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/resources/scripts/components/server/files/UploadButton.tsx b/resources/scripts/components/server/files/UploadButton.tsx index 5b399ef1..df2416a6 100644 --- a/resources/scripts/components/server/files/UploadButton.tsx +++ b/resources/scripts/components/server/files/UploadButton.tsx @@ -2,7 +2,7 @@ import axios from 'axios'; import getFileUploadUrl from '@/api/server/files/getFileUploadUrl'; import tw from 'twin.macro'; import Button from '@/components/elements/Button'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import styled from 'styled-components/macro'; import { ModalMask } from '@/components/elements/Modal'; import Fade from '@/components/elements/Fade'; @@ -18,6 +18,7 @@ const InnerContainer = styled.div` `; export default () => { + const fileUploadInput = useRef(null); const uuid = ServerContext.useStoreState(state => state.server.data!.uuid); const [ visible, setVisible ] = useState(false); const [ loading, setLoading ] = useState(false); @@ -46,17 +47,9 @@ export default () => { }; }, [ visible ]); - const onFileDrop = (e: React.DragEvent) => { - e.preventDefault(); - e.stopPropagation(); - - setVisible(false); - if (e.dataTransfer === undefined || e.dataTransfer === null) { - return; - } - + const onFileSubmission = (files: FileList) => { const form = new FormData(); - Array.from(e.dataTransfer.files).forEach(file => form.append('files', file)); + Array.from(files).forEach(file => form.append('files', file)); setLoading(true); clearFlashes('files'); @@ -84,7 +77,21 @@ export default () => { key={'upload_modal_mask'} unmountOnExit > - setVisible(false)} onDrop={onFileDrop} onDragOver={e => e.preventDefault()}> + setVisible(false)} + onDragOver={e => e.preventDefault()} + onDrop={e => { + e.preventDefault(); + e.stopPropagation(); + + setVisible(false); + if (e.dataTransfer === undefined || e.dataTransfer === null) { + return; + } + + onFileSubmission(e.dataTransfer.files); + }} + >

@@ -95,7 +102,27 @@ export default () => { - From 98d7b32036d5c15a9579df535b22194724d38226 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 9 Sep 2020 21:08:34 -0700 Subject: [PATCH 18/46] Use fixed spinner overlay for uploads --- resources/scripts/components/server/files/UploadButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/scripts/components/server/files/UploadButton.tsx b/resources/scripts/components/server/files/UploadButton.tsx index df2416a6..a2151e5a 100644 --- a/resources/scripts/components/server/files/UploadButton.tsx +++ b/resources/scripts/components/server/files/UploadButton.tsx @@ -101,7 +101,7 @@ export default () => {

- + Date: Wed, 9 Sep 2020 21:22:13 -0700 Subject: [PATCH 19/46] Don't try to upload dropped text --- resources/scripts/components/server/files/UploadButton.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/resources/scripts/components/server/files/UploadButton.tsx b/resources/scripts/components/server/files/UploadButton.tsx index a2151e5a..f5889111 100644 --- a/resources/scripts/components/server/files/UploadButton.tsx +++ b/resources/scripts/components/server/files/UploadButton.tsx @@ -85,9 +85,7 @@ export default () => { e.stopPropagation(); setVisible(false); - if (e.dataTransfer === undefined || e.dataTransfer === null) { - return; - } + if (!e.dataTransfer?.files.length) return; onFileSubmission(e.dataTransfer.files); }} From d86d0fedb4a4df3f14fc4e98583164ecf4408c1a Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 9 Sep 2020 21:32:43 -0700 Subject: [PATCH 20/46] Don't re-render entire file list when opening modals --- .../scripts/components/server/files/FileManagerContainer.tsx | 5 +++++ resources/scripts/plugins/useFileManagerSwr.ts | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/scripts/components/server/files/FileManagerContainer.tsx b/resources/scripts/components/server/files/FileManagerContainer.tsx index aae93a89..444dc2fa 100644 --- a/resources/scripts/components/server/files/FileManagerContainer.tsx +++ b/resources/scripts/components/server/files/FileManagerContainer.tsx @@ -27,6 +27,7 @@ export default () => { const id = ServerContext.useStoreState(state => state.server.data!.id); const { hash } = useLocation(); const { data: files, error, mutate } = useFileManagerSwr(); + const directory = ServerContext.useStoreState(state => state.files.directory); const clearFlashes = useStoreActions(actions => actions.flashes.clearFlashes); const setDirectory = ServerContext.useStoreActions(actions => actions.files.setDirectory); const setSelectedFiles = ServerContext.useStoreActions(actions => actions.files.setSelectedFiles); @@ -37,6 +38,10 @@ export default () => { setDirectory(hash.length > 0 ? hash : '/'); }, [ hash ]); + useEffect(() => { + mutate(); + }, [ directory ]); + if (error) { return ( mutate()}/> diff --git a/resources/scripts/plugins/useFileManagerSwr.ts b/resources/scripts/plugins/useFileManagerSwr.ts index eb36848b..05239377 100644 --- a/resources/scripts/plugins/useFileManagerSwr.ts +++ b/resources/scripts/plugins/useFileManagerSwr.ts @@ -11,7 +11,8 @@ export default () => { `${uuid}:files:${directory}`, () => loadDirectory(uuid, cleanDirectoryPath(directory)), { - revalidateOnMount: true, + focusThrottleInterval: 30000, + revalidateOnMount: false, refreshInterval: 0, }, ); From 735aae6df7114668b2d8476ffc22df92ccca2006 Mon Sep 17 00:00:00 2001 From: Charles Morgan Date: Thu, 10 Sep 2020 01:02:44 -0400 Subject: [PATCH 21/46] Arrange cron times in proper order to match Moves the rendering of the time boxes to proper locations to match the view on the main schedules page and to match cron syntax --- .../components/server/schedules/EditScheduleModal.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/scripts/components/server/schedules/EditScheduleModal.tsx b/resources/scripts/components/server/schedules/EditScheduleModal.tsx index 5d42888f..423ae991 100644 --- a/resources/scripts/components/server/schedules/EditScheduleModal.tsx +++ b/resources/scripts/components/server/schedules/EditScheduleModal.tsx @@ -40,16 +40,16 @@ const EditScheduleModal = ({ schedule, ...props }: Omit
- -
-
- +
+
+ +
- +

From 1077504c02f1350bd74d6e2e5c49788638f22445 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Thu, 10 Sep 2020 20:09:07 -0700 Subject: [PATCH 22/46] Rely on the test connection to the MySQL instance rather than trying to validate the host manually; closes #2311; closes #2282 --- app/Models/DatabaseHost.php | 14 --------- app/Rules/ResolvesToIPAddress.php | 49 ------------------------------- 2 files changed, 63 deletions(-) delete mode 100644 app/Rules/ResolvesToIPAddress.php diff --git a/app/Models/DatabaseHost.php b/app/Models/DatabaseHost.php index d76fed49..01670214 100644 --- a/app/Models/DatabaseHost.php +++ b/app/Models/DatabaseHost.php @@ -2,8 +2,6 @@ namespace Pterodactyl\Models; -use Pterodactyl\Rules\ResolvesToIPAddress; - class DatabaseHost extends Model { /** @@ -60,18 +58,6 @@ class DatabaseHost extends Model 'node_id' => 'sometimes|nullable|integer|exists:nodes,id', ]; - /** - * @return array - */ - public static function getRules() - { - $rules = parent::getRules(); - - $rules['host'] = array_merge($rules['host'], [ new ResolvesToIPAddress() ]); - - return $rules; - } - /** * Gets the node associated with a database host. * diff --git a/app/Rules/ResolvesToIPAddress.php b/app/Rules/ResolvesToIPAddress.php deleted file mode 100644 index e1421b52..00000000 --- a/app/Rules/ResolvesToIPAddress.php +++ /dev/null @@ -1,49 +0,0 @@ - Date: Sat, 12 Sep 2020 02:29:52 +0200 Subject: [PATCH 23/46] fix: remove ./ before wings for auto-configuration on the docs, you're downloading it to /usr/local/bin so it's easier like this --- resources/views/admin/nodes/view/configuration.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/admin/nodes/view/configuration.blade.php b/resources/views/admin/nodes/view/configuration.blade.php index aa085ce8..9c7e987b 100644 --- a/resources/views/admin/nodes/view/configuration.blade.php +++ b/resources/views/admin/nodes/view/configuration.blade.php @@ -74,7 +74,7 @@ swal({ type: 'success', title: 'Token created.', - text: '

To auto-configure your node run the following command:

cd /etc/pterodactyl && sudo ./wings configure --panel-url {{ config('app.url') }} --token ' + data.token + ' --node ' + data.node + '{{ config('app.debug') ? ' --allow-insecure' : '' }}

', + text: '

To auto-configure your node run the following command:

cd /etc/pterodactyl && sudo wings configure --panel-url {{ config('app.url') }} --token ' + data.token + ' --node ' + data.node + '{{ config('app.debug') ? ' --allow-insecure' : '' }}

', html: true }) }).fail(function () { From 09071a43dc85ed927bd58e9758a489127ef1dd45 Mon Sep 17 00:00:00 2001 From: Sourack Date: Fri, 11 Sep 2020 21:50:43 -0400 Subject: [PATCH 24/46] Update daemon_off_config_updated message core.json is now config.yml This error message isn't updated for wings 1.0 . --- resources/lang/en/exceptions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/en/exceptions.php b/resources/lang/en/exceptions.php index f1d58c6c..d8dcd559 100644 --- a/resources/lang/en/exceptions.php +++ b/resources/lang/en/exceptions.php @@ -4,7 +4,7 @@ return [ 'daemon_connection_failed' => 'There was an exception while attempting to communicate with the daemon resulting in a HTTP/:code response code. This exception has been logged.', 'node' => [ 'servers_attached' => 'A node must have no servers linked to it in order to be deleted.', - 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (core.json) for the daemon to apply these changes.', + 'daemon_off_config_updated' => 'The daemon configuration has been updated, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.', ], 'allocations' => [ 'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.', From 74767ed6a2944babfc0d93ae02aeb062bfaa2a27 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 11 Sep 2020 23:18:01 -0700 Subject: [PATCH 25/46] Disable buttons when not fully connected to instance --- resources/scripts/components/server/ServerConsole.tsx | 3 ++- resources/scripts/components/server/StopOrKillButton.tsx | 2 +- resources/scripts/state/server/index.ts | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/resources/scripts/components/server/ServerConsole.tsx b/resources/scripts/components/server/ServerConsole.tsx index 253cb05e..ad84505c 100644 --- a/resources/scripts/components/server/ServerConsole.tsx +++ b/resources/scripts/components/server/ServerConsole.tsx @@ -75,7 +75,7 @@ export default () => { status === 'offline' ? tw`text-red-500` : (status === 'running' ? tw`text-green-500` : tw`text-yellow-500`), ]} /> -  {status} +  {!status ? 'Connecting...' : status}

{cpu.toFixed(2)}% @@ -112,6 +112,7 @@ export default () => { size={'xsmall'} isSecondary css={tw`mr-2`} + disabled={!status} onClick={e => { e.preventDefault(); sendPowerCommand('restart'); diff --git a/resources/scripts/components/server/StopOrKillButton.tsx b/resources/scripts/components/server/StopOrKillButton.tsx index ee9d40d2..605ca397 100644 --- a/resources/scripts/components/server/StopOrKillButton.tsx +++ b/resources/scripts/components/server/StopOrKillButton.tsx @@ -16,7 +16,7 @@ const StopOrKillButton = ({ onPress }: { onPress: (action: PowerAction) => void

- -
+ +

{database.name}

-
+ -
+ -
+ diff --git a/resources/scripts/components/server/files/FileObjectRow.tsx b/resources/scripts/components/server/files/FileObjectRow.tsx index cf717569..0e05820b 100644 --- a/resources/scripts/components/server/files/FileObjectRow.tsx +++ b/resources/scripts/components/server/files/FileObjectRow.tsx @@ -73,12 +73,12 @@ const FileObjectRow = ({ file }: { file: FileObject }) => ( {file.name}
{file.isFile && -
+ } -
-
-
-

Pack Configuration

-
-
-
-
- - -
-

Check this box if user should be able to select this pack to install on their servers.

-
-
-
- - -
-

Check this box if this pack is visible in the dropdown menu. If this pack is assigned to a server it will be visible regardless of this setting.

-
-
-
- - -
-

Check this box if servers assigned this pack should not be able to switch to a different pack.

-
-
-
- - -

This package file must be a .tar.gz archive of pack files to be decompressed into the server folder.

-

If your file is larger than 50MB it is recommended to upload it using SFTP. Once you have added this pack to the system, a path will be provided where you should upload the file.

-
-

This node is currently configured with the following limits:
upload_max_filesize={{ ini_get('upload_max_filesize') }}
post_max_size={{ ini_get('post_max_size') }}

If your file is larger than either of those values this request will fail.

-
-
-
- -
-
-
- -@endsection - -@section('footer-scripts') - @parent - -@endsection diff --git a/resources/views/admin/packs/view.blade.php b/resources/views/admin/packs/view.blade.php deleted file mode 100644 index 63382a21..00000000 --- a/resources/views/admin/packs/view.blade.php +++ /dev/null @@ -1,154 +0,0 @@ -{{-- Pterodactyl - Panel --}} -{{-- Copyright (c) 2015 - 2017 Dane Everitt --}} - -{{-- This software is licensed under the terms of the MIT license. --}} -{{-- https://opensource.org/licenses/MIT --}} -@extends('layouts.admin') - -@section('title') - Packs → View → {{ $pack->name }} -@endsection - -@section('content-header') -

{{ $pack->name }}{{ str_limit($pack->description, 60) }}

- -@endsection - -@section('content') -
-
-
-
-
-

Pack Details

-
-
-
- - -

A short but descriptive name of what this pack is. For example, Counter Strike: Source if it is a Counter Strike package.

-
-
- - -
-
- - -

The version of this package, or the version of the files contained within the package.

-
-
- - -

If you would like to modify the stored pack you will need to upload a new archive.tar.gz to the location defined above.

-
-
-
-
-
-
-
-

Pack Configuration

-
-
-
- - -

The option that this pack is associated with. Only servers that are assigned this option will be able to access this pack. This assigned option cannot be changed if servers are attached to this pack.

-
-
-
- selectable ?: 'checked' }}/> - -
-

Check this box if user should be able to select this pack to install on their servers.

-
-
-
- visible ?: 'checked' }}/> - -
-

Check this box if this pack is visible in the dropdown menu. If this pack is assigned to a server it will be visible regardless of this setting.

-
-
-
- locked ?: 'checked' }}/> - -
-

Check this box if servers assigned this pack should not be able to switch to a different pack.

-
-
- -
-
-
-
-
-
-
-
-

Servers Using This Pack

-
-
- - - - - - - - @foreach($pack->servers as $server) - - - - - - - @endforeach -
IDServer NameNodeOwner
{{ $server->uuidShort }}{{ $server->name }}{{ $server->node->name }}{{ $server->user->email }}
-
-
-
-
-
-
-
- {!! csrf_field() !!} - -
-
- {!! csrf_field() !!} - -
-
-
-@endsection - -@section('footer-scripts') - @parent - -@endsection diff --git a/resources/views/admin/servers/new.blade.php b/resources/views/admin/servers/new.blade.php index 026be8be..fe9c7be2 100644 --- a/resources/views/admin/servers/new.blade.php +++ b/resources/views/admin/servers/new.blade.php @@ -244,20 +244,13 @@

Select the Egg that will define how this server should operate.

- -
- - -

Select a data pack to be automatically installed on this server when first created.

-
-
-

If the selected Egg has an install script attached to it, the script will run during install after the pack is installed. If you would like to skip this step, check this box.

+

If the selected Egg has an install script attached to it, the script will run during the install. If you would like to skip this step, check this box.

@@ -384,12 +377,6 @@ $('#pEggId').val('{{ old('egg_id') }}').change(); @endif // END Persist 'Egg' select2 - - // Persist 'Data Pack' select2 - @if (old('pack_id')) - $('#pPackId').val('{{ old('pack_id') }}').change(); - @endif - // END Persist 'Data Pack' select2 @endif // END Persist 'Nest' select2 }); diff --git a/resources/views/admin/servers/view/manage.blade.php b/resources/views/admin/servers/view/manage.blade.php index 8c41fc50..aad14209 100644 --- a/resources/views/admin/servers/view/manage.blade.php +++ b/resources/views/admin/servers/view/manage.blade.php @@ -28,7 +28,7 @@

Reinstall Server

-

This will reinstall the server with the assigned pack and service scripts. Danger! This could overwrite server data.

+

This will reinstall the server with the assigned service scripts. Danger! This could overwrite server data.

@@ -117,7 +112,6 @@ {!! Theme::js('vendor/lodash/lodash.js') !!} - {!! Theme::js('js/admin/new-server.js') !!} + {!! Theme::js('js/admin/new-server.js?v=20200913') !!}