diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index b3aefd1cd..c8025acde 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -46,7 +46,7 @@ class Handler extends ExceptionHandler */ public function render($request, Exception $exception) { - if ($request->expectsJson() || $request->isJson() || $request->is('api/*', 'remote/*', 'daemon/*')) { + if ($request->expectsJson() || $request->isJson() || $request->is(...config('pterodactyl.json_routes'))) { if (config('app.debug')) { $report = [ @@ -56,7 +56,7 @@ class Handler extends ExceptionHandler } $response = response()->json([ - 'error' => $exception->getMessage(), + 'error' => (config('app.debug')) ? $exception->getMessage() : 'An unhandled exception was encountered with this request.', 'exception' => ! isset($report) ?: $report, ], ($this->isHttpException($exception)) ? $exception->getStatusCode() : 500, [], JSON_UNESCAPED_SLASHES); diff --git a/app/Http/Controllers/API_old/User/InfoController.php b/app/Http/Controllers/API/User/ServerController.php similarity index 62% rename from app/Http/Controllers/API_old/User/InfoController.php rename to app/Http/Controllers/API/User/ServerController.php index faf1be622..b868cdb0e 100644 --- a/app/Http/Controllers/API_old/User/InfoController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -24,24 +24,35 @@ namespace Pterodactyl\Http\Controllers\API\User; +use Fractal; use Illuminate\Http\Request; -use Pterodactyl\Http\Controllers\API\BaseController; +use Pterodactyl\Models\Server; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Transformers\User\ServerTransformer; -class InfoController extends BaseController +class ServerController extends Controller { - public function me(Request $request) + public function index(Request $request, $uuid) { - return $request->user()->access('service', 'node', 'allocation', 'option')->get()->map(function ($server) { - return [ - 'id' => $server->uuidShort, - 'uuid' => $server->uuid, - 'name' => $server->name, - 'node' => $server->node->name, - 'ip' => $server->allocation->alias, - 'port' => $server->allocation->port, - 'service' => $server->service->name, - 'option' => $server->option->name, - ]; - })->all(); + $server = Server::byUuid($uuid); + $fractal = Fractal::create()->item($server); + + if ($request->input('with')) { + $fractal->parseIncludes(collect(explode(',', $request->input('with')))->intersect([ + 'allocations', 'subusers', 'stats', + ])->toArray()); + } + + return $fractal->transformWith(new ServerTransformer)->toArray(); + } + + public function power(Request $request, $uuid) + { + + } + + public function command(Request $request, $uuid) + { + } } diff --git a/app/Http/Controllers/API_old/NodeController.php b/app/Http/Controllers/API_old/NodeController.php deleted file mode 100755 index 6a03bdba1..000000000 --- a/app/Http/Controllers/API_old/NodeController.php +++ /dev/null @@ -1,172 +0,0 @@ -. - * - * 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\API; - -use Log; -use Illuminate\Http\Request; -use Pterodactyl\Models\Node; -use Pterodactyl\Models\Allocation; -use Dingo\Api\Exception\ResourceException; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Repositories\NodeRepository; -use Pterodactyl\Exceptions\DisplayValidationException; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; -use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; - -class NodeController extends BaseController -{ - /** - * Lists all nodes currently on the system. - * - * @param Request $request - * @return array - */ - public function index(Request $request) - { - return Node::all()->toArray(); - } - - /** - * Create a new node. - * - * @param Request $request - * @return array - * - * @throws \Pterodactyl\Exceptions\DisplayException - * @throws \Pterodactyl\Exceptions\DisplayValidationException - */ - public function create(Request $request) - { - $repo = new NodeRepository; - - try { - $node = $repo->create(array_merge( - $request->only([ - 'public', 'disk_overallocate', 'memory_overallocate', - ]), - $request->intersect([ - 'name', 'location_id', 'fqdn', - 'scheme', 'memory', 'disk', - 'daemonBase', 'daemonSFTP', 'daemonListen', - ]) - )); - - return ['id' => $node->id]; - } catch (DisplayValidationException $ex) { - throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $ex) { - Log::error($ex); - throw new BadRequestHttpException('There was an error while attempting to add this node to the system. This error has been logged.'); - } - } - - /** - * Lists specific fields about a server or all fields pertaining to that node. - * - * @param Request $request - * @param int $id - * @param string $fields - * @return array - */ - public function view(Request $request, $id, $fields = null) - { - $node = Node::with('allocations')->findOrFail($id); - - $node->allocations->transform(function ($item) { - return collect($item)->only([ - 'id', 'ip', 'ip_alias', 'port', 'server_id', - ]); - }); - - if (! empty($request->input('fields'))) { - $fields = explode(',', $request->input('fields')); - if (! empty($fields) && is_array($fields)) { - return collect($node)->only($fields); - } - } - - return $node->toArray(); - } - - /** - * Returns a configuration file for a given node. - * - * @param Request $request - * @param int $id - * @return array - */ - public function config(Request $request, $id) - { - $node = Node::findOrFail($id); - - return $node->getConfigurationAsJson(); - } - - /** - * Returns a listing of all allocations for every node. - * - * @param Request $request - * @return array - */ - public function allocations(Request $request) - { - return Allocation::all()->toArray(); - } - - /** - * Returns a listing of the allocation for the specified server id. - * - * @param Request $request - * @param int $id - * @return array - */ - public function allocationsView(Request $request, $id) - { - return Allocation::where('server_id', $id)->get()->toArray(); - } - - /** - * Delete a node. - * - * @param Request $request - * @param int $id - * @return void - */ - public function delete(Request $request, $id) - { - $repo = new NodeRepository; - try { - $repo->delete($id); - - return $this->response->noContent(); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $e) { - throw new ServiceUnavailableHttpException('An error occured while attempting to delete this node.'); - } - } -} diff --git a/app/Http/Controllers/API_old/ServerController.php b/app/Http/Controllers/API_old/ServerController.php deleted file mode 100755 index 769fa9412..000000000 --- a/app/Http/Controllers/API_old/ServerController.php +++ /dev/null @@ -1,231 +0,0 @@ -. - * - * 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\API; - -use Log; -use Illuminate\Http\Request; -use Pterodactyl\Models\Server; -use Dingo\Api\Exception\ResourceException; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Repositories\ServerRepository; -use Pterodactyl\Exceptions\DisplayValidationException; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; -use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; - -class ServerController extends BaseController -{ - /** - * Lists all servers currently on the system. - * - * @param Request $request - * @return array - */ - public function index(Request $request) - { - return Server::all()->toArray(); - } - - /** - * Create Server. - * - * @param Request $request - * @return array - */ - public function create(Request $request) - { - $repo = new ServerRepository; - - try { - $server = $repo->create($request->all()); - - return ['id' => $server->id]; - } catch (DisplayValidationException $ex) { - throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $ex) { - Log::error($ex); - throw new BadRequestHttpException('There was an error while attempting to add this server to the system.'); - } - } - - /** - * List Specific Server. - * - * @param Request $request - * @param int $id - * @return array - */ - public function view(Request $request, $id) - { - $server = Server::with('node', 'allocations', 'pack')->where('id', $id)->firstOrFail(); - - if (! is_null($request->input('fields'))) { - $fields = explode(',', $request->input('fields')); - if (! empty($fields) && is_array($fields)) { - return collect($server)->only($fields); - } - } - - if ($request->input('daemon') === 'true') { - try { - $response = $server->node->guzzleClient([ - 'X-Access-Token' => $server->node->daemonSecret, - ])->request('GET', '/servers'); - - $server->daemon = json_decode($response->getBody())->{$server->uuid}; - } catch (\GuzzleHttp\Exception\TransferException $ex) { - // Couldn't hit the daemon, return what we have though. - $server->daemon = [ - 'error' => 'There was an error encountered while attempting to connect to the remote daemon.', - ]; - } - } - - $server->allocations->transform(function ($item) { - return collect($item)->except(['created_at', 'updated_at']); - }); - - return $server->toArray(); - } - - /** - * Update Server configuration. - * - * @param Request $request - * @param int $id - * @return array - */ - public function config(Request $request, $id) - { - $repo = new ServerRepository; - - try { - $server = $repo->updateDetails($id, $request->intersect([ - 'owner_id', 'name', 'reset_token', - ])); - - return ['id' => $id]; - } catch (DisplayValidationException $ex) { - throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $ex) { - throw new ServiceUnavailableHttpException('Unable to update server on system due to an error.'); - } - } - - /** - * Update Server Build Configuration. - * - * @param Request $request - * @param int $id - * @return array - */ - public function build(Request $request, $id) - { - $repo = new ServerRepository; - - try { - $server = $repo->changeBuild($id, $request->intersect([ - 'allocation_id', 'add_allocations', 'remove_allocations', - 'memory', 'swap', 'io', 'cpu', - ])); - - return ['id' => $id]; - } catch (DisplayValidationException $ex) { - throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $ex) { - throw new ServiceUnavailableHttpException('Unable to update server on system due to an error.'); - } - } - - /** - * Suspend Server. - * - * @param Request $request - * @param int $id - * @return void - */ - public function suspend(Request $request, $id) - { - try { - $repo = new ServerRepository; - $repo->suspend($id); - - return $this->response->noContent(); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $ex) { - throw new ServiceUnavailableHttpException('An error occured while attempting to suspend this server instance.'); - } - } - - /** - * Unsuspend Server. - * - * @param Request $request - * @param int $id - * @return void - */ - public function unsuspend(Request $request, $id) - { - try { - $repo = new ServerRepository; - $repo->unsuspend($id); - - return $this->response->noContent(); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $ex) { - throw new ServiceUnavailableHttpException('An error occured while attempting to unsuspend this server instance.'); - } - } - - /** - * Delete Server. - * - * @param Request $request - * @param int $id - * @param string|null $force - * @return void - */ - public function delete(Request $request, $id, $force = null) - { - $repo = new ServerRepository; - - try { - $repo->delete($id, is_null($force)); - - return $this->response->noContent(); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $e) { - throw new ServiceUnavailableHttpException('An error occured while attempting to delete this server.'); - } - } -} diff --git a/app/Http/Controllers/API_old/User/ServerController.php b/app/Http/Controllers/API_old/User/ServerController.php deleted file mode 100644 index ced350476..000000000 --- a/app/Http/Controllers/API_old/User/ServerController.php +++ /dev/null @@ -1,132 +0,0 @@ -. - * - * 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\API\User; - -use Log; -use Illuminate\Http\Request; -use Pterodactyl\Models\Server; -use Pterodactyl\Http\Controllers\API\BaseController; - -class ServerController extends BaseController -{ - public function info(Request $request, $uuid) - { - $server = Server::byUuid($uuid)->load('allocations'); - - try { - $response = $server->guzzleClient()->request('GET', '/server'); - - $json = json_decode($response->getBody()); - $daemon = [ - 'status' => $json->status, - 'stats' => $json->proc, - ]; - } catch (\Exception $ex) { - $daemon = [ - 'error' => 'An error was encountered while trying to connect to the daemon to collect information. It might be offline.', - ]; - Log::error($ex); - } - - return [ - 'uuidShort' => $server->uuidShort, - 'uuid' => $server->uuid, - 'name' => $server->name, - 'node' => $server->node->name, - 'limits' => [ - 'memory' => $server->memory, - 'swap' => $server->swap, - 'disk' => $server->disk, - 'io' => $server->io, - 'cpu' => $server->cpu, - 'oom_disabled' => (bool) $server->oom_disabled, - ], - 'allocations' => $server->allocations->map(function ($item) use ($server) { - return [ - 'ip' => $item->alias, - 'port' => $item->port, - 'default' => ($item->id === $server->allocation_id), - ]; - }), - 'sftp' => [ - 'username' => ($request->user()->can('view-sftp', $server)) ? $server->username : null, - ], - 'daemon' => [ - 'token' => $server->daemonSecret, - 'response' => $daemon, - ], - ]; - } - - public function power(Request $request, $uuid) - { - $server = Server::byUuid($uuid); - $request->user()->can('power-' . $request->input('action'), $server); - - if (empty($request->input('action'))) { - return $this->response()->error([ - 'error' => 'An action must be passed to this request.', - ], 422); - } - - $res = $server->guzzleClient()->request('PUT', '/server/power', [ - 'exceptions' => false, - 'json' => [ - 'action' => $request->input('action'), - ], - ]); - - if ($res->getStatusCode() !== 204) { - return $this->response->error(json_decode($res->getBody())->error, $res->getStatusCode()); - } - - return $this->response->noContent(); - } - - public function command(Request $request, $uuid) - { - $server = Server::byUuid($uuid); - $request->user()->can('send-command', $server); - - if (empty($request->input('command'))) { - return $this->response()->error([ - 'error' => 'A command must be passed to this request.', - ], 422); - } - - $res = $server->guzzleClient()->request('POST', '/server/command', [ - 'exceptions' => false, - 'json' => [ - 'command' => $request->input('command'), - ], - ]); - - if ($res->getStatusCode() !== 204) { - return $this->response->error(json_decode($res->getBody())->error, $res->getStatusCode()); - } - - return $this->response->noContent(); - } -} diff --git a/app/Http/Controllers/API_old/UserController.php b/app/Http/Controllers/API_old/UserController.php deleted file mode 100755 index 981baef51..000000000 --- a/app/Http/Controllers/API_old/UserController.php +++ /dev/null @@ -1,151 +0,0 @@ -. - * - * 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\API; - -use Illuminate\Http\Request; -use Pterodactyl\Models\User; -use Dingo\Api\Exception\ResourceException; -use Pterodactyl\Exceptions\DisplayException; -use Pterodactyl\Repositories\UserRepository; -use Pterodactyl\Exceptions\DisplayValidationException; -use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; - -class UserController extends BaseController -{ - /** - * Lists all users currently on the system. - * - * @param Request $request - * @return array - */ - public function index(Request $request) - { - return User::all()->toArray(); - } - - /** - * Lists specific fields about a user or all fields pertaining to that user. - * - * @param Request $request - * @param int $id - * @return array - */ - public function view(Request $request, $id) - { - $user = User::with('servers')->where((is_numeric($id) ? 'id' : 'email'), $id)->firstOrFail(); - - $user->servers->transform(function ($item) { - return collect($item)->only([ - 'id', 'node_id', 'uuidShort', - 'uuid', 'name', 'suspended', - 'owner_id', - ]); - }); - - if (! is_null($request->input('fields'))) { - $fields = explode(',', $request->input('fields')); - if (! empty($fields) && is_array($fields)) { - return collect($user)->only($fields); - } - } - - return $user->toArray(); - } - - /** - * Create a New User. - * - * @param Request $request - * @return array - */ - public function create(Request $request) - { - $repo = new UserRepository; - - try { - $user = $user->create($request->only([ - 'email', 'password', 'name_first', - 'name_last', 'username', 'root_admin', - ])); - - return ['id' => $user->id]; - } catch (DisplayValidationException $ex) { - throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $ex) { - throw new ServiceUnavailableHttpException('Unable to create a user on the system due to an error.'); - } - } - - /** - * Update an Existing User. - * - * @param Request $request - * @param int $id - * @return array - */ - public function update(Request $request, $id) - { - $repo = new UserRepository; - - try { - $user = $repo->update($id, $request->only([ - 'email', 'password', 'name_first', - 'name_last', 'username', 'root_admin', - ])); - - return ['id' => $id]; - } catch (DisplayValidationException $ex) { - throw new ResourceException('A validation error occured.', json_decode($ex->getMessage(), true)); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $ex) { - throw new ServiceUnavailableHttpException('Unable to update a user on the system due to an error.'); - } - } - - /** - * Delete a User. - * - * @param Request $request - * @param int $id - * @return void - */ - public function delete(Request $request, $id) - { - $repo = new UserRepository; - - try { - $repo->delete($id); - - return $this->response->noContent(); - } catch (DisplayException $ex) { - throw new ResourceException($ex->getMessage()); - } catch (\Exception $ex) { - throw new ServiceUnavailableHttpException('Unable to delete this user due to an error.'); - } - } -} diff --git a/app/Http/Middleware/CheckServer.php b/app/Http/Middleware/CheckServer.php index 33f817295..a913b87ea 100644 --- a/app/Http/Middleware/CheckServer.php +++ b/app/Http/Middleware/CheckServer.php @@ -28,9 +28,26 @@ use Auth; use Closure; use Illuminate\Http\Request; use Pterodactyl\Models\Server; +use Illuminate\Auth\AuthenticationException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class CheckServer { + /** + * The elquent model for the server. + * + * @var \Pterodactyl\Models\Server + */ + protected $server; + + /** + * The request object. + * + * @var \Illuminate\Http\Request + */ + protected $request; + /** * Handle an incoming request. * @@ -41,22 +58,72 @@ class CheckServer public function handle(Request $request, Closure $next) { if (! Auth::user()) { - return redirect()->guest('auth/login'); + throw new AuthenticationException(); } - $server = Server::byUuid($request->route()->server); - if (! $server) { + $this->request = $request; + $this->server = Server::byUuid($request->route()->server); + + if(! $this->exists()) { return response()->view('errors.404', [], 404); } - if ($server->suspended) { + if ($this->suspended()) { return response()->view('errors.suspended', [], 403); } - if (! $server->installed) { + if (! $this->installed()) { return response()->view('errors.installing', [], 403); } 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/HMACAuthorization.php b/app/Http/Middleware/HMACAuthorization.php index 46f19c363..75b6a0f79 100644 --- a/app/Http/Middleware/HMACAuthorization.php +++ b/app/Http/Middleware/HMACAuthorization.php @@ -198,7 +198,7 @@ class HMACAuthorization */ protected function generateSignature() { - $content = urldecode($this->request()->url()) . $this->request()->getContent(); + $content = urldecode($this->request()->fullUrl()) . $this->request()->getContent(); return hash_hmac(self::HMAC_ALGORITHM, $content, Crypt::decrypt($this->key()->secret), true); } diff --git a/app/Http/Controllers/API_old/BaseController.php b/app/Transformers/User/AllocationTransformer.php old mode 100755 new mode 100644 similarity index 57% rename from app/Http/Controllers/API_old/BaseController.php rename to app/Transformers/User/AllocationTransformer.php index 085803a11..2e58574e6 --- a/app/Http/Controllers/API_old/BaseController.php +++ b/app/Transformers/User/AllocationTransformer.php @@ -22,12 +22,42 @@ * SOFTWARE. */ -namespace Pterodactyl\Http\Controllers\API; +namespace Pterodactyl\Transformers\User; -use Dingo\Api\Routing\Helpers; -use Illuminate\Routing\Controller; +use Pterodactyl\Models\Server; +use Pterodactyl\Models\Allocation; +use League\Fractal\TransformerAbstract; -class BaseController extends Controller +class AllocationTransformer extends TransformerAbstract { - use Helpers; + /** + * Server eloquent model. + * + * @return \Pterodactyl\Models\Server + */ + protected $server; + + /** + * Setup allocation transformer with access to server data. + * + * @return void + */ + public function __construct(Server $server) + { + $this->server = $server; + } + + /** + * Return a generic transformed allocation array. + * + * @return array + */ + public function transform(Allocation $allocation) + { + return [ + 'ip' => $allocation->alias, + 'port' => $allocation->port, + 'default' => ($allocation->id === $this->server->allocation_id), + ]; + } } diff --git a/app/Http/Controllers/API_old/ServiceController.php b/app/Transformers/User/OverviewTransformer.php old mode 100755 new mode 100644 similarity index 63% rename from app/Http/Controllers/API_old/ServiceController.php rename to app/Transformers/User/OverviewTransformer.php index 1916ef41c..57c5b8d6c --- a/app/Http/Controllers/API_old/ServiceController.php +++ b/app/Transformers/User/OverviewTransformer.php @@ -22,22 +22,29 @@ * SOFTWARE. */ -namespace Pterodactyl\Http\Controllers\API; +namespace Pterodactyl\Transformers\User; -use Illuminate\Http\Request; -use Pterodactyl\Models\Service; +use Pterodactyl\Models\Server; +use League\Fractal\TransformerAbstract; -class ServiceController extends BaseController +class OverviewTransformer extends TransformerAbstract { - public function index(Request $request) + /** + * Return a generic transformed server array. + * + * @return array + */ + public function transform(Server $server) { - return Service::all()->toArray(); - } - - public function view(Request $request, $id) - { - $service = Service::with('options.variables', 'options.packs')->findOrFail($id); - - return $service->toArray(); + return [ + 'uuidShort' => $server->uuidShort, + 'uuid' => $server->uuid, + 'name' => $server->name, + 'node' => $server->node->name, + 'ip' => $server->allocation->alias, + 'port' => $server->allocation->port, + 'service' => $server->service->name, + 'option' => $server->option->name, + ]; } } diff --git a/app/Transformers/User/ServerTransformer.php b/app/Transformers/User/ServerTransformer.php index 2dba2adc2..063718863 100644 --- a/app/Transformers/User/ServerTransformer.php +++ b/app/Transformers/User/ServerTransformer.php @@ -29,6 +29,17 @@ use League\Fractal\TransformerAbstract; class ServerTransformer extends TransformerAbstract { + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = [ + 'allocations', + 'subusers', + 'stats', + ]; + /** * Return a generic transformed server array. * @@ -37,14 +48,53 @@ class ServerTransformer extends TransformerAbstract public function transform(Server $server) { return [ - 'short' => $server->uuidShort, + 'uuidShort' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, + 'description' => $server->description, 'node' => $server->node->name, - 'ip' => $server->allocation->alias, - 'port' => $server->allocation->port, - 'service' => $server->service->name, - 'option' => $server->option->name, + 'limits' => [ + 'memory' => $server->memory, + 'swap' => $server->swap, + 'disk' => $server->disk, + 'io' => $server->io, + 'cpu' => $server->cpu, + 'oom_disabled' => (bool) $server->oom_disabled, + ], ]; } + + /** + * Return a generic array of allocations for this server. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeAllocations(Server $server) + { + $allocations = $server->allocations; + + return $this->collection($allocations, new AllocationTransformer($server)); + } + + /** + * Return a generic array of subusers for this server. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeSubusers(Server $server) + { + $server->load('subusers.permissions', 'subusers.user'); + + return $this->collection($server->subusers, new SubuserTransformer); + } + + /** + * Return a generic array of allocations for this server. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeStats(Server $server) + { + return $this->item($server->guzzleClient(), new StatsTransformer); + } } diff --git a/app/Transformers/User/StatsTransformer.php b/app/Transformers/User/StatsTransformer.php new file mode 100644 index 000000000..15bfa699c --- /dev/null +++ b/app/Transformers/User/StatsTransformer.php @@ -0,0 +1,62 @@ +. + * + * 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\User; + +use GuzzleHttp\Client; +use League\Fractal\TransformerAbstract; +use GuzzleHttp\Exception\ConnectException; + +class StatsTransformer extends TransformerAbstract +{ + /** + * Return a generic transformed subuser array. + * + * @return array + */ + public function transform(Client $client) + { + try { + $res = $client->request('GET', '/server', ['http_errors' => false]); + + if ($res->getStatusCode() !== 200) { + return [ + 'error' => 'Error: HttpResponseException. Recieved non-200 HTTP status code from daemon: ' . $res->statusCode(), + ]; + } + + $json = json_decode($res->getBody()); + + return [ + 'status' => $json->status, + 'resources' => $json->proc, + ]; + } catch (ConnectException $ex) { + return [ + 'error' => 'Error: ConnectException. Unable to contact the daemon to request server status.', + 'exception' => (config('app.debug')) ? $ex->getMessage() : null, + ]; + } + } +} diff --git a/app/Http/Controllers/API_old/LocationController.php b/app/Transformers/User/SubuserTransformer.php old mode 100755 new mode 100644 similarity index 68% rename from app/Http/Controllers/API_old/LocationController.php rename to app/Transformers/User/SubuserTransformer.php index 29ff72c34..0793eed3b --- a/app/Http/Controllers/API_old/LocationController.php +++ b/app/Transformers/User/SubuserTransformer.php @@ -22,27 +22,26 @@ * SOFTWARE. */ -namespace Pterodactyl\Http\Controllers\API; +namespace Pterodactyl\Transformers\User; -use Illuminate\Http\Request; -use Pterodactyl\Models\Location; +use Pterodactyl\Models\Subuser; +use Pterodactyl\Models\Permission; +use League\Fractal\TransformerAbstract; -class LocationController extends BaseController +class SubuserTransformer extends TransformerAbstract { /** - * Lists all locations currently on the system. + * Return a generic transformed subuser array. * - * @param Request $request * @return array */ - public function index(Request $request) + public function transform(Subuser $subuser) { - return Location::with('nodes')->get()->map(function ($item) { - $item->nodes->transform(function ($item) { - return collect($item)->only(['id', 'name', 'fqdn', 'scheme', 'daemonListen', 'daemonSFTP']); - }); - - return $item; - })->toArray(); + return [ + 'username' => $subuser->user->username, + 'email' => $subuser->user->email, + '2fa' => (bool) $subuser->user->use_totp, + 'permissions' => $subuser->permissions->pluck('permission'), + ]; } } diff --git a/config/pterodactyl.php b/config/pterodactyl.php index ddaee443e..bbe93f4da 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -103,4 +103,18 @@ return [ 'lang' => [ 'in_context' => env('PHRASE_IN_CONTEXT', false), ], + + /* + |-------------------------------------------------------------------------- + | JSON Response Routes + |-------------------------------------------------------------------------- + | + | You should not edit this block. These routes are ajax based routes that + | expect content to be returned in JSON format. + */ + 'json_routes' => [ + 'api/*', + 'daemon/*', + 'remote/*', + ], ]; diff --git a/routes/api.php b/routes/api.php index 1a7b71f4a..88a9d5ee7 100644 --- a/routes/api.php +++ b/routes/api.php @@ -32,7 +32,10 @@ Route::get('/', 'CoreController@index')->name('api.user'); | Endpoint: /api/user/server/{server} | */ -Route::group(['prefix' => '/server/{server}'], function () { +Route::group([ + 'prefix' => '/server/{server}', + 'middleware' => 'server', +], function () { Route::get('/', 'ServerController@index')->name('api.user.server'); Route::post('/power', 'ServerController@power')->name('api.user.server.power');