From 4532811fcd2cf392996bb8b3eaa140d0eea2db1e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 2 Sep 2017 21:35:33 -0500 Subject: [PATCH] Improved middleware, console page now using new setup --- .../RequiredVariableMissingException.php | 4 +- .../Server/UserNotLinkedToServerException.php | 31 +++++ .../Controllers/Server/ConsoleController.php | 99 ++++++++++++++ .../Controllers/Server/ServerController.php | 55 -------- app/Http/Kernel.php | 3 +- ...CheckServer.php => ServerAuthenticate.php} | 124 +++++++++--------- .../Middleware/SubuserAccessAuthenticate.php | 81 ++++++++++++ app/Providers/RouteServiceProvider.php | 2 +- .../Servers/ServerAccessHelperService.php | 43 +++--- app/Traits/Controllers/ServerToJavascript.php | 64 +++++++++ .../pterodactyl/layouts/master.blade.php | 49 +++---- routes/server.php | 4 +- .../Server/ConsoleControllerTest.php | 105 +++++++++++++++ 13 files changed, 499 insertions(+), 165 deletions(-) create mode 100644 app/Exceptions/Service/Server/UserNotLinkedToServerException.php create mode 100644 app/Http/Controllers/Server/ConsoleController.php rename app/Http/Middleware/{CheckServer.php => ServerAuthenticate.php} (56%) create mode 100644 app/Http/Middleware/SubuserAccessAuthenticate.php create mode 100644 app/Traits/Controllers/ServerToJavascript.php create mode 100644 tests/Unit/Http/Controllers/Server/ConsoleControllerTest.php diff --git a/app/Exceptions/Service/Server/RequiredVariableMissingException.php b/app/Exceptions/Service/Server/RequiredVariableMissingException.php index f026ccce5..ea22dd08b 100644 --- a/app/Exceptions/Service/Server/RequiredVariableMissingException.php +++ b/app/Exceptions/Service/Server/RequiredVariableMissingException.php @@ -24,8 +24,8 @@ namespace Pterodactyl\Exceptions\Service\Server; -use Exception; +use Pterodactyl\Exceptions\PterodactylException; -class RequiredVariableMissingException extends Exception +class RequiredVariableMissingException extends PterodactylException { } diff --git a/app/Exceptions/Service/Server/UserNotLinkedToServerException.php b/app/Exceptions/Service/Server/UserNotLinkedToServerException.php new file mode 100644 index 000000000..346b41fe7 --- /dev/null +++ b/app/Exceptions/Service/Server/UserNotLinkedToServerException.php @@ -0,0 +1,31 @@ +. + * + * 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\Exceptions\Service\Server; + +use Pterodactyl\Exceptions\PterodactylException; + +class UserNotLinkedToServerException extends PterodactylException +{ +} diff --git a/app/Http/Controllers/Server/ConsoleController.php b/app/Http/Controllers/Server/ConsoleController.php new file mode 100644 index 000000000..8f43b1a2c --- /dev/null +++ b/app/Http/Controllers/Server/ConsoleController.php @@ -0,0 +1,99 @@ +. + * + * 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\Http\Controllers\Server; + +use Illuminate\Contracts\Session\Session; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Traits\Controllers\ServerToJavascript; +use Illuminate\Contracts\Config\Repository as ConfigRepository; + +class ConsoleController extends Controller +{ + use ServerToJavascript; + + /** + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * @var \Illuminate\Contracts\Session\Session + */ + protected $session; + + /** + * ConsoleController constructor. + * + * @param \Illuminate\Contracts\Config\Repository $config + * @param \Illuminate\Contracts\Session\Session $session + */ + public function __construct( + ConfigRepository $config, + Session $session + ) { + $this->config = $config; + $this->session = $session; + } + + /** + * Render server index page with the console and power options. + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function index() + { + $server = $this->session->get('server_data.model'); + + $this->injectJavascript([ + 'meta' => [ + 'saveFile' => route('server.files.save', $server->uuidShort), + 'csrfToken' => csrf_token(), + ], + 'config' => [ + 'console_count' => $this->config->get('pterodactyl.console.count'), + 'console_freq' => $this->config->get('pterodactyl.console.frequency'), + ], + ]); + + return view('server.index', ['server' => $server, 'node' => $server->node]); + } + + /** + * Render a stand-alone console in the browser. + * + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function console() + { + $server = $this->session->get('server_data.model'); + + $this->injectJavascript(['config' => [ + 'console_count' => $this->config->get('pterodactyl.console.count'), + 'console_freq' => $this->config->get('pterodactyl.console.frequency'), + ]]); + + return view('server.console', ['server' => $server, 'node' => $server->node]); + } +} diff --git a/app/Http/Controllers/Server/ServerController.php b/app/Http/Controllers/Server/ServerController.php index 86382186d..c677c1cd6 100644 --- a/app/Http/Controllers/Server/ServerController.php +++ b/app/Http/Controllers/Server/ServerController.php @@ -31,65 +31,10 @@ use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Repositories\ServerRepository; use Pterodactyl\Exceptions\DisplayValidationException; -use Pterodactyl\Repositories\old_Daemon\FileRepository; class ServerController extends Controller { - /** - * Renders server index page for specified server. - * - * @param \Illuminate\Http\Request $request - * @param string $uuid - * @return \Illuminate\View\View - */ - public function getIndex(Request $request, $uuid) - { - $server = Models\Server::byUuid($uuid); - - $server->js([ - 'meta' => [ - 'saveFile' => route('server.files.save', $server->uuidShort), - 'csrfToken' => csrf_token(), - ], - 'config' => [ - 'console_count' => config('pterodactyl.console.count'), - 'console_freq' => config('pterodactyl.console.frequency'), - ], - ]); - - return view('server.index', [ - 'server' => $server, - 'node' => $server->node, - ]); - } - - /** - * Renders server console as an individual item. - * - * @param \Illuminate\Http\Request $request - * @param string $uuid - * @return \Illuminate\View\View - */ - public function getConsole(Request $request, $uuid) - { - \Debugbar::disable(); - $server = Models\Server::byUuid($uuid); - - $server->js([ - 'config' => [ - 'console_count' => config('pterodactyl.console.count'), - 'console_freq' => config('pterodactyl.console.frequency'), - ], - ]); - - return view('server.console', [ - 'server' => $server, - 'node' => $server->node, - ]); - } - /** * Renders file overview page. * diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index a70895a3e..1e98b9cfd 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -54,7 +54,8 @@ class Kernel extends HttpKernel 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'guest' => \Pterodactyl\Http\Middleware\RedirectIfAuthenticated::class, - 'server' => \Pterodactyl\Http\Middleware\CheckServer::class, + 'server' => \Pterodactyl\Http\Middleware\ServerAuthenticate::class, + 'subuser' => \Pterodactyl\Http\Middleware\SubuserAccessAuthenticate::class, 'admin' => \Pterodactyl\Http\Middleware\AdminAuthenticate::class, 'daemon' => \Pterodactyl\Http\Middleware\DaemonAuthenticate::class, 'csrf' => \Pterodactyl\Http\Middleware\VerifyCsrfToken::class, diff --git a/app/Http/Middleware/CheckServer.php b/app/Http/Middleware/ServerAuthenticate.php similarity index 56% rename from app/Http/Middleware/CheckServer.php rename to app/Http/Middleware/ServerAuthenticate.php index c1da9ea1b..83d35073d 100644 --- a/app/Http/Middleware/CheckServer.php +++ b/app/Http/Middleware/ServerAuthenticate.php @@ -24,106 +24,102 @@ namespace Pterodactyl\Http\Middleware; -use Auth; use Closure; +use Illuminate\Contracts\Session\Session; use Illuminate\Http\Request; +use Pterodactyl\Contracts\Repository\ServerRepositoryInterface; use Pterodactyl\Models\Server; +use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Auth\AuthenticationException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; -class CheckServer +class ServerAuthenticate { /** - * The elquent model for the server. - * + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface + */ + protected $repository; + + /** * @var \Pterodactyl\Models\Server */ protected $server; /** - * The request object. - * - * @var \Illuminate\Http\Request + * @var \Illuminate\Contracts\Session\Session */ - protected $request; + protected $session; /** - * Handle an incoming request. + * ServerAuthenticate constructor. + * + * @param \Illuminate\Contracts\Config\Repository $config + * @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository + * @param \Illuminate\Contracts\Session\Session $session + */ + public function __construct( + ConfigRepository $config, + ServerRepositoryInterface $repository, + Session $session + ) { + $this->config = $config; + $this->repository = $repository; + $this->session = $session; + } + + /** + * Determine if a given user has permission to access a server. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed + * + * @throws \Illuminate\Auth\AuthenticationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException */ public function handle(Request $request, Closure $next) { - if (! Auth::user()) { - throw new AuthenticationException(); + if (! $request->user()) { + throw new AuthenticationException; } - $this->request = $request; - $this->server = Server::byUuid($request->route()->server); + $attributes = $request->route()->parameter('server'); + $isApiRequest = $request->expectsJson() || $request->is(...$this->config->get('pterodactyl.json_routes', [])); + $server = $this->repository->getByUuid($attributes instanceof Server ? $attributes->uuid : $attributes); + + if (! $server) { + if ($isApiRequest) { + throw new NotFoundHttpException('The requested server was not found on the system.'); + } - if (! $this->exists()) { return response()->view('errors.404', [], 404); } - if ($this->suspended()) { + if ($server->suspended) { + if ($isApiRequest) { + throw new AccessDeniedHttpException('Server is suspended.'); + } + return response()->view('errors.suspended', [], 403); } - if (! $this->installed()) { + if ($server->installed !== 1) { + if ($isApiRequest) { + throw new AccessDeniedHttpException('Server is completing install process.'); + } + return response()->view('errors.installing', [], 403); } + // Store the server in the session. + $this->session->now('server_data.model', $server); + return $next($request); } - - /** - * Determine if the server was found on the system. - * - * @return bool - */ - protected function exists() - { - if (! $this->server) { - if ($this->request->expectsJson() || $this->request->is(...config('pterodactyl.json_routes'))) { - throw new NotFoundHttpException('The requested server was not found on the system.'); - } - } - - return (! $this->server) ? false : true; - } - - /** - * Determine if the server is suspended. - * - * @return bool - */ - protected function suspended() - { - if ($this->server->suspended) { - if ($this->request->expectsJson() || $this->request->is(...config('pterodactyl.json_routes'))) { - throw new AccessDeniedHttpException('Server is suspended.'); - } - } - - return $this->server->suspended; - } - - /** - * Determine if the server is installed. - * - * @return bool - */ - protected function installed() - { - if ($this->server->installed !== 1) { - if ($this->request->expectsJson() || $this->request->is(...config('pterodactyl.json_routes'))) { - throw new AccessDeniedHttpException('Server is completing install process.'); - } - } - - return $this->server->installed === 1; - } } diff --git a/app/Http/Middleware/SubuserAccessAuthenticate.php b/app/Http/Middleware/SubuserAccessAuthenticate.php new file mode 100644 index 000000000..ca52d7e22 --- /dev/null +++ b/app/Http/Middleware/SubuserAccessAuthenticate.php @@ -0,0 +1,81 @@ +. + * + * 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\Http\Middleware; + +use Closure; +use Illuminate\Auth\AuthenticationException; +use Illuminate\Contracts\Session\Session; +use Illuminate\Http\Request; +use Pterodactyl\Exceptions\Service\Server\UserNotLinkedToServerException; +use Pterodactyl\Services\Servers\ServerAccessHelperService; + +class SubuserAccessAuthenticate +{ + /** + * @var \Pterodactyl\Services\Servers\ServerAccessHelperService + */ + protected $accessHelperService; + + /** + * @var \Illuminate\Contracts\Session\Session + */ + protected $session; + + /** + * SubuserAccessAuthenticate constructor. + * + * @param \Pterodactyl\Services\Servers\ServerAccessHelperService $accessHelperService + * @param \Illuminate\Contracts\Session\Session $session + */ + public function __construct( + ServerAccessHelperService $accessHelperService, + Session $session + ) { + $this->accessHelperService = $accessHelperService; + $this->session = $session; + } + + /** + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + * + * @throws \Illuminate\Auth\AuthenticationException + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + */ + public function handle(Request $request, Closure $next) + { + $server = $this->session->get('server_data.model'); + + try { + $token = $this->accessHelperService->handle($server, $request->user()); + $this->session->now('server_data.token', $token); + } catch (UserNotLinkedToServerException $exception) { + throw new AuthenticationException('This account does not have permission to access this server.'); + } + + return $next($request); + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 9876208c5..64b747d0d 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -50,7 +50,7 @@ class RouteServiceProvider extends ServiceProvider ->namespace($this->namespace . '\Auth') ->group(base_path('routes/auth.php')); - Route::middleware(['web', 'auth', 'server', 'csrf'])->prefix('/server/{server}') + Route::middleware(['web', 'csrf', 'auth', 'server', 'subuser'])->prefix('/server/{server}') ->namespace($this->namespace . '\Server') ->group(base_path('routes/server.php')); diff --git a/app/Services/Servers/ServerAccessHelperService.php b/app/Services/Servers/ServerAccessHelperService.php index 2aef717f8..deabbc050 100644 --- a/app/Services/Servers/ServerAccessHelperService.php +++ b/app/Services/Servers/ServerAccessHelperService.php @@ -24,6 +24,8 @@ namespace Pterodactyl\Services\Servers; +use Pterodactyl\Exceptions\Service\Server\UserNotLinkedToServerException; +use Pterodactyl\Models\Server; use Pterodactyl\Models\User; use Illuminate\Cache\Repository as CacheRepository; use Pterodactyl\Contracts\Repository\UserRepositoryInterface; @@ -44,28 +46,37 @@ class ServerAccessHelperService $this->userRepository = $userRepository; } - public function handle($uuid, $user) + /** + * @param int|\Pterodactyl\Models\Server $server + * @param int|\Pterodactyl\Models\User $user + * @return string + * + * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + * @throws \Pterodactyl\Exceptions\Service\Server\UserNotLinkedToServerException + */ + public function handle($server, $user) { + if (! $server instanceof Server) { + $server = $this->repository->find($server); + } + if (! $user instanceof User) { $user = $this->userRepository->find($user); } - $server = $this->repository->getByUuid($uuid); - if (! $user->root_admin) { - if (! in_array($server->id, $this->repository->getUserAccessServers($user->id))) { - throw new \Exception('User does not have access.'); - } - - if ($server->owner_id !== $user->id) { - $subuser = $this->subuserRepository->withColumns('daemonSecret')->findWhere([ - ['user_id', '=', $user->id], - ['server_id', '=', $server->id], - ]); - - $server->daemonSecret = $subuser->daemonToken; - } + if ($user->root_admin || $server->owner_id === $user->id) { + return $server->daemonSecret; } - return $server; + if (! in_array($server->id, $this->repository->getUserAccessServers($user->id))) { + throw new UserNotLinkedToServerException; + } + + $subuser = $this->subuserRepository->withColumns('daemonSecret')->findWhere([ + ['user_id', '=', $user->id], + ['server_id', '=', $server->id], + ]); + + return $subuser->daemonSecret; } } diff --git a/app/Traits/Controllers/ServerToJavascript.php b/app/Traits/Controllers/ServerToJavascript.php new file mode 100644 index 000000000..6c550f58f --- /dev/null +++ b/app/Traits/Controllers/ServerToJavascript.php @@ -0,0 +1,64 @@ +. + * + * 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\Traits\Controllers; + +use Javascript; + +trait ServerToJavascript +{ + /** + * @var \Illuminate\Contracts\Session\Session + */ + protected $session; + + /** + * Injects server javascript into the page to be used by other services. + * + * @param array $args + * @param bool $overwrite + * @return mixed + */ + public function injectJavascript($args = [], $overwrite = false) + { + $server = $this->session->get('server_data.model'); + $token = $this->session->get('server_data.token'); + + $response = array_merge([ + 'server' => [ + 'uuid' => $server->uuid, + 'uuidShort' => $server->uuidShort, + 'daemonSecret' => $token, + 'username' => $server->username, + ], + 'node' => [ + 'fqdn' => $server->node->fqdn, + 'scheme' => $server->node->scheme, + 'daemonListen' => $server->node->daemonListen, + ], + ], $args); + + return Javascript::put($overwrite ? $args : $response); + } +} diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 7a137d100..a0963fd94 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -74,9 +74,9 @@ -
  • - -
  • + {{--
  • --}} + {{----}} + {{--
  • --}} @if(Auth::user()->isRootAdmin())
  • @@ -241,27 +241,28 @@ diff --git a/routes/server.php b/routes/server.php index d446bf6a0..f8e68ee62 100644 --- a/routes/server.php +++ b/routes/server.php @@ -21,8 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -Route::get('/', 'ServerController@getIndex')->name('server.index'); -Route::get('/console', 'ServerController@getConsole')->name('server.console'); +Route::get('/', 'ConsoleController@index')->name('server.index'); +Route::get('/console', 'ConsoleController@console')->name('server.console'); /* |-------------------------------------------------------------------------- diff --git a/tests/Unit/Http/Controllers/Server/ConsoleControllerTest.php b/tests/Unit/Http/Controllers/Server/ConsoleControllerTest.php new file mode 100644 index 000000000..e56c4ea7b --- /dev/null +++ b/tests/Unit/Http/Controllers/Server/ConsoleControllerTest.php @@ -0,0 +1,105 @@ +. + * + * 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 Tests\Unit\Http\Controllers\Server; + +use Illuminate\Contracts\Session\Session; +use Mockery as m; +use Pterodactyl\Http\Controllers\Server\ConsoleController; +use Pterodactyl\Models\Node; +use Pterodactyl\Models\Server; +use Tests\Assertions\ControllerAssertionsTrait; +use Tests\TestCase; +use Illuminate\Contracts\Config\Repository; + +class ConsoleControllerTest extends TestCase +{ + use ControllerAssertionsTrait; + + /** + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * @var \Pterodactyl\Http\Controllers\Server\ConsoleController + */ + protected $controller; + + /** + * @var \Illuminate\Contracts\Session\Session + */ + protected $session; + + /** + * Setup tests. + */ + public function setUp() + { + parent::setUp(); + + $this->config = m::mock(Repository::class); + $this->session = m::mock(Session::class); + + $this->controller = m::mock(ConsoleController::class, [$this->config, $this->session])->makePartial(); + } + + /** + * Test both controllers as they do effectively the same thing. + * + * @dataProvider controllerDataProvider + */ + public function testAllControllers($function, $view) + { + $server = factory(Server::class)->make(); + $node = factory(Node::class)->make(); + $server->node = $node; + + $this->session->shouldReceive('get')->with('server_data.model')->once()->andReturn($server); + $this->config->shouldReceive('get')->with('pterodactyl.console.count')->once()->andReturn(100); + $this->config->shouldReceive('get')->with('pterodactyl.console.frequency')->once()->andReturn(10); + $this->controller->shouldReceive('injectJavascript')->once()->andReturnNull(); + + $response = $this->controller->$function(); + $this->assertIsViewResponse($response); + $this->assertViewNameEquals($view, $response); + $this->assertViewHasKey('server', $response); + $this->assertViewHasKey('node', $response); + $this->assertViewKeyEquals('server', $server, $response); + $this->assertViewKeyEquals('node', $node, $response); + } + + /** + * Provide data for the tests. + * + * @return array + */ + public function controllerDataProvider() + { + return [ + ['index', 'server.index'], + ['console', 'server.console'], + ]; + } +}