From 34117017ec6b1863ffe48dd0f762f52354667677 Mon Sep 17 00:00:00 2001 From: Arnaud Lier Date: Sun, 13 Sep 2020 09:35:35 +0200 Subject: [PATCH 01/96] fix: only show download button if it's a file --- .../scripts/components/server/files/FileDropdownMenu.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/scripts/components/server/files/FileDropdownMenu.tsx b/resources/scripts/components/server/files/FileDropdownMenu.tsx index 1ccf4b60c..48d53eeb2 100644 --- a/resources/scripts/components/server/files/FileDropdownMenu.tsx +++ b/resources/scripts/components/server/files/FileDropdownMenu.tsx @@ -171,7 +171,9 @@ const FileDropdownMenu = ({ file }: { file: FileObject }) => { } - + {file.isFile && + + } setShowConfirmation(true)} icon={faTrashAlt} title={'Delete'} $danger/> From 353f2487a0344cffde43a380a64ea6cc2be3abf4 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 16 Sep 2020 20:20:48 -0700 Subject: [PATCH 02/96] Correctly send backup ignored files from textarea; closes #2349 For some reason Formik can't handle the css macro on these fields? Concerning, but not wasting time this close to release to dig into it more. --- .../scripts/components/server/backups/CreateBackupButton.tsx | 3 ++- .../scripts/components/server/schedules/TaskDetailsModal.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/scripts/components/server/backups/CreateBackupButton.tsx b/resources/scripts/components/server/backups/CreateBackupButton.tsx index e505fd251..5e8c3bfdf 100644 --- a/resources/scripts/components/server/backups/CreateBackupButton.tsx +++ b/resources/scripts/components/server/backups/CreateBackupButton.tsx @@ -12,6 +12,7 @@ import tw from 'twin.macro'; import { Textarea } from '@/components/elements/Input'; import getServerBackups from '@/api/swr/getServerBackups'; import { ServerContext } from '@/state/server'; +import styled from 'styled-components/macro'; interface Values { name: string; @@ -44,7 +45,7 @@ const ModalContent = ({ ...props }: RequiredModalProps) => { prefixing the path with an exclamation point. `} > - +
diff --git a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx index 1ef64c138..f6b81bd86 100644 --- a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx +++ b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx @@ -84,7 +84,7 @@ const TaskDetailsForm = ({ isEditingTask }: { isEditingTask: boolean }) => { name={'payload'} description={'Optional. Include the files and folders to be excluded in this backup. By default, the contents of your .pteroignore file will be used.'} > - +
} From 1e4b50fa61e7fca5a1fb27c4d591ea0edd5180fa Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 16 Sep 2020 20:28:32 -0700 Subject: [PATCH 03/96] Remove socketio connections from server listing; closes #1942 --- .../pterodactyl/js/admin/node/view-servers.js | 113 ------------------ .../views/admin/nodes/view/servers.blade.php | 18 --- 2 files changed, 131 deletions(-) delete mode 100644 public/themes/pterodactyl/js/admin/node/view-servers.js diff --git a/public/themes/pterodactyl/js/admin/node/view-servers.js b/public/themes/pterodactyl/js/admin/node/view-servers.js deleted file mode 100644 index 96950cd19..000000000 --- a/public/themes/pterodactyl/js/admin/node/view-servers.js +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2015 - 2017 Dane Everitt -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -(function initSocket() { - if (typeof $.notifyDefaults !== 'function') { - console.error('Notify does not appear to be loaded.'); - return; - } - - if (typeof io !== 'function') { - console.error('Socket.io is reqired to use this panel.'); - return; - } - - $.notifyDefaults({ - placement: { - from: 'bottom', - align: 'right' - }, - newest_on_top: true, - delay: 2000, - animate: { - enter: 'animated zoomInDown', - exit: 'animated zoomOutDown' - } - }); - - var notifySocketError = false; - // Main Socket Object - window.Socket = io(Pterodactyl.node.scheme + '://' + Pterodactyl.node.fqdn + ':' + Pterodactyl.node.daemonListen + '/v1/stats/', { - 'query': 'token=' + Pterodactyl.node.daemonSecret, - }); - - // Socket Failed to Connect - Socket.io.on('connect_error', function (err) { - if(typeof notifySocketError !== 'object') { - notifySocketError = $.notify({ - message: 'There was an error attempting to establish a WebSocket connection to the Daemon. This panel will not work as expected.

' + err, - }, { - type: 'danger', - delay: 0 - }); - } - }); - - // Connected to Socket Successfully - Socket.on('connect', function () { - if (notifySocketError !== false) { - notifySocketError.close(); - notifySocketError = false; - } - }); - - Socket.on('error', function (err) { - console.error('There was an error while attemping to connect to the websocket: ' + err + '\n\nPlease try loading this page again.'); - }); - - Socket.on('live-stats', function (data) { - $.each(data.servers, function (uuid, info) { - var element = $('tr[data-server="' + uuid + '"]'); - switch (info.status) { - case 0: - element.find('[data-action="status"]').html('Offline'); - break; - case 1: - element.find('[data-action="status"]').html('Online'); - break; - case 2: - element.find('[data-action="status"]').html('Starting'); - break; - case 3: - element.find('[data-action="status"]').html('Stopping'); - break; - case 20: - element.find('[data-action="status"]').html('Installing'); - break; - case 30: - element.find('[data-action="status"]').html('Suspended'); - break; - } - if (info.status !== 0) { - var cpuMax = element.find('[data-action="cpu"]').data('cpumax'); - var currentCpu = info.proc.cpu.total; - if (cpuMax !== 0) { - currentCpu = parseFloat(((info.proc.cpu.total / cpuMax) * 100).toFixed(2).toString()); - } - element.find('[data-action="memory"]').html(parseInt(info.proc.memory.total / (1024 * 1024))); - element.find('[data-action="disk"]').html(parseInt(info.proc.disk.used)); - element.find('[data-action="cpu"]').html(currentCpu); - } else { - element.find('[data-action="memory"]').html('--'); - element.find('[data-action="disk"]').html('--'); - element.find('[data-action="cpu"]').html('--'); - } - }); - }); -})(); \ No newline at end of file diff --git a/resources/views/admin/nodes/view/servers.blade.php b/resources/views/admin/nodes/view/servers.blade.php index 17d6d531b..b8b9ee514 100644 --- a/resources/views/admin/nodes/view/servers.blade.php +++ b/resources/views/admin/nodes/view/servers.blade.php @@ -1,8 +1,3 @@ -{{-- 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') @@ -46,10 +41,6 @@ Server Name Owner Service - Memory - Disk - CPU - Status @foreach($servers as $server) @@ -57,10 +48,6 @@ {{ $server->name }} {{ $server->user->username }} {{ $server->nest->name }} ({{ $server->egg->name }}) - -- / {{ $server->memory === 0 ? '∞' : $server->memory }} MB - -- / {{ $server->disk === 0 ? '∞' : $server->disk }} MB - -- % - -- @endforeach @@ -74,8 +61,3 @@ @endsection - -@section('footer-scripts') - @parent - {!! Theme::js('js/admin/node/view-servers.js') !!} -@endsection \ No newline at end of file From 95b27a8d56dbc6595a9b23a4189aaeff1f0af80d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Wed, 16 Sep 2020 20:28:38 -0700 Subject: [PATCH 04/96] Remove unused views --- resources/views/errors/403.blade.php | 30 -- resources/views/errors/404.blade.php | 31 -- resources/views/errors/503.blade.php | 47 --- resources/views/errors/installing.blade.php | 32 -- resources/views/errors/maintenance.blade.php | 30 -- resources/views/errors/suspended.blade.php | 30 -- resources/views/layouts/admin.blade.php | 1 - resources/views/layouts/auth.blade.php | 64 ---- resources/views/layouts/error.blade.php | 69 ----- resources/views/layouts/master.blade.php | 310 ------------------- 10 files changed, 644 deletions(-) delete mode 100644 resources/views/errors/403.blade.php delete mode 100644 resources/views/errors/404.blade.php delete mode 100644 resources/views/errors/503.blade.php delete mode 100644 resources/views/errors/installing.blade.php delete mode 100644 resources/views/errors/maintenance.blade.php delete mode 100644 resources/views/errors/suspended.blade.php delete mode 100644 resources/views/layouts/auth.blade.php delete mode 100644 resources/views/layouts/error.blade.php delete mode 100644 resources/views/layouts/master.blade.php diff --git a/resources/views/errors/403.blade.php b/resources/views/errors/403.blade.php deleted file mode 100644 index f44fb6f13..000000000 --- a/resources/views/errors/403.blade.php +++ /dev/null @@ -1,30 +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.error') - -@section('title') - @lang('base.errors.403.header') -@endsection - -@section('content-header') -@endsection - -@section('content') -
-
-
-
-

403

-

@lang('base.errors.403.desc')

-
- -
-
-
-@endsection diff --git a/resources/views/errors/404.blade.php b/resources/views/errors/404.blade.php deleted file mode 100644 index b178dccd1..000000000 --- a/resources/views/errors/404.blade.php +++ /dev/null @@ -1,31 +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.error') - -@section('title') - @lang('base.errors.404.header') -@endsection - -@section('content-header') -@endsection - -@section('content') - -
-
-
-
-

404

-

@lang('base.errors.404.desc')

-
- -
-
-
-@endsection diff --git a/resources/views/errors/503.blade.php b/resources/views/errors/503.blade.php deleted file mode 100644 index 7d55e46ad..000000000 --- a/resources/views/errors/503.blade.php +++ /dev/null @@ -1,47 +0,0 @@ - - - - Be right back. - - - - - - -
-
-
Be right back!
-
-
- - diff --git a/resources/views/errors/installing.blade.php b/resources/views/errors/installing.blade.php deleted file mode 100644 index c9f43e657..000000000 --- a/resources/views/errors/installing.blade.php +++ /dev/null @@ -1,32 +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.error') - -@section('title') - @lang('base.errors.installing.header') -@endsection - -@section('content-header') -@endsection - -@section('content') -
-
-
-
-
-
-
-

@lang('base.errors.installing.desc')

-
- -
-
-
-@endsection diff --git a/resources/views/errors/maintenance.blade.php b/resources/views/errors/maintenance.blade.php deleted file mode 100644 index 8cc8eea27..000000000 --- a/resources/views/errors/maintenance.blade.php +++ /dev/null @@ -1,30 +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.error') - -@section('title') - @lang('base.errors.maintenance.header') -@endsection - -@section('content-header') -@endsection - -@section('content') -
-
-
-
-

@lang('base.errors.maintenance.title')

-

@lang('base.errors.maintenance.desc')

-
- -
-
-
-@endsection diff --git a/resources/views/errors/suspended.blade.php b/resources/views/errors/suspended.blade.php deleted file mode 100644 index 86e804f69..000000000 --- a/resources/views/errors/suspended.blade.php +++ /dev/null @@ -1,30 +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.error') - -@section('title') - @lang('base.errors.suspended.header') -@endsection - -@section('content-header') -@endsection - -@section('content') -
-
-
-
-

403

-

@lang('base.errors.suspended.desc')

-
- -
-
-
-@endsection diff --git a/resources/views/layouts/admin.blade.php b/resources/views/layouts/admin.blade.php index 0680b8d58..e885183e8 100644 --- a/resources/views/layouts/admin.blade.php +++ b/resources/views/layouts/admin.blade.php @@ -176,7 +176,6 @@ {!! Theme::js('vendor/bootstrap/bootstrap.min.js?t={cache-version}') !!} {!! Theme::js('vendor/slimscroll/jquery.slimscroll.min.js?t={cache-version}') !!} {!! Theme::js('vendor/adminlte/app.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/socketio/socket.io.v203.min.js?t={cache-version}') !!} {!! Theme::js('vendor/bootstrap-notify/bootstrap-notify.min.js?t={cache-version}') !!} {!! Theme::js('vendor/select2/select2.full.min.js?t={cache-version}') !!} {!! Theme::js('js/admin/functions.js?t={cache-version}') !!} diff --git a/resources/views/layouts/auth.blade.php b/resources/views/layouts/auth.blade.php deleted file mode 100644 index 9d6655de2..000000000 --- a/resources/views/layouts/auth.blade.php +++ /dev/null @@ -1,64 +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 --}} - - - - - - {{ config('app.name', 'Pterodactyl') }} - @yield('title') - - - - - - - - - - - - @section('scripts') - {!! Theme::css('vendor/bootstrap/bootstrap.min.css?t={cache-version}') !!} - {!! Theme::css('vendor/adminlte/admin.min.css?t={cache-version}') !!} - {!! Theme::css('css/pterodactyl.css?t={cache-version}') !!} - - - - - @show - - -
-
- - @yield('content') - -
-
- - - {!! Theme::js('vendor/jquery/jquery.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/bootstrap/bootstrap.min.js?t={cache-version}') !!} - - {!! Theme::js('vendor/particlesjs/particles.min.js?t={cache-version}') !!} - - - diff --git a/resources/views/layouts/error.blade.php b/resources/views/layouts/error.blade.php deleted file mode 100644 index 89b85fd2d..000000000 --- a/resources/views/layouts/error.blade.php +++ /dev/null @@ -1,69 +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 --}} - - - - - - {{ config('app.name', 'Pterodactyl') }} - @yield('title') - - - - - - - - - - - - - @section('scripts') - {!! Theme::css('vendor/bootstrap/bootstrap.min.css?t={cache-version}') !!} - {!! Theme::css('vendor/adminlte/admin.min.css?t={cache-version}') !!} - {!! Theme::css('vendor/adminlte/colors/skin-blue.min.css?t={cache-version}') !!} - {!! Theme::css('vendor/sweetalert/sweetalert.min.css?t={cache-version}') !!} - {!! Theme::css('css/pterodactyl.css?t={cache-version}') !!} - - - - - @show - - -
-
- - -
-
-
- @yield('content-header') -
-
- @yield('content') -
-
- -
- @section('footer-scripts') - {!! Theme::js('vendor/jquery/jquery.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/bootstrap/bootstrap.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/slimscroll/jquery.slimscroll.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/adminlte/app.min.js?t={cache-version}') !!} - @show - - diff --git a/resources/views/layouts/master.blade.php b/resources/views/layouts/master.blade.php deleted file mode 100644 index b81906271..000000000 --- a/resources/views/layouts/master.blade.php +++ /dev/null @@ -1,310 +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 --}} - - - - - - {{ config('app.name', 'Pterodactyl') }} - @yield('title') - - - - - - - - - - - - - @include('layouts.scripts') - - @section('scripts') - {!! Theme::css('vendor/bootstrap/bootstrap.min.css?t={cache-version}') !!} - {!! Theme::css('vendor/adminlte/admin.min.css?t={cache-version}') !!} - {!! Theme::css('vendor/adminlte/colors/skin-blue.min.css?t={cache-version}') !!} - {!! Theme::css('vendor/sweetalert/sweetalert.min.css?t={cache-version}') !!} - {!! Theme::css('vendor/animate/animate.min.css?t={cache-version}') !!} - {!! Theme::css('css/pterodactyl.css?t={cache-version}') !!} - - - - - @show - - -
-
- - -
- -
-
- @yield('content-header') -
-
-
-
- @if (count($errors) > 0) -
- There was an error validating the data provided.

-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
- @endif - @foreach (Alert::getMessages() as $type => $messages) - @foreach ($messages as $message) - - @endforeach - @endforeach -
-
- @yield('content') -
-
-
-
- {{ $appVersion }}
- {{ round(microtime(true) - LARAVEL_START, 3) }}s -
- Copyright © 2015 - {{ date('Y') }} Pterodactyl Software. -
- @if(isset($sidebarServerList)) - - @endif -
-
- @section('footer-scripts') - - - - {!! Theme::js('vendor/jquery/jquery.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/sweetalert/sweetalert.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/bootstrap/bootstrap.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/slimscroll/jquery.slimscroll.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/adminlte/app.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/socketio/socket.io.v203.min.js?t={cache-version}') !!} - {!! Theme::js('vendor/bootstrap-notify/bootstrap-notify.min.js?t={cache-version}') !!} - - - @if(Auth::user()->root_admin) - - @endif - @show - - From 607184e57811140da467c4a487a45023b9f28db4 Mon Sep 17 00:00:00 2001 From: Charles Morgan Date: Thu, 17 Sep 2020 00:01:48 -0400 Subject: [PATCH 05/96] Schedule Fixes Limiting Schedule name 75>255 Moved Payload to bottom of new task window Closes #2346 --- app/Models/Schedule.php | 2 +- .../server/schedules/ScheduleTaskRow.tsx | 2 +- .../server/schedules/TaskDetailsModal.tsx | 77 ++++++++++--------- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/app/Models/Schedule.php b/app/Models/Schedule.php index 384d354ad..f72b866d4 100644 --- a/app/Models/Schedule.php +++ b/app/Models/Schedule.php @@ -103,7 +103,7 @@ class Schedule extends Model */ public static $validationRules = [ 'server_id' => 'required|exists:servers,id', - 'name' => 'nullable|string|max:255', + 'name' => 'nullable|string|max:75', 'cron_day_of_week' => 'required|string', 'cron_day_of_month' => 'required|string', 'cron_hour' => 'required|string', diff --git a/resources/scripts/components/server/schedules/ScheduleTaskRow.tsx b/resources/scripts/components/server/schedules/ScheduleTaskRow.tsx index 4ab5eeef6..7674553cb 100644 --- a/resources/scripts/components/server/schedules/ScheduleTaskRow.tsx +++ b/resources/scripts/components/server/schedules/ScheduleTaskRow.tsx @@ -81,7 +81,7 @@ export default ({ schedule, task }: Props) => {
{task.action === 'backup' &&

Ignoring files & folders:

} -
+
{task.payload}
diff --git a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx index 1ef64c138..e1fca0cb0 100644 --- a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx +++ b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx @@ -57,45 +57,46 @@ const TaskDetailsForm = ({ isEditingTask }: { isEditingTask: boolean }) => {
-
- {action === 'command' ? - - : - action === 'power' ? -
- - - - - - - - - -
- : -
- - - - -
- } +
+
- + {action === 'command' ? +
+ + + + +
+ : + action === 'power' ? +
+ + + + + + + + + +
+ : +
+ + + + +
+ }
diff --git a/resources/views/admin/mounts/index.blade.php b/resources/views/admin/mounts/index.blade.php index da554cd04..309dc3c17 100644 --- a/resources/views/admin/mounts/index.blade.php +++ b/resources/views/admin/mounts/index.blade.php @@ -84,7 +84,7 @@
-

A longer description for this mount, must be less than 255 characters.

+

A longer description for this mount, must be less than 191 characters.

From 47697e07cfeee569bea15d57ab1eaac07a89cfc4 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Sep 2020 17:25:14 -0700 Subject: [PATCH 29/96] Add test coverage for creating a subuser --- .../Subuser/CreateServerSubuserTest.php | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 tests/Integration/Api/Client/Server/Subuser/CreateServerSubuserTest.php diff --git a/tests/Integration/Api/Client/Server/Subuser/CreateServerSubuserTest.php b/tests/Integration/Api/Client/Server/Subuser/CreateServerSubuserTest.php new file mode 100644 index 000000000..53a299e02 --- /dev/null +++ b/tests/Integration/Api/Client/Server/Subuser/CreateServerSubuserTest.php @@ -0,0 +1,166 @@ +generateTestAccount($permissions); + + $response = $this->actingAs($user)->postJson($this->link($server) . "/users", [ + 'email' => $email = $this->faker->email, + 'permissions' => [ + Permission::ACTION_USER_CREATE, + ], + ]); + + $response->assertOk(); + + /** @var \Pterodactyl\Models\User $subuser */ + $subuser = User::query()->where('email', $email)->firstOrFail(); + + $response->assertJsonPath('object', Subuser::RESOURCE_NAME); + $response->assertJsonPath('attributes.uuid', $subuser->uuid); + $response->assertJsonPath('attributes.permissions', [ + Permission::ACTION_USER_CREATE, + Permission::ACTION_WEBSOCKET_CONNECT, + ]); + + $expected = $response->json('attributes'); + unset($expected['permissions']); + + $this->assertJsonTransformedWith($expected, $subuser); + } + + /** + * Tests that an error is returned if a subuser attempts to create a new subuser and assign + * permissions that their account does not also possess. + */ + public function testErrorIsReturnedIfAssigningPermissionsNotAssignedToSelf() + { + [$user, $server] = $this->generateTestAccount([ + Permission::ACTION_USER_CREATE, + Permission::ACTION_USER_READ, + Permission::ACTION_CONTROL_CONSOLE, + ]); + + $response = $this->actingAs($user)->postJson($this->link($server) . "/users", [ + 'email' => $email = $this->faker->email, + 'permissions' => [ + Permission::ACTION_USER_CREATE, + Permission::ACTION_USER_UPDATE, // This permission is not assigned to the subuser. + ], + ]); + + $response->assertForbidden(); + $response->assertJsonPath('errors.0.code', 'HttpForbiddenException'); + $response->assertJsonPath('errors.0.detail', 'Cannot assign permissions to a subuser that your account does not actively possess.'); + } + + /** + * Throws some bad data at the API and ensures that a subuser cannot be created. + */ + public function testSubuserWithExcessivelyLongEmailCannotBeCreated() + { + [$user, $server] = $this->generateTestAccount(); + + $email = str_repeat(Str::random(20), 9) . '1@gmail.com'; // 191 is the hard limit for the column in MySQL. + + $response = $this->actingAs($user)->postJson($this->link($server) . "/users", [ + 'email' => $email, + 'permissions' => [ + Permission::ACTION_USER_CREATE, + ], + ]); + + $response->assertOk(); + + $response = $this->actingAs($user)->postJson($this->link($server) . "/users", [ + 'email' => $email . '.au', + 'permissions' => [ + Permission::ACTION_USER_CREATE, + ], + ]); + + $response->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY); + $response->assertJsonPath('errors.0.detail', 'The email must be between 1 and 191 characters.'); + $response->assertJsonPath('errors.0.meta.source_field', 'email'); + } + + /** + * Test that creating a subuser when there is already an account with that email runs + * as expected and does not create a new account. + */ + public function testCreatingSubuserWithSameEmailAsExistingUserWorks() + { + [$user, $server] = $this->generateTestAccount(); + + /** @var \Pterodactyl\Models\User $existing */ + $existing = factory(User::class)->create(['email' => $this->faker->email]); + + $response = $this->actingAs($user)->postJson($this->link($server) . "/users", [ + 'email' => $existing->email, + 'permissions' => [ + Permission::ACTION_USER_CREATE, + ], + ]); + + $response->assertOk(); + $response->assertJsonPath('object', Subuser::RESOURCE_NAME); + $response->assertJsonPath('attributes.uuid', $existing->uuid); + } + + /** + * Test that an error is returned if the account associated with an email address is already + * associated with the server instance. + */ + public function testAddingSubuserThatAlreadyIsAssignedReturnsError() + { + [$user, $server] = $this->generateTestAccount(); + + $response = $this->actingAs($user)->postJson($this->link($server) . "/users", [ + 'email' => $email = $this->faker->email, + 'permissions' => [ + Permission::ACTION_USER_CREATE, + ], + ]); + + $response->assertOk(); + + $response = $this->actingAs($user)->postJson($this->link($server) . "/users", [ + 'email' => $email, + 'permissions' => [ + Permission::ACTION_USER_CREATE, + ], + ]); + + $response->assertStatus(Response::HTTP_BAD_REQUEST); + $response->assertJsonPath('errors.0.code', 'ServerSubuserExistsException'); + $response->assertJsonPath('errors.0.detail', 'A user with that email address is already assigned as a subuser for this server.'); + } + + /** + * @return array + */ + public function permissionsDataProvider(): array + { + return [[[]], [[Permission::ACTION_USER_CREATE]]]; + } +} From 3e899ffc5177fcf5a941c6582550fedd00302f19 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 27 Sep 2020 09:22:09 -0700 Subject: [PATCH 30/96] Handle JWT expirations a little better --- .../components/server/WebsocketHandler.tsx | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/resources/scripts/components/server/WebsocketHandler.tsx b/resources/scripts/components/server/WebsocketHandler.tsx index fe43e56d5..f53466e0a 100644 --- a/resources/scripts/components/server/WebsocketHandler.tsx +++ b/resources/scripts/components/server/WebsocketHandler.tsx @@ -8,20 +8,27 @@ import Spinner from '@/components/elements/Spinner'; import tw from 'twin.macro'; export default () => { - const server = ServerContext.useStoreState(state => state.server.data); - const [ error, setError ] = useState(false); + let updatingToken = false; + const [ error, setError ] = useState<'connecting' | string>(''); const { connected, instance } = ServerContext.useStoreState(state => state.socket); + const uuid = ServerContext.useStoreState(state => state.server.data?.uuid); const setServerStatus = ServerContext.useStoreActions(actions => actions.status.setServerStatus); const { setInstance, setConnectionState } = ServerContext.useStoreActions(actions => actions.socket); const updateToken = (uuid: string, socket: Websocket) => { + if (updatingToken) return; + + updatingToken = true; getWebsocketToken(uuid) .then(data => socket.setToken(data.token, true)) - .catch(error => console.error(error)); + .catch(error => console.error(error)) + .then(() => { + updatingToken = false; + }); }; useEffect(() => { - connected && setError(false); + connected && setError(''); }, [ connected ]); useEffect(() => { @@ -33,7 +40,7 @@ export default () => { useEffect(() => { // If there is already an instance or there is no server, just exit out of this process // since we don't need to make a new connection. - if (instance || !server) { + if (instance || !uuid) { return; } @@ -42,7 +49,7 @@ export default () => { socket.on('auth success', () => setConnectionState(true)); socket.on('SOCKET_CLOSE', () => setConnectionState(false)); socket.on('SOCKET_ERROR', () => { - setError(true); + setError('connecting'); setConnectionState(false); }); socket.on('status', (status) => setServerStatus(status)); @@ -51,10 +58,20 @@ export default () => { console.warn('Got error message from daemon socket:', message); }); - socket.on('token expiring', () => updateToken(server.uuid, socket)); - socket.on('token expired', () => updateToken(server.uuid, socket)); + socket.on('token expiring', () => updateToken(uuid, socket)); + socket.on('token expired', () => updateToken(uuid, socket)); + socket.on('jwt error', (error: string) => { + setConnectionState(false); + console.warn('JWT validation error from wings:', error); - getWebsocketToken(server.uuid) + if (error === 'jwt: exp claim is invalid') { + updateToken(uuid, socket); + } else { + setError('There was an error validating the credentials provided for the websocket. Please refresh the page.'); + } + }); + + getWebsocketToken(uuid) .then(data => { // Connect and then set the authentication token. socket.setToken(data.token).connect(data.socket); @@ -63,17 +80,25 @@ export default () => { setInstance(socket); }) .catch(error => console.error(error)); - }, [ server ]); + }, [ uuid ]); return ( error ?
- -

- We're having some trouble connecting to your server, please wait... -

+ {error === 'connecting' ? + <> + +

+ We're having some trouble connecting to your server, please wait... +

+ + : +

+ {error} +

+ }
From da0b5277152a46d4ba93502de9e8e52642d92540 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 27 Sep 2020 09:30:05 -0700 Subject: [PATCH 31/96] Do not re-render rows excessively --- .../scripts/components/server/files/FileObjectRow.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/resources/scripts/components/server/files/FileObjectRow.tsx b/resources/scripts/components/server/files/FileObjectRow.tsx index 0e05820bd..53005653b 100644 --- a/resources/scripts/components/server/files/FileObjectRow.tsx +++ b/resources/scripts/components/server/files/FileObjectRow.tsx @@ -92,4 +92,11 @@ const FileObjectRow = ({ file }: { file: FileObject }) => ( ); -export default memo(FileObjectRow, isEqual); +export default memo(FileObjectRow, (prevProps, nextProps) => { + /* eslint-disable @typescript-eslint/no-unused-vars */ + const { isArchiveType, isEditable, ...prevFile } = prevProps.file; + const { isArchiveType: nextIsArchiveType, isEditable: nextIsEditable, ...nextFile } = nextProps.file; + /* eslint-enable @typescript-eslint/no-unused-vars */ + + return isEqual(prevFile, nextFile); +}); From ff50940fa67dd193d8a671dc7344d2c3da7307d5 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 27 Sep 2020 09:30:24 -0700 Subject: [PATCH 32/96] Fix keyboard save shortcut when saving a new file; closes #2427 --- .../scripts/components/server/files/FileEditContainer.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/scripts/components/server/files/FileEditContainer.tsx b/resources/scripts/components/server/files/FileEditContainer.tsx index 5d8102728..87eda2eb5 100644 --- a/resources/scripts/components/server/files/FileEditContainer.tsx +++ b/resources/scripts/components/server/files/FileEditContainer.tsx @@ -116,7 +116,13 @@ export default () => { fetchContent={value => { fetchFileContent = value; }} - onContentSaved={save} + onContentSaved={() => { + if (action !== 'edit') { + setModalVisible(true); + } else { + save(); + } + }} />
From 1db7e4db665ebac61510dbf90c93abf145e264dc Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 27 Sep 2020 09:45:37 -0700 Subject: [PATCH 33/96] Request stats from wings when loading the console; closes pterodactyl/panel#2414 --- resources/scripts/components/server/Console.tsx | 1 + resources/scripts/components/server/ServerConsole.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/resources/scripts/components/server/Console.tsx b/resources/scripts/components/server/Console.tsx index 49fb59cf0..3840934b8 100644 --- a/resources/scripts/components/server/Console.tsx +++ b/resources/scripts/components/server/Console.tsx @@ -52,6 +52,7 @@ const TerminalDiv = styled.div` export default () => { const TERMINAL_PRELUDE = '\u001b[1m\u001b[33mcontainer@pterodactyl~ \u001b[0m'; const [ terminalElement, setTerminalElement ] = useState(null); + const useRef = useCallback(node => setTerminalElement(node), []); const terminal = useMemo(() => new Terminal({ ...terminalProps }), []); const { connected, instance } = ServerContext.useStoreState(state => state.socket); diff --git a/resources/scripts/components/server/ServerConsole.tsx b/resources/scripts/components/server/ServerConsole.tsx index d3068c8f1..05470078a 100644 --- a/resources/scripts/components/server/ServerConsole.tsx +++ b/resources/scripts/components/server/ServerConsole.tsx @@ -53,6 +53,7 @@ export default () => { } instance.addListener('stats', statsListener); + instance.send('send stats'); return () => { instance.removeListener('stats', statsListener); From f31a6d3967b89b7b37ef41d677efd0add73de606 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 27 Sep 2020 10:39:18 -0700 Subject: [PATCH 34/96] Fix parameter bindings for client API routes; closes pterodactyl/panel#2359 --- .../Client/SubstituteClientApiBindings.php | 4 +- .../Subuser/CreateServerSubuserTest.php | 2 +- .../Server/Subuser/DeleteSubuserTest.php | 59 +++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 tests/Integration/Api/Client/Server/Subuser/DeleteSubuserTest.php diff --git a/app/Http/Middleware/Api/Client/SubstituteClientApiBindings.php b/app/Http/Middleware/Api/Client/SubstituteClientApiBindings.php index 77879c97f..7ab597b63 100644 --- a/app/Http/Middleware/Api/Client/SubstituteClientApiBindings.php +++ b/app/Http/Middleware/Api/Client/SubstituteClientApiBindings.php @@ -49,11 +49,11 @@ class SubstituteClientApiBindings extends ApiSubstituteBindings return Database::query()->where('id', $id)->firstOrFail(); }); - $this->router->model('backup', Backup::class, function ($value) { + $this->router->bind('backup', function ($value) { return Backup::query()->where('uuid', $value)->firstOrFail(); }); - $this->router->model('user', User::class, function ($value) { + $this->router->bind('user', function ($value) { return User::query()->where('uuid', $value)->firstOrFail(); }); diff --git a/tests/Integration/Api/Client/Server/Subuser/CreateServerSubuserTest.php b/tests/Integration/Api/Client/Server/Subuser/CreateServerSubuserTest.php index 53a299e02..3a1f8bc6b 100644 --- a/tests/Integration/Api/Client/Server/Subuser/CreateServerSubuserTest.php +++ b/tests/Integration/Api/Client/Server/Subuser/CreateServerSubuserTest.php @@ -1,6 +1,6 @@ generateTestAccount(); + + /** @var \Pterodactyl\Models\User $differentUser */ + $differentUser = factory(User::class)->create(); + + // Generate a UUID that lines up with a user in the database if it were to be cast to an int. + $uuid = $differentUser->id . str_repeat('a', strlen((string)$differentUser->id)) . substr(Uuid::uuid4()->toString(), 8); + + /** @var \Pterodactyl\Models\User $subuser */ + $subuser = factory(User::class)->create(['uuid' => $uuid]); + + Subuser::query()->forceCreate([ + 'user_id' => $subuser->id, + 'server_id' => $server->id, + 'permissions' => [ Permission::ACTION_WEBSOCKET_CONNECT ], + ]); + + $this->actingAs($user)->deleteJson($this->link($server) . "/users/{$subuser->uuid}")->assertNoContent(); + + // Try the same test, but this time with a UUID that if cast to an int (shouldn't) line up with + // anything in the database. + $uuid = '18180000' . substr(Uuid::uuid4()->toString(), 8); + /** @var \Pterodactyl\Models\User $subuser */ + $subuser = factory(User::class)->create(['uuid' => $uuid]); + + Subuser::query()->forceCreate([ + 'user_id' => $subuser->id, + 'server_id' => $server->id, + 'permissions' => [ Permission::ACTION_WEBSOCKET_CONNECT ], + ]); + + $this->actingAs($user)->deleteJson($this->link($server) . "/users/{$subuser->uuid}")->assertNoContent(); + } +} From 1616cf1318854e9f8d9bdeb0862c5fdea589a7d1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Oct 2020 11:18:14 -0700 Subject: [PATCH 35/96] Always show errors from HTTP exceptions correctly to the user; closes #2439 --- app/Exceptions/Handler.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index f84c7077b..7cd007792 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\ModelNotFoundException; use Symfony\Component\HttpKernel\Exception\HttpException; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; +use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; class Handler extends ExceptionHandler { @@ -217,7 +218,9 @@ class Handler extends ExceptionHandler 'status' => method_exists($exception, 'getStatusCode') ? strval($exception->getStatusCode()) : ($exception instanceof ValidationException ? '422' : '500'), - 'detail' => 'An error was encountered while processing this request.', + 'detail' => $exception instanceof HttpExceptionInterface + ? $exception->getMessage() + : 'An unexpected error was ecnountered while processing this request, please try again.', ]; if ($exception instanceof ModelNotFoundException || $exception->getPrevious() instanceof ModelNotFoundException) { From 6893f9bfcdc858a17f2e7144967ba84917a7ff9f Mon Sep 17 00:00:00 2001 From: Oreo Oreoniv <28255085+zKoz210@users.noreply.github.com> Date: Sat, 3 Oct 2020 21:21:09 +0300 Subject: [PATCH 36/96] Fixes for mobile responsiveness on the console page (#2411) --- .../components/server/ServerConsole.tsx | 4 +- .../scripts/components/server/StatGraphs.tsx | 40 ++++++++++--------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/resources/scripts/components/server/ServerConsole.tsx b/resources/scripts/components/server/ServerConsole.tsx index 05470078a..edf10d130 100644 --- a/resources/scripts/components/server/ServerConsole.tsx +++ b/resources/scripts/components/server/ServerConsole.tsx @@ -65,7 +65,7 @@ export default () => { return ( -
+

{

}
-
+
diff --git a/resources/scripts/components/server/StatGraphs.tsx b/resources/scripts/components/server/StatGraphs.tsx index 399b96724..725373b30 100644 --- a/resources/scripts/components/server/StatGraphs.tsx +++ b/resources/scripts/components/server/StatGraphs.tsx @@ -142,24 +142,28 @@ export default () => { return (
- - {status !== 'offline' ? - - : -

- Server is offline. -

- } -
- - {status !== 'offline' ? - - : -

- Server is offline. -

- } -
+
+ + {status !== 'offline' ? + + : +

+ Server is offline. +

+ } +
+
+
+ + {status !== 'offline' ? + + : +

+ Server is offline. +

+ } +
+
); }; From 10eeae09273dc20f24f9929567e04a4d0f6e0e34 Mon Sep 17 00:00:00 2001 From: Oreo Oreoniv <28255085+zKoz210@users.noreply.github.com> Date: Sat, 3 Oct 2020 21:22:37 +0300 Subject: [PATCH 37/96] Fix text overflows through out the front end (#2406) --- resources/scripts/components/elements/Modal.tsx | 2 ++ resources/scripts/components/server/backups/BackupRow.tsx | 4 +++- resources/scripts/components/server/files/FileObjectRow.tsx | 2 +- .../scripts/components/server/files/NewDirectoryButton.tsx | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/resources/scripts/components/elements/Modal.tsx b/resources/scripts/components/elements/Modal.tsx index 10401e9ca..2980fecd9 100644 --- a/resources/scripts/components/elements/Modal.tsx +++ b/resources/scripts/components/elements/Modal.tsx @@ -35,6 +35,8 @@ const ModalContainer = styled.div<{ alignTop?: boolean }>` margin-top: 20%; ${breakpoint('md')`margin-top: 10%`}; `}; + + margin-bottom: 5%; & > .close-icon { ${tw`absolute right-0 p-2 text-white cursor-pointer opacity-50 transition-all duration-150 ease-linear hover:opacity-100`}; diff --git a/resources/scripts/components/server/backups/BackupRow.tsx b/resources/scripts/components/server/backups/BackupRow.tsx index 0a45c7ca9..fbbb849f9 100644 --- a/resources/scripts/components/server/backups/BackupRow.tsx +++ b/resources/scripts/components/server/backups/BackupRow.tsx @@ -55,7 +55,9 @@ export default ({ backup, className }: Props) => { Failed } - {backup.name} +
+ {backup.name} +
{(backup.completedAt && backup.isSuccessful) && } diff --git a/resources/scripts/components/server/files/FileObjectRow.tsx b/resources/scripts/components/server/files/FileObjectRow.tsx index 53005653b..43416eb4c 100644 --- a/resources/scripts/components/server/files/FileObjectRow.tsx +++ b/resources/scripts/components/server/files/FileObjectRow.tsx @@ -69,7 +69,7 @@ const FileObjectRow = ({ file }: { file: FileObject }) => ( }
-
+
{file.name}
{file.isFile && diff --git a/resources/scripts/components/server/files/NewDirectoryButton.tsx b/resources/scripts/components/server/files/NewDirectoryButton.tsx index e1f92e0e7..2be673db9 100644 --- a/resources/scripts/components/server/files/NewDirectoryButton.tsx +++ b/resources/scripts/components/server/files/NewDirectoryButton.tsx @@ -88,7 +88,7 @@ export default ({ className }: WithClassname) => { name={'directoryName'} label={'Directory Name'} /> -

+

This directory will be created as  /home/container/ From 3473e1dfbfe6ff2c05aa9c338a74014c55d55f91 Mon Sep 17 00:00:00 2001 From: Charles Morgan Date: Sat, 3 Oct 2020 14:23:16 -0400 Subject: [PATCH 38/96] Remove console logging (#2415) Remove console logging, as its not an error being logged i see no reason for this to be printed when the startup page is viewed. --- resources/scripts/api/swr/getServerStartup.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/scripts/api/swr/getServerStartup.ts b/resources/scripts/api/swr/getServerStartup.ts index fff0263f9..892f78fdd 100644 --- a/resources/scripts/api/swr/getServerStartup.ts +++ b/resources/scripts/api/swr/getServerStartup.ts @@ -9,7 +9,6 @@ interface Response { } export default (uuid: string, initialData?: Response) => useSWR([ uuid, '/startup' ], async (): Promise => { - console.log('firing getServerStartup'); const { data } = await http.get(`/api/client/servers/${uuid}/startup`); const variables = ((data as FractalResponseList).data || []).map(rawDataToServerEggVariable); From 62856556b901def3dcc651e6ee9f114191443c9b Mon Sep 17 00:00:00 2001 From: Stepan Fedotov Date: Sat, 3 Oct 2020 19:55:35 +0300 Subject: [PATCH 39/96] Apply security fixes from #2441 to 1.0 --- CHANGELOG.md | 13 ++++++- .../themes/pterodactyl/js/admin/new-server.js | 37 +++++++++++-------- .../admin/servers/view/details.blade.php | 18 ++++++--- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efd2cef5b..8958e82be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ This file is a running track of new features and fixes to each version of the pa This project follows [Semantic Versioning](http://semver.org) guidelines. +## v0.7.19 (Derelict Dermodactylus) +### Fixed +* **[Security]** Fixes XSS in the admin area's server owner selection. + +## v0.7.18 (Derelict Dermodactylus) +### Fixed +* **[Security]** Re-addressed missed endpoint that would not properly limit a user account to 5 API keys. +* **[Security]** Addresses a Client API vulnerability that would allow a user to list all servers on the system ([`GHSA-6888-7f3w-92jx`](https://github.com/pterodactyl/panel/security/advisories/GHSA-6888-7f3w-92jx)) + ## v0.7.17 (Derelict Dermodactylus) ### Fixed * Limited accounts to 5 API keys at a time. @@ -301,7 +310,7 @@ the response from the server `GET` endpoint. * Nest and Egg listings now show the associated ID in order to make API requests easier. * Added star indicators to user listing in Admin CP to indicate users who are set as a root admin. * Creating a new node will now requires a SSL connection if the Panel is configured to use SSL as well. -* Connector error messages due to permissions are now rendered correctly in the UI rather than causing a silent failure. +* Socketio error messages due to permissions are now rendered correctly in the UI rather than causing a silent failure. * File manager now supports mass deletion option for files and folders. * Support for CS:GO as a default service option selection. * Support for GMOD as a default service option selection. @@ -431,7 +440,7 @@ the response from the server `GET` endpoint. * Changed 2FA login process to be more secure. Previously authentication checking happened on the 2FA post page, now it happens prior and is passed along to the 2FA page to avoid storing any credentials. ### Added -* Connector error messages due to permissions are now rendered correctly in the UI rather than causing a silent failure. +* Socketio error messages due to permissions are now rendered correctly in the UI rather than causing a silent failure. ## v0.7.0-beta.1 (Derelict Dermodactylus) ### Added diff --git a/public/themes/pterodactyl/js/admin/new-server.js b/public/themes/pterodactyl/js/admin/new-server.js index 7416451da..cda0d5cf3 100644 --- a/public/themes/pterodactyl/js/admin/new-server.js +++ b/public/themes/pterodactyl/js/admin/new-server.js @@ -153,6 +153,12 @@ function updateAdditionalAllocations() { } function initUserIdSelect(data) { + function escapeHtml(str) { + var div = document.createElement('div'); + div.appendChild(document.createTextNode(str)); + return div.innerHTML; + } + $('#pUserId').select2({ ajax: { url: '/admin/users/accounts.json', @@ -176,28 +182,27 @@ function initUserIdSelect(data) { data: data, escapeMarkup: function (markup) { return markup; }, minimumInputLength: 2, - templateResult: function (data) { - if (data.loading) return data.text; + if (data.loading) return escapeHtml(data.text); return '

\ - User Image \ - \ - ' + data.name_first + ' ' + data.name_last +' \ - \ - ' + data.email + ' - ' + data.username + ' \ -
'; + User Image \ + \ + ' + escapeHtml(data.name_first) + ' ' + escapeHtml(data.name_last) +' \ + \ + ' + escapeHtml(data.email) + ' - ' + escapeHtml(data.username) + ' \ +
'; }, - templateSelection: function (data) { return '
\ - \ - User Image \ - \ - \ - ' + data.name_first + ' ' + data.name_last + ' (' + data.email + ') \ - \ -
'; + \ + User Image \ + \ + \ + ' + escapeHtml(data.name_first) + ' ' + escapeHtml(data.name_last) + ' (' + escapeHtml(data.email) + ') \ + \ +
'; } + }); } diff --git a/resources/views/admin/servers/view/details.blade.php b/resources/views/admin/servers/view/details.blade.php index 38c3a487d..a3d6be628 100644 --- a/resources/views/admin/servers/view/details.blade.php +++ b/resources/views/admin/servers/view/details.blade.php @@ -66,6 +66,12 @@ @section('footer-scripts') @parent - {!! Theme::js('js/admin/new-server.js?v=20200913') !!} + {!! Theme::js('js/admin/new-server.js?v=20201003') !!}