From 0e89ecb42737a0eb3de2facbe3faf1f0b5e9bca5 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 16:19:25 -0500 Subject: [PATCH 01/14] Handle node: properly when doing server searches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uses the node name rather than the node’s ID by default. --- .../Controllers/Admin/ServersController.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 8f0b184c6..15dd1abd6 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -68,14 +68,21 @@ class ServersController extends Controller $match = str_replace('"', '', $match); if (strpos($match, ':')) { list($field, $term) = explode(':', $match); - $field = (strpos($field, '.')) ? $field : 'servers.' . $field; + if ($field === 'node') { + $field = 'nodes.name'; + } else if (!strpos($field, '.')) { + $field = 'servers.' . $field; + } + $query->orWhere($field, 'LIKE', '%' . $term . '%'); } else { $query->where('servers.name', 'LIKE', '%' . $match . '%'); - $query->orWhere('servers.username', 'LIKE', '%' . $match . '%'); - $query->orWhere('users.email', 'LIKE', '%' . $match . '%'); - $query->orWhere('allocations.port', 'LIKE', '%' . $match . '%'); - $query->orWhere('allocations.ip', 'LIKE', '%' . $match . '%'); + $query->orWhere([ + ['servers.username', 'LIKE', '%' . $match . '%'], + ['users.email', 'LIKE', '%' . $match . '%'], + ['allocations.port', 'LIKE', '%' . $match . '%'], + ['allocations.ip', 'LIKE', '%' . $match . '%'], + ]); } } } From 723b608e0c9321843552919c8db3e12703194c47 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 16:29:13 -0500 Subject: [PATCH 02/14] Implement node deletion properly, fixes #173 --- .../Controllers/Admin/NodesController.php | 26 ++++++++++--------- app/Repositories/NodeRepository.php | 26 +++++++++++++++++-- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 24ac37614..ef77da4e0 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -253,20 +253,22 @@ class NodesController extends Controller public function deleteNode(Request $request, $id) { - $node = Models\Node::findOrFail($id); - $servers = Models\Server::where('node', $id)->count(); - if ($servers > 0) { - Alert::danger('You cannot delete a node with servers currently attached to it.')->flash(); - return redirect()->route('admin.nodes.view', [ - 'id' => $id, - 'tab' => 'tab_delete' - ]); + try { + $repo = new NodeRepository; + $repo->delete($id); + Alert::success('Successfully deleted the requested node from the panel.')->flash(); + return redirect()->route('admin.nodes'); + } catch (DisplayException $e) { + Alert::danger($e->getMessage())->flash(); + } catch (\Exception $e) { + Log::error($e); + Alert::danger('An unhandled exception occured while attempting to delete this node. Please try again.')->flash(); } - $node->delete(); - Alert::success('Node successfully deleted.')->flash(); - return redirect()->route('admin.nodes'); - + return redirect()->route('admin.nodes.view', [ + 'id' => $id, + 'tab' => 'tab_delete' + ]); } } diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index a23cc7455..2d579f274 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -229,8 +229,30 @@ class NodeRepository { public function delete($id) { - // @TODO: add logic; - return true; + $node = Models\Node::findOrFail($id); + if (Models\Server::where('node', $id)->count() > 0) { + throw new DisplayException('You cannot delete a node with servers currently attached to it.'); + } + + DB::beginTransaction(); + + try { + // Unlink Database Servers + Models\DatabaseServer::where('linked_node', $node->id)->update([ + 'linked_node' => null, + ]); + + // Delete Allocations + Models\Allocation::where('node', $node->id)->delete(); + + // Delete Node + $node->delete(); + + DB::commit(); + } catch (\Exception $ex) { + DB::rollback(); + throw $ex; + } } } From 1ad715f1a3192524efff9ec5e241d431ec94d5b1 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 17:34:14 -0500 Subject: [PATCH 03/14] Improve database management for servers, fixes #181 --- app/Repositories/DatabaseRepository.php | 40 +++++++++++++------- resources/views/admin/servers/view.blade.php | 2 +- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/app/Repositories/DatabaseRepository.php b/app/Repositories/DatabaseRepository.php index c1c9b4e37..8861549be 100644 --- a/app/Repositories/DatabaseRepository.php +++ b/app/Repositories/DatabaseRepository.php @@ -56,13 +56,12 @@ class DatabaseRepository { } DB::beginTransaction(); - try { $db = new Models\Database; $db->fill([ 'server_id' => $server->id, 'db_server' => $options['db_server'], - 'database' => $server->uuidShort . '_' . $options['database'], + 'database' => "s{$server->id}_{$options['database']}", 'username' => $server->uuidShort . '_' . str_random(7), 'remote' => $options['remote'], 'password' => Crypt::encrypt(str_random(20)) @@ -90,16 +89,29 @@ class DatabaseRepository { $capsule->setAsGlobal(); - Capsule::statement('CREATE DATABASE ' . $db->database); - Capsule::statement('CREATE USER \'' . $db->username . '\'@\'' . $db->remote . '\' IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\''); - Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON ' . $db->database . '.* TO \'' . $db->username . '\'@\'' . $db->remote . '\''); - Capsule::statement('FLUSH PRIVILEGES'); - - DB::commit(); - return true; } catch (\Exception $ex) { - DB::rollback(); - throw $ex; + DB::rollBack(); + throw new DisplayException('There was an error while connecting to the Database Host Server. Please check the error logs.', $ex); + } + + try { + Capsule::statement('CREATE DATABASE `' . $db->database . '`'); + Capsule::statement('CREATE USER `' . $db->username . '`@`' . $db->remote . '` IDENTIFIED BY \'' . Crypt::decrypt($db->password) . '\''); + Capsule::statement('GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX ON `' . $db->database . '`.* TO `' . $db->username . '`@`' . $db->remote . '`'); + Capsule::statement('FLUSH PRIVILEGES'); + DB::commit(); + } catch (\Exception $ex) { + try { + Capsule::statement('DROP DATABASE `' . $db->database . '`'); + Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); + } catch (\Exception $exi) { + // ignore it, if it fails its probably + // because we failed to ever make the DB + // or the user on the system. + } finally { + DB::rollBack(); + throw $ex; + } } } @@ -138,7 +150,7 @@ class DatabaseRepository { $capsule->setAsGlobal(); Capsule::statement(sprintf( - 'SET PASSWORD FOR \'%s\'@\'%s\' = PASSWORD(\'%s\')', + 'SET PASSWORD FOR `%s`@`%s` = PASSWORD(\'%s\')', $db->username, $db->remote, $password @@ -182,8 +194,8 @@ class DatabaseRepository { $capsule->setAsGlobal(); - Capsule::statement('DROP USER \'' . $db->username . '\'@\'' . $db->remote . '\''); - Capsule::statement('DROP DATABASE ' . $db->database); + Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); + Capsule::statement('DROP DATABASE `' . $db->database . '`'); $db->delete(); diff --git a/resources/views/admin/servers/view.blade.php b/resources/views/admin/servers/view.blade.php index d6178d872..cb429ebe9 100644 --- a/resources/views/admin/servers/view.blade.php +++ b/resources/views/admin/servers/view.blade.php @@ -373,7 +373,7 @@
-
{{ $server->uuidShort }}_
+
s{{ $server->id }}_
From d93f88f4713164b7947b8f51dca820c6f960d810 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 17:49:56 -0500 Subject: [PATCH 04/14] Properly display node status with newer daemon versions --- resources/views/admin/nodes/index.blade.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index dcfd41629..689a9dda4 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -78,6 +78,9 @@ function pingNodes() { $.ajax({ type: 'GET', url: $(element).data('location'), + headers: { + 'X-Access-Token': '{{ $node->daemonSecret }}' + }, timeout: 5000 }).done(function (data) { $(element).removeClass('text-muted').find('i').removeClass().addClass('fa fa-fw fa-heartbeat faa-pulse animated').css('color', '#50af51'); From edaae40df939bd6ad182e8bd7fa135202ef512b7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 18:23:10 -0500 Subject: [PATCH 05/14] Add some quick daemon information when viewing nodes --- resources/views/admin/nodes/index.blade.php | 37 +++++++++++---------- resources/views/admin/nodes/view.blade.php | 30 +++++++++++++++++ 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index 689a9dda4..114f3a0cf 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -70,24 +70,27 @@ @endsection diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index cf71bd691..b67505c3b 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -69,6 +69,18 @@
+ + + + + + + + + + + + @@ -777,6 +789,24 @@ $(document).ready(function () { element.parent().removeClass('has-error has-success'); } + (function getInformation() { + $.ajax({ + method: 'GET', + url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}', + timeout: 5000, + headers: { + 'X-Access-Token': '{{ $node->daemonSecret }}' + }, + }).done(function (data) { + $('[data-attr="info-version"]').html(data.version); + $('[data-attr="info-system"]').html(data.system.type + '(' + data.system.arch + ') ' + data.system.release + ''); + $('[data-attr="info-cpus"]').html(data.system.cpus); + }).fail(function (jqXHR) { + + }).always(function() { + setTimeout(getInformation, 10000); + }); + })(); }); @endsection From 261535d83dc6dbaf28f0fa509453d87c844bc709 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 18:52:19 -0500 Subject: [PATCH 06/14] Fix broken block ending for script --- resources/views/admin/nodes/index.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index 114f3a0cf..ea3752433 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -91,6 +91,6 @@ $(document).ready(function () { }); }); })(); -} +}); @endsection From 90cd2b677e696901934d9a44c7a5ab107ffd1b5f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 26 Nov 2016 19:29:57 -0500 Subject: [PATCH 07/14] Add version checking to daemon and panel Also includes some buttons for users to get help from the panel. --- app/Console/Commands/ShowVersion.php | 3 +- app/Facades/Version.php | 35 ++++++++ app/Services/VersionService.php | 93 ++++++++++++++++++++++ config/app.php | 1 + resources/views/admin/index.blade.php | 32 ++++++-- resources/views/admin/nodes/view.blade.php | 2 +- 6 files changed, 157 insertions(+), 9 deletions(-) create mode 100644 app/Facades/Version.php create mode 100644 app/Services/VersionService.php diff --git a/app/Console/Commands/ShowVersion.php b/app/Console/Commands/ShowVersion.php index 0dcce04a1..2033f9b0f 100644 --- a/app/Console/Commands/ShowVersion.php +++ b/app/Console/Commands/ShowVersion.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Console\Commands; use Illuminate\Console\Command; +use Version; class ShowVersion extends Command { @@ -58,6 +59,6 @@ class ShowVersion extends Command */ public function handle() { - $this->info('You are running Pterodactyl Panel ' . config('app.version')); + $this->info('You are running Pterodactyl Panel v' . Version::getCurrentPanel() . ' (' . ((Version::isLatestPanel()) ? 'Up to Date' : 'Latest: ' . Version::getDaemon()) . ')'); } } diff --git a/app/Facades/Version.php b/app/Facades/Version.php new file mode 100644 index 000000000..840862600 --- /dev/null +++ b/app/Facades/Version.php @@ -0,0 +1,35 @@ + + * + * 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. + */ +namespace Pterodactyl\Facades; + +use Illuminate\Support\Facades\Facade; + +class Version extends Facade +{ + + protected static function getFacadeAccessor() + { + return '\Pterodactyl\Services\VersionService'; + } +} diff --git a/app/Services/VersionService.php b/app/Services/VersionService.php new file mode 100644 index 000000000..5afb97e46 --- /dev/null +++ b/app/Services/VersionService.php @@ -0,0 +1,93 @@ + + * + * 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. + */ +namespace Pterodactyl\Services; + +use Cache; +use GuzzleHttp\Client; + +class VersionService +{ + + protected static $versions; + + /** + * Constructor + */ + public function __construct() + { + self::$versions = Cache::remember('versions', env('VERSION_CACHE_TIME', 60), function () { + $client = new Client(); + + try { + $response = $client->request('GET', env('VERSION_CHECK_URL', 'https://cdn.pterodactyl.io/releases/latest.json')); + + if ($response->getStatusCode() === 200) { + return json_decode($response->getBody()); + } else { + throw new \Exception('Invalid response code.'); + } + } catch (\Exception $ex) { + // Failed request, just return errored version. + return (object) [ + 'panel' => 'error', + 'daemon' => 'error', + ]; + } + }); + } + + public static function getPanel() + { + return self::$versions->panel; + } + + public static function getDaemon() + { + return self::$versions->daemon; + } + + public function getCurrentPanel() + { + return config('app.version'); + } + + public static function isLatestPanel() + { + if (config('app.version') === 'canary') { + return true; + } + + return (version_compare(config('app.version'), self::$versions->panel) >= 0); + } + + public static function isLatestDaemon($daemon) + { + if ($daemon === '0.0.0-canary') { + return true; + } + + return (version_compare($daemon, self::$versions->daemon) >= 0); + } + +} diff --git a/config/app.php b/config/app.php index 619e51039..a3c3ff532 100644 --- a/config/app.php +++ b/config/app.php @@ -217,6 +217,7 @@ return [ 'URL' => Illuminate\Support\Facades\URL::class, 'Uuid' => Webpatser\Uuid\Uuid::class, 'Validator' => Illuminate\Support\Facades\Validator::class, + 'Version' => Pterodactyl\Facades\Version::class, 'View' => Illuminate\Support\Facades\View::class, ], diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index 27e8d52e9..85ffa5708 100644 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -24,13 +24,31 @@ @endsection @section('content') -
- -

Pterodactyl Admin Control Panel


-

Welcome to the most advanced, lightweight, and user-friendly open source game server control panel.

-

You are running version {{ config('app.version') }}.

+
+
+ +

Pterodactyl Admin Control Panel


+ @if (Version::isLatestPanel()) +
You are running Pterodactyl Panel version {{ Version::getCurrentPanel() }}. Your panel is up-to-date!
+ @else +
+ Your panel is not up-to-date! The latest version is {{ Version::getPanel() }} and you are currently running version {{ Version::getCurrentPanel() }}. +
+ @endif +
+
+
Daemon Version
System Information
Total CPU Cores
Total Servers {{ count($servers) }}