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 3fab319b8..18121a3f1 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 18121a3f1..c1fa644e5 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 c1fa644e5..861df2654 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 a504f1951..819e66639 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 fea2eaac0..f975f7e8f 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 8c10b22d2..505f1a305 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 acaba0c43..84fcaf2d4 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 671a64fd3..75ece65b2 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 77e44bce8..1caf6bf9d 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 595f2b9c8..f17787e03 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 0a14aca8c..bb8935744 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 709fdd5e6..8cb82dd9b 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 fa4818fc9..000000000 --- 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 25dc4f1e1..008b44436 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 a7eb2709b..f870866e2 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 bb8935744..cf717569b 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 66b2fbb32..1ccf4b60c 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 f9b6a2cd1..25aa3318b 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 75ece65b2..5721277cf 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 bc4d2486e..6726e931f 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 ead68105c..10d0794d9 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 689da89b6..92121b7df 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 2c90e9925..aae93a89a 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 304fe5630..6b4595024 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 d495400b4..98e7a8d53 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 1e1e702ca..f8b13eda2 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 a58d9e904..06f95c0b4 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 861df2654..a88f18036 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 b62918050..896a32567 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 5b399ef1d..df2416a6b 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 df2416a6b..a2151e5a3 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 a2151e5a3..f58891112 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 aae93a89a..444dc2fac 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 eb36848bf..052393774 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 5d42888f3..423ae9919 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 d76fed494..016702141 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 e1421b52c..000000000 --- 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 aa085ce81..9c7e987b5 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 f1d58c6c6..d8dcd559b 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 253cb05e2..ad84505c9 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 ee9d40d2d..605ca397e 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 cf717569b..0e05820bd 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 63382a21c..000000000 --- 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 026be8be3..fe9c7be24 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 8c41fc503..aad14209b 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') !!}