From 7d29986e9d3e5701fef0df764d0b6b8106a0ab2e Mon Sep 17 00:00:00 2001 From: DoNotSpamPls <7570108+DoNotSpamPls@users.noreply.github.com> Date: Sat, 3 Mar 2018 20:56:48 +0200 Subject: [PATCH 01/13] Fix some game name typos (#1000) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f6931c048..135f4d4ef 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ Some of our core supported games include: * Teamspeak * Mumble * Team Fortress 2 -* Counter Strike: GO -* Garrys Mod -* Ark: Survival Evolved +* Counter Strike: Global Offensive +* 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: From b53df2b271c8305960cd42eb02cc5c5391a32c9b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 16:56:46 -0600 Subject: [PATCH 02/13] Fix application keys being created as client keys, closes #1016 --- CHANGELOG.md | 2 ++ resources/themes/pterodactyl/admin/api/new.blade.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31c1cef28..5cb50e119 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ 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.5 (Derelict Dermodactylus) + ## v0.7.4-h1 (Derelict Dermodactylus) ### Fixed * Being able to create servers is kind of a core aspect of the software, pushing releases late at night is not a great idea. diff --git a/resources/themes/pterodactyl/admin/api/new.blade.php b/resources/themes/pterodactyl/admin/api/new.blade.php index b5db6a154..b5876ee8c 100644 --- a/resources/themes/pterodactyl/admin/api/new.blade.php +++ b/resources/themes/pterodactyl/admin/api/new.blade.php @@ -15,7 +15,7 @@ @section('content')
-
+
From e8cb441fc8c7b3a904195312724f8f9573180d7b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 17:14:36 -0600 Subject: [PATCH 03/13] Update Readme --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cb50e119..dd53c2a83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ 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.5 (Derelict Dermodactylus) +### Fixed +* Fixes application API keys being created as a client API key. ## v0.7.4-h1 (Derelict Dermodactylus) ### Fixed From c739f292e4b783bf25275eee93a00fbc585dc895 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 17:52:35 -0600 Subject: [PATCH 04/13] paginate databases when viewing a host --- CHANGELOG.md | 3 +++ .../DatabaseHostRepositoryInterface.php | 12 ----------- .../DatabaseRepositoryInterface.php | 17 +++++++++------- .../Controllers/Admin/DatabaseController.php | 19 ++++++++++-------- .../Eloquent/DatabaseHostRepository.php | 20 ------------------- .../Eloquent/DatabaseRepository.php | 15 ++++++++++++++ .../admin/databases/view.blade.php | 11 +++++++--- 7 files changed, 47 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd53c2a83..313ef0b61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * Fixes application API keys being created as a client API key. +### Changed +* Databases are now properly paginated when viewing a database host. + ## v0.7.4-h1 (Derelict Dermodactylus) ### Fixed * Being able to create servers is kind of a core aspect of the software, pushing releases late at night is not a great idea. diff --git a/app/Contracts/Repository/DatabaseHostRepositoryInterface.php b/app/Contracts/Repository/DatabaseHostRepositoryInterface.php index dfd29e9ab..a924d85a9 100644 --- a/app/Contracts/Repository/DatabaseHostRepositoryInterface.php +++ b/app/Contracts/Repository/DatabaseHostRepositoryInterface.php @@ -3,7 +3,6 @@ namespace Pterodactyl\Contracts\Repository; use Illuminate\Support\Collection; -use Pterodactyl\Models\DatabaseHost; interface DatabaseHostRepositoryInterface extends RepositoryInterface { @@ -14,15 +13,4 @@ interface DatabaseHostRepositoryInterface extends RepositoryInterface * @return \Illuminate\Support\Collection */ public function getWithViewDetails(): Collection; - - /** - * Return a database host with the databases and associated servers - * that are attached to said databases. - * - * @param int $id - * @return \Pterodactyl\Models\DatabaseHost - * - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function getWithServers(int $id): DatabaseHost; } diff --git a/app/Contracts/Repository/DatabaseRepositoryInterface.php b/app/Contracts/Repository/DatabaseRepositoryInterface.php index 7fc3bf045..f5d531513 100644 --- a/app/Contracts/Repository/DatabaseRepositoryInterface.php +++ b/app/Contracts/Repository/DatabaseRepositoryInterface.php @@ -1,16 +1,10 @@ . - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ namespace Pterodactyl\Contracts\Repository; use Pterodactyl\Models\Database; use Illuminate\Support\Collection; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; interface DatabaseRepositoryInterface extends RepositoryInterface { @@ -39,6 +33,15 @@ interface DatabaseRepositoryInterface extends RepositoryInterface */ public function getDatabasesForServer(int $server): Collection; + /** + * Return all of the databases for a given host with the server relationship loaded. + * + * @param int $host + * @param int $count + * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + */ + public function getDatabasesForHost(int $host, int $count = 25): LengthAwarePaginator; + /** * Create a new database if it does not already exist on the host with * the provided details. diff --git a/app/Http/Controllers/Admin/DatabaseController.php b/app/Http/Controllers/Admin/DatabaseController.php index d03f7050e..affb0c80e 100644 --- a/app/Http/Controllers/Admin/DatabaseController.php +++ b/app/Http/Controllers/Admin/DatabaseController.php @@ -1,11 +1,4 @@ . - * - * This software is licensed under the terms of the MIT license. - * https://opensource.org/licenses/MIT - */ namespace Pterodactyl\Http\Controllers\Admin; @@ -19,6 +12,7 @@ use Pterodactyl\Services\Databases\Hosts\HostUpdateService; use Pterodactyl\Http\Requests\Admin\DatabaseHostFormRequest; use Pterodactyl\Services\Databases\Hosts\HostCreationService; use Pterodactyl\Services\Databases\Hosts\HostDeletionService; +use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface; @@ -34,6 +28,11 @@ class DatabaseController extends Controller */ private $creationService; + /** + * @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface + */ + private $databaseRepository; + /** * @var \Pterodactyl\Services\Databases\Hosts\HostDeletionService */ @@ -59,6 +58,7 @@ class DatabaseController extends Controller * * @param \Prologue\Alerts\AlertsMessageBag $alert * @param \Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface $repository + * @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $databaseRepository * @param \Pterodactyl\Services\Databases\Hosts\HostCreationService $creationService * @param \Pterodactyl\Services\Databases\Hosts\HostDeletionService $deletionService * @param \Pterodactyl\Services\Databases\Hosts\HostUpdateService $updateService @@ -67,6 +67,7 @@ class DatabaseController extends Controller public function __construct( AlertsMessageBag $alert, DatabaseHostRepositoryInterface $repository, + DatabaseRepositoryInterface $databaseRepository, HostCreationService $creationService, HostDeletionService $deletionService, HostUpdateService $updateService, @@ -74,6 +75,7 @@ class DatabaseController extends Controller ) { $this->alert = $alert; $this->creationService = $creationService; + $this->databaseRepository = $databaseRepository; $this->deletionService = $deletionService; $this->repository = $repository; $this->locationRepository = $locationRepository; @@ -105,7 +107,8 @@ class DatabaseController extends Controller { return view('admin.databases.view', [ 'locations' => $this->locationRepository->getAllWithNodes(), - 'host' => $this->repository->getWithServers($host), + 'host' => $this->repository->find($host), + 'databases' => $this->databaseRepository->getDatabasesForHost($host), ]); } diff --git a/app/Repositories/Eloquent/DatabaseHostRepository.php b/app/Repositories/Eloquent/DatabaseHostRepository.php index 6bfb94d70..4ed4d411e 100644 --- a/app/Repositories/Eloquent/DatabaseHostRepository.php +++ b/app/Repositories/Eloquent/DatabaseHostRepository.php @@ -4,8 +4,6 @@ namespace Pterodactyl\Repositories\Eloquent; use Illuminate\Support\Collection; use Pterodactyl\Models\DatabaseHost; -use Illuminate\Database\Eloquent\ModelNotFoundException; -use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface; class DatabaseHostRepository extends EloquentRepository implements DatabaseHostRepositoryInterface @@ -30,22 +28,4 @@ class DatabaseHostRepository extends EloquentRepository implements DatabaseHostR { return $this->getBuilder()->withCount('databases')->with('node')->get(); } - - /** - * Return a database host with the databases and associated servers - * that are attached to said databases. - * - * @param int $id - * @return \Pterodactyl\Models\DatabaseHost - * - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException - */ - public function getWithServers(int $id): DatabaseHost - { - try { - return $this->getBuilder()->with('databases.server')->findOrFail($id, $this->getColumns()); - } catch (ModelNotFoundException $exception) { - throw new RecordNotFoundException; - } - } } diff --git a/app/Repositories/Eloquent/DatabaseRepository.php b/app/Repositories/Eloquent/DatabaseRepository.php index d24dd177e..8a8c93fd8 100644 --- a/app/Repositories/Eloquent/DatabaseRepository.php +++ b/app/Repositories/Eloquent/DatabaseRepository.php @@ -6,6 +6,7 @@ use Pterodactyl\Models\Database; use Illuminate\Support\Collection; use Illuminate\Foundation\Application; use Illuminate\Database\DatabaseManager; +use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; use Pterodactyl\Exceptions\Repository\DuplicateDatabaseNameException; @@ -78,6 +79,20 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor return $this->getBuilder()->where('server_id', $server)->get($this->getColumns()); } + /** + * Return all of the databases for a given host with the server relationship loaded. + * + * @param int $host + * @param int $count + * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator + */ + public function getDatabasesForHost(int $host, int $count = 25): LengthAwarePaginator + { + return $this->getBuilder()->with('server') + ->where('database_host_id', $host) + ->paginate($count, $this->getColumns()); + } + /** * Create a new database if it does not already exist on the host with * the provided details. diff --git a/resources/themes/pterodactyl/admin/databases/view.blade.php b/resources/themes/pterodactyl/admin/databases/view.blade.php index 41a2d7901..655b833fc 100644 --- a/resources/themes/pterodactyl/admin/databases/view.blade.php +++ b/resources/themes/pterodactyl/admin/databases/view.blade.php @@ -101,14 +101,14 @@ Connections From - @foreach($host->databases as $database) + @foreach($databases as $database) - {{ $database->server->name }} + {{ $database->getRelation('server')->name }} {{ $database->database }} {{ $database->username }} {{ $database->remote }} - + @@ -116,6 +116,11 @@ @endforeach
+ @if($databases->hasPages()) + + @endif
From eaf54a8c63549adddcb72b8f05bb0bd7acdc8b36 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 17:57:12 -0600 Subject: [PATCH 05/13] Search term is now passed through when using paginated result sets --- CHANGELOG.md | 1 + resources/themes/pterodactyl/admin/nodes/index.blade.php | 2 +- resources/themes/pterodactyl/admin/packs/index.blade.php | 2 +- resources/themes/pterodactyl/admin/servers/index.blade.php | 2 +- resources/themes/pterodactyl/admin/users/index.blade.php | 2 +- resources/themes/pterodactyl/base/index.blade.php | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 313ef0b61..a8d3df98e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ## v0.7.5 (Derelict Dermodactylus) ### Fixed * Fixes application API keys being created as a client API key. +* Search term is now passed through when using paginated result sets. ### Changed * Databases are now properly paginated when viewing a database host. diff --git a/resources/themes/pterodactyl/admin/nodes/index.blade.php b/resources/themes/pterodactyl/admin/nodes/index.blade.php index a96d32240..b4f936fb6 100644 --- a/resources/themes/pterodactyl/admin/nodes/index.blade.php +++ b/resources/themes/pterodactyl/admin/nodes/index.blade.php @@ -70,7 +70,7 @@ @if($nodes->hasPages()) @endif diff --git a/resources/themes/pterodactyl/admin/packs/index.blade.php b/resources/themes/pterodactyl/admin/packs/index.blade.php index 270bea96b..dd74f17ed 100644 --- a/resources/themes/pterodactyl/admin/packs/index.blade.php +++ b/resources/themes/pterodactyl/admin/packs/index.blade.php @@ -61,7 +61,7 @@ @if ($packs->hasPages()) @endif diff --git a/resources/themes/pterodactyl/admin/servers/index.blade.php b/resources/themes/pterodactyl/admin/servers/index.blade.php index 24fe4d81f..117a4de70 100644 --- a/resources/themes/pterodactyl/admin/servers/index.blade.php +++ b/resources/themes/pterodactyl/admin/servers/index.blade.php @@ -76,7 +76,7 @@ @if($servers->hasPages()) @endif diff --git a/resources/themes/pterodactyl/admin/users/index.blade.php b/resources/themes/pterodactyl/admin/users/index.blade.php index dd95f222b..2de490d53 100644 --- a/resources/themes/pterodactyl/admin/users/index.blade.php +++ b/resources/themes/pterodactyl/admin/users/index.blade.php @@ -75,7 +75,7 @@ @if($users->hasPages()) @endif diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index 3b5cd62f7..cb5a9f616 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -79,7 +79,7 @@ @if($servers->hasPages()) @endif From a31334c0c50deb96a9aef849749b1d3a6626fdbc Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 18:00:23 -0600 Subject: [PATCH 06/13] Fix SQl queries being executed unnecessarily when listing servers --- CHANGELOG.md | 1 + app/Repositories/Eloquent/ServerRepository.php | 2 +- resources/themes/pterodactyl/base/index.blade.php | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8d3df98e..c5088b525 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Fixed * Fixes application API keys being created as a client API key. * Search term is now passed through when using paginated result sets. +* Reduces the number of SQL queries executed when rendering the server listing to increase performance. ### Changed * Databases are now properly paginated when viewing a database host. diff --git a/app/Repositories/Eloquent/ServerRepository.php b/app/Repositories/Eloquent/ServerRepository.php index 5a53d33f0..ec244dd0b 100644 --- a/app/Repositories/Eloquent/ServerRepository.php +++ b/app/Repositories/Eloquent/ServerRepository.php @@ -216,7 +216,7 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt */ public function filterUserAccessServers(User $user, int $level, bool $paginate = true) { - $instance = $this->getBuilder()->select($this->getColumns())->with(['user']); + $instance = $this->getBuilder()->select($this->getColumns())->with(['user', 'node', 'allocation']); // If access level is set to owner, only display servers // that the user owns. diff --git a/resources/themes/pterodactyl/base/index.blade.php b/resources/themes/pterodactyl/base/index.blade.php index cb5a9f616..95cce6128 100644 --- a/resources/themes/pterodactyl/base/index.blade.php +++ b/resources/themes/pterodactyl/base/index.blade.php @@ -51,8 +51,8 @@ description)) rowspan="2" @endif>{{ $server->uuidShort }} {{ $server->name }} - {{ $server->node->name }} - {{ $server->allocation->alias }}:{{ $server->allocation->port }} + {{ $server->getRelation('node')->name }} + {{ $server->getRelation('allocation')->alias }}:{{ $server->getRelation('allocation')->port }} -- / {{ $server->memory === 0 ? '∞' : $server->memory }} MB -- % From 6d217869e040fc8b1b367ce47ef81aa38f9f7691 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 18:09:49 -0600 Subject: [PATCH 07/13] Don't load daemon key on server models automatically. --- CHANGELOG.md | 1 + app/Models/Server.php | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5088b525..cbed7fc5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. ### Changed * Databases are now properly paginated when viewing a database host. +* No more loading daemon keys for every server model being loaded, some of us value our databases. ## v0.7.4-h1 (Derelict Dermodactylus) ### Fixed diff --git a/app/Models/Server.php b/app/Models/Server.php index d5c6b3a8d..5d42cf86b 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -35,13 +35,6 @@ class Server extends Model implements CleansAttributes, ValidableContract */ protected $dates = [self::CREATED_AT, self::UPDATED_AT, 'deleted_at']; - /** - * Always eager load these relationships on the model. - * - * @var array - */ - protected $with = ['key']; - /** * Fields that are not mass assignable. * From 18e394eb14016056345413021002e14c1b41b929 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 18:24:40 -0600 Subject: [PATCH 08/13] Fix tests --- .../Admin/DatabaseControllerTest.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/Unit/Http/Controllers/Admin/DatabaseControllerTest.php b/tests/Unit/Http/Controllers/Admin/DatabaseControllerTest.php index 108198bde..c3735b927 100644 --- a/tests/Unit/Http/Controllers/Admin/DatabaseControllerTest.php +++ b/tests/Unit/Http/Controllers/Admin/DatabaseControllerTest.php @@ -13,11 +13,13 @@ use Mockery as m; use Tests\TestCase; use Pterodactyl\Models\DatabaseHost; use Prologue\Alerts\AlertsMessageBag; +use Illuminate\Pagination\LengthAwarePaginator; use Tests\Assertions\ControllerAssertionsTrait; use Pterodactyl\Http\Controllers\Admin\DatabaseController; use Pterodactyl\Services\Databases\Hosts\HostUpdateService; use Pterodactyl\Services\Databases\Hosts\HostCreationService; use Pterodactyl\Services\Databases\Hosts\HostDeletionService; +use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface; use Pterodactyl\Contracts\Repository\LocationRepositoryInterface; use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface; @@ -35,6 +37,11 @@ class DatabaseControllerTest extends TestCase */ private $creationService; + /** + * @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface|\Mockery\Mock + */ + private $databaseRepository; + /** * @var \Pterodactyl\Services\Databases\Hosts\HostDeletionService|\Mockery\Mock */ @@ -64,6 +71,7 @@ class DatabaseControllerTest extends TestCase $this->alert = m::mock(AlertsMessageBag::class); $this->creationService = m::mock(HostCreationService::class); + $this->databaseRepository = m::mock(DatabaseRepositoryInterface::class); $this->deletionService = m::mock(HostDeletionService::class); $this->locationRepository = m::mock(LocationRepositoryInterface::class); $this->repository = m::mock(DatabaseHostRepositoryInterface::class); @@ -94,9 +102,14 @@ class DatabaseControllerTest extends TestCase public function testViewController() { $model = factory(DatabaseHost::class)->make(); + $paginator = new LengthAwarePaginator([], 1, 1); $this->locationRepository->shouldReceive('getAllWithNodes')->withNoArgs()->once()->andReturn(collect(['getAllWithNodes'])); - $this->repository->shouldReceive('getWithServers')->with(1)->once()->andReturn($model); + $this->repository->shouldReceive('find')->with(1)->once()->andReturn($model); + $this->databaseRepository->shouldReceive('getDatabasesForHost') + ->once() + ->with(1) + ->andReturn($paginator); $response = $this->getController()->view(1); @@ -104,8 +117,10 @@ class DatabaseControllerTest extends TestCase $this->assertViewNameEquals('admin.databases.view', $response); $this->assertViewHasKey('locations', $response); $this->assertViewHasKey('host', $response); + $this->assertViewHasKey('databases', $response); $this->assertViewKeyEquals('locations', collect(['getAllWithNodes']), $response); $this->assertViewKeyEquals('host', $model, $response); + $this->assertViewKeyEquals('databases', $paginator, $response); } /** @@ -118,6 +133,7 @@ class DatabaseControllerTest extends TestCase return new DatabaseController( $this->alert, $this->repository, + $this->databaseRepository, $this->creationService, $this->deletionService, $this->updateService, From a4f03f5d022851da51a55e736af474a088ced850 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 21:31:44 -0600 Subject: [PATCH 09/13] Handle missing daemon keys better and fix subuser missing key errors --- CHANGELOG.md | 2 + .../Server/AuthenticateAsSubuser.php | 11 +---- .../DaemonKeys/DaemonKeyProviderService.php | 27 +++++++++-- app/Transformers/Daemon/ApiKeyTransformer.php | 26 +--------- .../Server/AuthenticateAsSubuserTest.php | 10 +--- .../DaemonKeyProviderServiceTest.php | 47 ++++++++++++++++++- 6 files changed, 74 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbed7fc5c..7ee5c4c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,12 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Fixes application API keys being created as a client API key. * Search term is now passed through when using paginated result sets. * Reduces the number of SQL queries executed when rendering the server listing to increase performance. +* Fixes exceptions being thrown for non-existent subuser permissions. ### Changed * Databases are now properly paginated when viewing a database host. * No more loading daemon keys for every server model being loaded, some of us value our databases. +* Changed behavior of the subuser middleware to add a daemon access key if one is missing from the database for some reason. ## v0.7.4-h1 (Derelict Dermodactylus) ### Fixed diff --git a/app/Http/Middleware/Server/AuthenticateAsSubuser.php b/app/Http/Middleware/Server/AuthenticateAsSubuser.php index 8f8a158ca..1a185bb6e 100644 --- a/app/Http/Middleware/Server/AuthenticateAsSubuser.php +++ b/app/Http/Middleware/Server/AuthenticateAsSubuser.php @@ -11,7 +11,6 @@ namespace Pterodactyl\Http\Middleware\Server; use Closure; use Illuminate\Http\Request; -use Illuminate\Contracts\Session\Session; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; @@ -23,21 +22,14 @@ class AuthenticateAsSubuser */ private $keyProviderService; - /** - * @var \Illuminate\Contracts\Session\Session - */ - private $session; - /** * SubuserAccessAuthenticate constructor. * * @param \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService $keyProviderService - * @param \Illuminate\Contracts\Session\Session $session */ - public function __construct(DaemonKeyProviderService $keyProviderService, Session $session) + public function __construct(DaemonKeyProviderService $keyProviderService) { $this->keyProviderService = $keyProviderService; - $this->session = $session; } /** @@ -60,7 +52,6 @@ class AuthenticateAsSubuser throw new AccessDeniedHttpException('This account does not have permission to access this server.'); } - $this->session->now('server_data.token', $token); $request->attributes->set('server_token', $token); return $next($request); diff --git a/app/Services/DaemonKeys/DaemonKeyProviderService.php b/app/Services/DaemonKeys/DaemonKeyProviderService.php index ab19329fa..a386d286e 100644 --- a/app/Services/DaemonKeys/DaemonKeyProviderService.php +++ b/app/Services/DaemonKeys/DaemonKeyProviderService.php @@ -28,6 +28,7 @@ use Carbon\Carbon; use Pterodactyl\Models\User; use Pterodactyl\Models\Server; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; +use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface; use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface; class DaemonKeyProviderService @@ -47,21 +48,29 @@ class DaemonKeyProviderService */ private $repository; + /** + * @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface + */ + private $subuserRepository; + /** * GetDaemonKeyService constructor. * * @param \Pterodactyl\Services\DaemonKeys\DaemonKeyCreationService $keyCreationService * @param \Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface $repository * @param \Pterodactyl\Services\DaemonKeys\DaemonKeyUpdateService $keyUpdateService + * @param \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface $subuserRepository */ public function __construct( DaemonKeyCreationService $keyCreationService, DaemonKeyRepositoryInterface $repository, - DaemonKeyUpdateService $keyUpdateService + DaemonKeyUpdateService $keyUpdateService, + SubuserRepositoryInterface $subuserRepository ) { $this->keyCreationService = $keyCreationService; $this->keyUpdateService = $keyUpdateService; $this->repository = $repository; + $this->subuserRepository = $subuserRepository; } /** @@ -89,10 +98,18 @@ class DaemonKeyProviderService return $this->keyCreationService->handle($server->id, $user->id); } - // If they aren't the admin or owner of the server, they shouldn't get access. - // Subusers should always have an entry created when they are, so if there is - // no record, it should fail. - throw $exception; + // Check if user is a subuser for this server. Ideally they should always have + // a record associated with them in the database, but we should still handle + // that potentiality here. + // + // If no subuser is found, a RecordNotFoundException will be thrown, thus handling + // the parent error as well. + $subuser = $this->subuserRepository->findFirstWhere([ + ['user_id', '=', $user->id], + ['server_id', '=', $server->id], + ]); + + return $this->keyCreationService->handle($subuser->server_id, $subuser->user_id); } if (! $updateIfExpired || Carbon::now()->diffInSeconds($key->expires_at, false) > 0) { diff --git a/app/Transformers/Daemon/ApiKeyTransformer.php b/app/Transformers/Daemon/ApiKeyTransformer.php index 54aa37d6f..7f1d7427b 100644 --- a/app/Transformers/Daemon/ApiKeyTransformer.php +++ b/app/Transformers/Daemon/ApiKeyTransformer.php @@ -1,26 +1,4 @@ . - * - * 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\Transformers\Daemon; @@ -83,8 +61,8 @@ class ApiKeyTransformer extends TransformerAbstract $daemonPermissions = ['s:console']; foreach ($permissions as $permission) { - if (! is_null($mappings[$permission])) { - $daemonPermissions[] = $mappings[$permission]; + if (! is_null(array_get($mappings, $permission))) { + $daemonPermissions[] = array_get($mappings, $permission); } } diff --git a/tests/Unit/Http/Middleware/Server/AuthenticateAsSubuserTest.php b/tests/Unit/Http/Middleware/Server/AuthenticateAsSubuserTest.php index 8ee1a0e4c..04965facc 100644 --- a/tests/Unit/Http/Middleware/Server/AuthenticateAsSubuserTest.php +++ b/tests/Unit/Http/Middleware/Server/AuthenticateAsSubuserTest.php @@ -4,7 +4,6 @@ namespace Tests\Unit\Http\Middleware\Server; use Mockery as m; use Pterodactyl\Models\Server; -use Illuminate\Contracts\Session\Session; use Tests\Unit\Http\Middleware\MiddlewareTestCase; use Pterodactyl\Http\Middleware\Server\AuthenticateAsSubuser; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; @@ -17,11 +16,6 @@ class AuthenticateAsSubuserTest extends MiddlewareTestCase */ private $keyProviderService; - /** - * @var \Illuminate\Contracts\Session\Session|\Mockery\Mock - */ - private $session; - /** * Setup tests. */ @@ -30,7 +24,6 @@ class AuthenticateAsSubuserTest extends MiddlewareTestCase parent::setUp(); $this->keyProviderService = m::mock(DaemonKeyProviderService::class); - $this->session = m::mock(Session::class); } /** @@ -43,7 +36,6 @@ class AuthenticateAsSubuserTest extends MiddlewareTestCase $this->setRequestAttribute('server', $model); $this->keyProviderService->shouldReceive('handle')->with($model, $user)->once()->andReturn('abc123'); - $this->session->shouldReceive('now')->with('server_data.token', 'abc123')->once()->andReturnNull(); $this->getMiddleware()->handle($this->request, $this->getClosureAssertions()); $this->assertRequestHasAttribute('server_token'); @@ -74,6 +66,6 @@ class AuthenticateAsSubuserTest extends MiddlewareTestCase */ public function getMiddleware(): AuthenticateAsSubuser { - return new AuthenticateAsSubuser($this->keyProviderService, $this->session); + return new AuthenticateAsSubuser($this->keyProviderService); } } diff --git a/tests/Unit/Services/DaemonKeys/DaemonKeyProviderServiceTest.php b/tests/Unit/Services/DaemonKeys/DaemonKeyProviderServiceTest.php index 87d5f506b..81d1b3a09 100644 --- a/tests/Unit/Services/DaemonKeys/DaemonKeyProviderServiceTest.php +++ b/tests/Unit/Services/DaemonKeys/DaemonKeyProviderServiceTest.php @@ -14,11 +14,13 @@ use Carbon\Carbon; use Tests\TestCase; use Pterodactyl\Models\User; use Pterodactyl\Models\Server; +use Pterodactyl\Models\Subuser; use Pterodactyl\Models\DaemonKey; use Pterodactyl\Services\DaemonKeys\DaemonKeyUpdateService; use Pterodactyl\Services\DaemonKeys\DaemonKeyCreationService; use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; use Pterodactyl\Exceptions\Repository\RecordNotFoundException; +use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface; use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface; class DaemonKeyProviderServiceTest extends TestCase @@ -38,6 +40,11 @@ class DaemonKeyProviderServiceTest extends TestCase */ private $repository; + /** + * @var \Pterodactyl\Contracts\Repository\SubuserRepositoryInterface|\Mockery\Mock + */ + private $subuserRepository; + /** * Setup tests. */ @@ -49,6 +56,7 @@ class DaemonKeyProviderServiceTest extends TestCase $this->keyCreationService = m::mock(DaemonKeyCreationService::class); $this->keyUpdateService = m::mock(DaemonKeyUpdateService::class); $this->repository = m::mock(DaemonKeyRepositoryInterface::class); + $this->subuserRepository = m::mock(SubuserRepositoryInterface::class); } /** @@ -154,6 +162,33 @@ class DaemonKeyProviderServiceTest extends TestCase $this->assertEquals($key->secret, $response); } + /** + * Test that a missing key is created for a subuser. + */ + public function testMissingKeyIsCreatedForSubuser() + { + $user = factory(User::class)->make(['root_admin' => 0]); + $server = factory(Server::class)->make(); + $key = factory(DaemonKey::class)->make(['expires_at' => Carbon::now()->subHour()]); + $subuser = factory(Subuser::class)->make(['user_id' => $user->id, 'server_id' => $server->id]); + + $this->repository->shouldReceive('findFirstWhere')->with([ + ['user_id', '=', $user->id], + ['server_id', '=', $server->id], + ])->once()->andThrow(new RecordNotFoundException); + + $this->subuserRepository->shouldReceive('findFirstWhere')->once()->with([ + ['user_id', '=', $user->id], + ['server_id', '=', $server->id], + ])->andReturn($subuser); + + $this->keyCreationService->shouldReceive('handle')->with($server->id, $user->id)->once()->andReturn($key->secret); + + $response = $this->getService()->handle($server, $user, false); + $this->assertNotEmpty($response); + $this->assertEquals($key->secret, $response); + } + /** * Test that an exception is thrown if the user should not get a key. * @@ -169,6 +204,11 @@ class DaemonKeyProviderServiceTest extends TestCase ['server_id', '=', $server->id], ])->once()->andThrow(new RecordNotFoundException); + $this->subuserRepository->shouldReceive('findFirstWhere')->once()->with([ + ['user_id', '=', $user->id], + ['server_id', '=', $server->id], + ])->andThrow(new RecordNotFoundException); + $this->getService()->handle($server, $user, false); } @@ -179,6 +219,11 @@ class DaemonKeyProviderServiceTest extends TestCase */ private function getService(): DaemonKeyProviderService { - return new DaemonKeyProviderService($this->keyCreationService, $this->repository, $this->keyUpdateService); + return new DaemonKeyProviderService( + $this->keyCreationService, + $this->repository, + $this->keyUpdateService, + $this->subuserRepository + ); } } From d7efb4c4a2ca16c800276c942ca414a6da8f491d Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 21:45:10 -0600 Subject: [PATCH 10/13] Fix inability to revoke admin tokens from daemon --- CHANGELOG.md | 1 + app/Repositories/Daemon/ServerRepository.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ee5c4c31..bc9321981 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Search term is now passed through when using paginated result sets. * Reduces the number of SQL queries executed when rendering the server listing to increase performance. * Fixes exceptions being thrown for non-existent subuser permissions. +* Fixes exception caused when trying to revoke admin privileges from a user account due to a bad endpoint. ### Changed * Databases are now properly paginated when viewing a database host. diff --git a/app/Repositories/Daemon/ServerRepository.php b/app/Repositories/Daemon/ServerRepository.php index 3af381d1c..bdc7fc99c 100644 --- a/app/Repositories/Daemon/ServerRepository.php +++ b/app/Repositories/Daemon/ServerRepository.php @@ -115,7 +115,7 @@ class ServerRepository extends BaseRepository implements ServerRepositoryInterfa public function revokeAccessKey($key): ResponseInterface { if (is_array($key)) { - return $this->getHttpClient()->request('POST', 'keys', [ + return $this->getHttpClient()->request('POST', 'keys/batch-delete', [ 'json' => $key, ]); } From 85e75a280862937e2db360dd442e2590aa341da2 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 21:53:07 -0600 Subject: [PATCH 11/13] Fix bulk key revocation --- app/Repositories/Daemon/ServerRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Repositories/Daemon/ServerRepository.php b/app/Repositories/Daemon/ServerRepository.php index bdc7fc99c..cf5a5a69a 100644 --- a/app/Repositories/Daemon/ServerRepository.php +++ b/app/Repositories/Daemon/ServerRepository.php @@ -116,7 +116,7 @@ class ServerRepository extends BaseRepository implements ServerRepositoryInterfa { if (is_array($key)) { return $this->getHttpClient()->request('POST', 'keys/batch-delete', [ - 'json' => $key, + 'json' => ['keys' => $key], ]); } From 36837df0a6c3402c9194fa6b8b20a3d48a196347 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 22:20:53 -0600 Subject: [PATCH 12/13] Use beginning of UUID for server uuidShort --- CHANGELOG.md | 1 + .../Repository/ServerRepositoryInterface.php | 9 ++++++++ .../Eloquent/ServerRepository.php | 12 ++++++++++ .../Servers/ServerCreationService.php | 22 ++++++++++++++++-- .../Servers/ServerCreationServiceTest.php | 23 +++++++++++++++++-- 5 files changed, 63 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc9321981..6d9126443 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Databases are now properly paginated when viewing a database host. * No more loading daemon keys for every server model being loaded, some of us value our databases. * Changed behavior of the subuser middleware to add a daemon access key if one is missing from the database for some reason. +* Server short-codes are now based on the UUID as they were in previous versions of Pterodactyl. ## v0.7.4-h1 (Derelict Dermodactylus) ### Fixed diff --git a/app/Contracts/Repository/ServerRepositoryInterface.php b/app/Contracts/Repository/ServerRepositoryInterface.php index 983cf7e6e..dc677fba0 100644 --- a/app/Contracts/Repository/ServerRepositoryInterface.php +++ b/app/Contracts/Repository/ServerRepositoryInterface.php @@ -136,4 +136,13 @@ interface ServerRepositoryInterface extends RepositoryInterface, SearchableInter * @return int */ public function getServersForPowerActionCount(array $servers = [], array $nodes = []): int; + + /** + * Check if a given UUID and UUID-Short string are unique to a server. + * + * @param string $uuid + * @param string $short + * @return bool + */ + public function isUniqueUuidCombo(string $uuid, string $short): bool; } diff --git a/app/Repositories/Eloquent/ServerRepository.php b/app/Repositories/Eloquent/ServerRepository.php index ec244dd0b..2fc5f878b 100644 --- a/app/Repositories/Eloquent/ServerRepository.php +++ b/app/Repositories/Eloquent/ServerRepository.php @@ -303,6 +303,18 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt return $this->getServersForPowerAction($servers, $nodes, true); } + /** + * Check if a given UUID and UUID-Short string are unique to a server. + * + * @param string $uuid + * @param string $short + * @return bool + */ + public function isUniqueUuidCombo(string $uuid, string $short): bool + { + return ! $this->getBuilder()->where('uuid', '=', $uuid)->orWhere('uuidShort', '=', $short)->exists(); + } + /** * Return an array of server IDs that a given user can access based * on owner and subuser permissions. diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index 36144241f..4b4c4ef89 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -210,10 +210,12 @@ class ServerCreationService */ private function createModel(array $data): Server { + $uuid = $this->generateUniqueUuidCombo(); + return $this->repository->create([ 'external_id' => array_get($data, 'external_id'), - 'uuid' => Uuid::uuid4()->toString(), - 'uuidShort' => str_random(8), + 'uuid' => $uuid, + 'uuidShort' => substr($uuid, 0, 8), 'node_id' => array_get($data, 'node_id'), 'name' => array_get($data, 'name'), 'description' => array_get($data, 'description') ?? '', @@ -289,4 +291,20 @@ class ServerCreationService return $allocation->node_id; } + + /** + * Create a unique UUID and UUID-Short combo for a server. + * + * @return string + */ + private function generateUniqueUuidCombo(): string + { + $uuid = Uuid::uuid4()->toString(); + + if (! $this->repository->isUniqueUuidCombo($uuid, substr($uuid, 0, 8))) { + return $this->generateUniqueUuidCombo(); + } + + return $uuid; + } } diff --git a/tests/Unit/Services/Servers/ServerCreationServiceTest.php b/tests/Unit/Services/Servers/ServerCreationServiceTest.php index 309508dbf..92fbec127 100644 --- a/tests/Unit/Services/Servers/ServerCreationServiceTest.php +++ b/tests/Unit/Services/Servers/ServerCreationServiceTest.php @@ -116,8 +116,14 @@ class ServerCreationServiceTest extends TestCase ]); $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); + $this->repository->shouldReceive('isUniqueUuidCombo') + ->once() + ->with($this->getKnownUuid(), substr($this->getKnownUuid(), 0, 8)) + ->andReturn(true); + $this->repository->shouldReceive('create')->with(m::subset([ 'uuid' => $this->getKnownUuid(), + 'uuidShort' => substr($this->getKnownUuid(), 0, 8), 'node_id' => $model->node_id, 'allocation_id' => $model->allocation_id, 'owner_id' => $model->owner_id, @@ -164,8 +170,14 @@ class ServerCreationServiceTest extends TestCase $this->eggRepository->shouldReceive('setColumns->find')->once()->with($model->egg_id)->andReturn($eggModel); $this->validatorService->shouldReceive('setUserLevel->handle')->once()->andReturn(collect([])); - $this->repository->shouldReceive('create')->once()->with(m::subset([ + $this->repository->shouldReceive('isUniqueUuidCombo') + ->once() + ->with($this->getKnownUuid(), substr($this->getKnownUuid(), 0, 8)) + ->andReturn(true); + + $this->repository->shouldReceive('create')->with(m::subset([ 'uuid' => $this->getKnownUuid(), + 'uuidShort' => substr($this->getKnownUuid(), 0, 8), 'node_id' => $model->node_id, 'allocation_id' => $model->allocation_id, 'nest_id' => $model->nest_id, @@ -211,8 +223,14 @@ class ServerCreationServiceTest extends TestCase $this->allocationSelectionService->shouldReceive('handle')->once()->withNoArgs()->andReturn($allocationModel); $this->validatorService->shouldReceive('setUserLevel->handle')->once()->andReturn(collect([])); - $this->repository->shouldReceive('create')->once()->with(m::subset([ + $this->repository->shouldReceive('isUniqueUuidCombo') + ->once() + ->with($this->getKnownUuid(), substr($this->getKnownUuid(), 0, 8)) + ->andReturn(true); + + $this->repository->shouldReceive('create')->with(m::subset([ 'uuid' => $this->getKnownUuid(), + 'uuidShort' => substr($this->getKnownUuid(), 0, 8), 'node_id' => $model->node_id, 'allocation_id' => $model->allocation_id, 'nest_id' => $model->nest_id, @@ -244,6 +262,7 @@ class ServerCreationServiceTest extends TestCase ]); $this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull(); + $this->repository->shouldReceive('isUniqueUuidCombo')->once()->andReturn(true); $this->repository->shouldReceive('create')->once()->andReturn($model); $this->allocationRepository->shouldReceive('assignAllocationsToServer')->once()->andReturn(1); $this->validatorService->shouldReceive('setUserLevel')->once()->andReturnSelf(); From 4e3dd288250dc774d985050c86ea10bc9eb30c5e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 3 Mar 2018 22:24:52 -0600 Subject: [PATCH 13/13] bump for release --- config/app.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/app.php b/config/app.php index c1c94fa61..fe5ed34ca 100644 --- a/config/app.php +++ b/config/app.php @@ -9,7 +9,7 @@ return [ | change this value if you are not maintaining your own internal versions. */ - 'version' => 'canary', + 'version' => '0.7.5', /* |--------------------------------------------------------------------------