From 55bf26e5187423616a8d57084348aec3db7b9f7e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 1 Apr 2017 22:52:27 -0400 Subject: [PATCH 01/23] Fix broken status route spamming logs. --- routes/server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/server.php b/routes/server.php index b666a42cd..cf46054cb 100644 --- a/routes/server.php +++ b/routes/server.php @@ -110,7 +110,7 @@ Route::group(['prefix' => 'tasks'], function () { | */ Route::group(['prefix' => 'ajax'], function () { - Route::get('/status', 'Server\AjaxController@getStatus')->name('server.ajax.status'); + Route::get('/status', 'AjaxController@getStatus')->name('server.ajax.status'); Route::post('/set-primary', 'AjaxController@postSetPrimary')->name('server.ajax.set-primary'); Route::post('/settings/reset-database-password', 'AjaxController@postResetDatabasePassword')->name('server.ajax.reset-database-password'); From 87530cdc01fc1fd2b3a2fc338b1709c6b13fc3e6 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 2 Apr 2017 00:11:52 -0400 Subject: [PATCH 02/23] Initial moves to new API scheme. Implements a better middleware for handling API authentication, as well as cleaner route handling. --- app/Exceptions/Handler.php | 15 +- .../Controllers/API/User/CoreController.php | 36 + .../{API => API_old}/BaseController.php | 0 .../{API => API_old}/LocationController.php | 0 .../{API => API_old}/NodeController.php | 0 .../{API => API_old}/ServerController.php | 0 .../{API => API_old}/ServiceController.php | 0 .../{API => API_old}/User/InfoController.php | 0 .../User/ServerController.php | 0 .../{API => API_old}/UserController.php | 0 app/Http/Kernel.php | 1 + app/Http/Middleware/HMACAuthorization.php | 242 +++++++ app/Models/APIKey.php | 9 + app/Providers/RouteServiceProvider.php | 8 + composer.json | 28 +- composer.lock | 639 +++++++++--------- config/api.php | 220 ------ config/app.php | 6 +- routes/api-admin.php | 34 + routes/api.php | 40 ++ 20 files changed, 706 insertions(+), 572 deletions(-) create mode 100644 app/Http/Controllers/API/User/CoreController.php rename app/Http/Controllers/{API => API_old}/BaseController.php (100%) rename app/Http/Controllers/{API => API_old}/LocationController.php (100%) rename app/Http/Controllers/{API => API_old}/NodeController.php (100%) rename app/Http/Controllers/{API => API_old}/ServerController.php (100%) rename app/Http/Controllers/{API => API_old}/ServiceController.php (100%) rename app/Http/Controllers/{API => API_old}/User/InfoController.php (100%) rename app/Http/Controllers/{API => API_old}/User/ServerController.php (100%) rename app/Http/Controllers/{API => API_old}/UserController.php (100%) create mode 100644 app/Http/Middleware/HMACAuthorization.php delete mode 100644 config/api.php create mode 100644 routes/api-admin.php create mode 100644 routes/api.php diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index bab6ef3e1..b3aefd1cd 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -46,10 +46,19 @@ class Handler extends ExceptionHandler */ public function render($request, Exception $exception) { - if ($request->expectsJson()) { + if ($request->expectsJson() || $request->isJson() || $request->is('api/*', 'remote/*', 'daemon/*')) { + + if (config('app.debug')) { + $report = [ + 'code' => (! $this->isHttpException($exception)) ?: $exception->getStatusCode(), + 'message' => class_basename($exception) . ' in ' . $exception->getFile() . ' on line ' . $exception->getLine(), + ]; + } + $response = response()->json([ - 'error' => ($exception instanceof DisplayException) ? $exception->getMessage() : 'An unhandled error occured while attempting to process this request.', - ], ($this->isHttpException($exception)) ? $exception->getStatusCode() : 500); + 'error' => $exception->getMessage(), + 'exception' => ! isset($report) ?: $report, + ], ($this->isHttpException($exception)) ? $exception->getStatusCode() : 500, [], JSON_UNESCAPED_SLASHES); parent::report($exception); } diff --git a/app/Http/Controllers/API/User/CoreController.php b/app/Http/Controllers/API/User/CoreController.php new file mode 100644 index 000000000..be9ce30ab --- /dev/null +++ b/app/Http/Controllers/API/User/CoreController.php @@ -0,0 +1,36 @@ +. + * + * 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 Illuminate\Http\Request; +use Pterodactyl\Http\Controllers\Controller; + +class CoreController extends Controller +{ + public function index(Request $request) + { + dd($request->user()); + } +} diff --git a/app/Http/Controllers/API/BaseController.php b/app/Http/Controllers/API_old/BaseController.php similarity index 100% rename from app/Http/Controllers/API/BaseController.php rename to app/Http/Controllers/API_old/BaseController.php diff --git a/app/Http/Controllers/API/LocationController.php b/app/Http/Controllers/API_old/LocationController.php similarity index 100% rename from app/Http/Controllers/API/LocationController.php rename to app/Http/Controllers/API_old/LocationController.php diff --git a/app/Http/Controllers/API/NodeController.php b/app/Http/Controllers/API_old/NodeController.php similarity index 100% rename from app/Http/Controllers/API/NodeController.php rename to app/Http/Controllers/API_old/NodeController.php diff --git a/app/Http/Controllers/API/ServerController.php b/app/Http/Controllers/API_old/ServerController.php similarity index 100% rename from app/Http/Controllers/API/ServerController.php rename to app/Http/Controllers/API_old/ServerController.php diff --git a/app/Http/Controllers/API/ServiceController.php b/app/Http/Controllers/API_old/ServiceController.php similarity index 100% rename from app/Http/Controllers/API/ServiceController.php rename to app/Http/Controllers/API_old/ServiceController.php diff --git a/app/Http/Controllers/API/User/InfoController.php b/app/Http/Controllers/API_old/User/InfoController.php similarity index 100% rename from app/Http/Controllers/API/User/InfoController.php rename to app/Http/Controllers/API_old/User/InfoController.php diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API_old/User/ServerController.php similarity index 100% rename from app/Http/Controllers/API/User/ServerController.php rename to app/Http/Controllers/API_old/User/ServerController.php diff --git a/app/Http/Controllers/API/UserController.php b/app/Http/Controllers/API_old/UserController.php similarity index 100% rename from app/Http/Controllers/API/UserController.php rename to app/Http/Controllers/API_old/UserController.php diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 845e14aab..a70895a3e 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -39,6 +39,7 @@ class Kernel extends HttpKernel \Pterodactyl\Http\Middleware\LanguageMiddleware::class, ], 'api' => [ + \Pterodactyl\Http\Middleware\HMACAuthorization::class, 'throttle:60,1', 'bindings', ], diff --git a/app/Http/Middleware/HMACAuthorization.php b/app/Http/Middleware/HMACAuthorization.php new file mode 100644 index 000000000..46f19c363 --- /dev/null +++ b/app/Http/Middleware/HMACAuthorization.php @@ -0,0 +1,242 @@ +. + * + * 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 Auth; +use Crypt; +use Config; +use Closure; +use Response; +use IPTools\IP; +use IPTools\Range; +use Illuminate\Http\Request; +use Pterodactyl\Models\APIKey; +use Pterodactyl\Models\APIPermission; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; // 400 +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; // 403 + +class HMACAuthorization +{ + /** + * The algorithm to use for handling HMAC encryption. + * + * @var string + */ + const HMAC_ALGORITHM = 'sha256'; + + /** + * Stored values from the Authorization header. + * + * @var array + */ + protected $token = []; + + /** + * The eloquent model for the API key. + * + * @var \Pterodactyl\Models\APIKey + */ + protected $key; + + /** + * The illuminate request object. + * + * @var \Illuminate\Http\Request + */ + private $request; + + /** + * Construct class instance. + * + * @return void + */ + public function __construct() + { + Config::set('session.driver', 'array'); + } + + /** + * Handle an incoming request for the API. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @return mixed + */ + public function handle(Request $request, Closure $next) + { + $this->request = $request; + + $this->checkBearer(); + $this->validateRequest(); + $this->validateContents(); + + Auth::loginUsingId($this->key()->user_id); + + return $next($request); + } + + /** + * Checks that the Bearer token is provided and in a valid format. + * + * @return void + * + * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + protected function checkBearer() + { + if (empty($this->request()->bearerToken())) { + throw new BadRequestHttpException('Request was missing required Authorization header.'); + } + + $token = explode('.', $this->request()->bearerToken()); + if (count($token) !== 2) { + throw new BadRequestHttpException('The Authorization header passed was not in a validate public/private key format.'); + } + + $this->token = [ + 'public' => $token[0], + 'hash' => $token[1], + ]; + } + + /** + * Determine if the request contains a valid public API key + * as well as permissions for the resource. + * + * @return void + * + * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + protected function validateRequest() + { + $this->key = APIKey::where('public', $this->public())->first(); + if (! $this->key) { + throw new AccessDeniedHttpException('Unable to identify requester. Authorization token is invalid.'); + } + + if (empty($this->request()->route()->getName())) { + throw new \Exception('Attempting to access un-named route. This should not be possible.'); + } + + $this->validateIPAccess(); + + $query = APIPermission::where('key_id', $this->key()->id) + ->where('permission', $this->request()->route()->getName()); + + if (starts_with($this->request()->route()->getName(), 'api.user')) { + $query->orWhere('permission', 'api.user.*'); + } + + if (! $query->first()) { + throw new AccessDeniedHttpException('You do not have permission to access this resource on the API.'); + } + } + + /** + * Determine if the requesting IP address is allowed to use this API key. + * + * @return bool + * + * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + protected function validateIPAccess() + { + if (! is_null($this->key()->allowed_ips)) { + foreach($this->key()->allowed_ips as $ip) { + if (Range::parse($ip)->contains(new IP($this->request()->ip()))) { + return true; + } + } + + throw new AccessDeniedHttpException('This IP address does not have permission to access the API using these credentials.'); + } + + return true; + } + + /** + * Determine if the HMAC sent in the request matches the one generated + * on the panel side. + * + * @return void + * + * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException + */ + protected function validateContents() + { + if (base64_decode($this->hash()) !== $this->generateSignature()) { + throw new BadRequestHttpException('The HMAC for the request was invalid.'); + } + } + + /** + * Generate a HMAC from the request and known API secret key. + * + * @return string + */ + protected function generateSignature() + { + $content = urldecode($this->request()->url()) . $this->request()->getContent(); + + return hash_hmac(self::HMAC_ALGORITHM, $content, Crypt::decrypt($this->key()->secret), true); + } + + /** + * Return the public key passed in the Authorization header. + * + * @return string + */ + protected function public() { + return $this->token['public']; + } + + /** + * Return the base64'd HMAC sent in the Authorization header. + * + * @return string + */ + protected function hash() { + return $this->token['hash']; + } + + /** + * Return the API Key model. + * + * @return \Pterodactyl\Models\APIKey + */ + protected function key() { + return $this->key; + } + + /** + * Return the Illuminate Request object. + * + * @return \Illuminate\Http\Request + */ + private function request() + { + return $this->request; + } +} diff --git a/app/Models/APIKey.php b/app/Models/APIKey.php index 68e481712..f560fda85 100644 --- a/app/Models/APIKey.php +++ b/app/Models/APIKey.php @@ -42,6 +42,15 @@ class APIKey extends Model */ protected $hidden = ['secret']; + /** + * Cast values to correct type. + * + * @var array + */ + protected $casts = [ + 'allowed_ips' => 'json', + ]; + /** * Fields that are not mass assignable. * diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 0aa015828..d129489af 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -33,6 +33,14 @@ class RouteServiceProvider extends ServiceProvider */ public function map() { + Route::middleware(['api'])->prefix('/api/user') + ->namespace($this->namespace . '\API\User') + ->group(base_path('routes/api.php')); + + Route::middleware(['api'])->prefix('/api/admin') + ->namespace($this->namespace . '\API\Admin') + ->group(base_path('routes/api-admin.php')); + Route::middleware(['web', 'auth', 'csrf']) ->namespace($this->namespace . '\Base') ->group(base_path('routes/base.php')); diff --git a/composer.json b/composer.json index b0fcb26cc..ef76b71b0 100644 --- a/composer.json +++ b/composer.json @@ -12,26 +12,26 @@ ], "require": { "php": ">=7.0.0", - "laravel/framework": "5.4.16", - "laravel/tinker": "1.0.0", + "aws/aws-sdk-php": "3.25.1", "barryvdh/laravel-debugbar": "2.3.2", "doctrine/dbal": "2.5.12", + "edvinaskrucas/settings": "2.0.0", + "fideloper/proxy": "3.3.0", "guzzlehttp/guzzle": "6.2.3", + "igaster/laravel-theme": "1.14.0", + "laracasts/utilities": "2.1.0", + "laravel/framework": "5.4.16", + "laravel/tinker": "1.0.0", + "lord/laroute": "2.4.4", + "mtdowling/cron-expression": "1.2.0", + "nesbot/carbon": "1.22.1", + "nicolaslopezj/searchable": "1.9.5", "pragmarx/google2fa": "1.0.1", - "webpatser/laravel-uuid": "2.0.1", + "predis/predis": "1.1.1", "prologue/alerts": "0.4.1", "s1lentium/iptools": "1.1.0", - "edvinaskrucas/settings": "2.0.0", - "igaster/laravel-theme": "1.14.0", - "nesbot/carbon": "1.22.1", - "mtdowling/cron-expression": "1.2.0", - "dingo/api": "1.0.0-beta8", - "aws/aws-sdk-php": "3.25.1", - "predis/predis": "1.1.1", - "fideloper/proxy": "3.3.0", - "laracasts/utilities": "2.1.0", - "lord/laroute": "2.4.4", - "nicolaslopezj/searchable": "1.9.5" + "spatie/laravel-fractal": "3.5.0", + "webpatser/laravel-uuid": "2.0.1" }, "require-dev": { "fzaninotto/faker": "~1.4", diff --git a/composer.lock b/composer.lock index f4dcae4a8..4ce9d4ee0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "5f54adee49654a63977f6c5593e5e1a8", - "content-hash": "081359d468db67f98d08ff1f304ea712", + "hash": "ae03837be570fb8ebf2a916a50614193", + "content-hash": "d4eb663cbd7d79c85e06d626b64cdbcd", "packages": [ { "name": "aws/aws-sdk-php", @@ -195,136 +195,6 @@ ], "time": "2016-05-05 11:49:03" }, - { - "name": "dingo/api", - "version": "v1.0.0-beta8", - "source": { - "type": "git", - "url": "https://github.com/dingo/api.git", - "reference": "46cffad61942caa094dd876155e503b6819c5095" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dingo/api/zipball/46cffad61942caa094dd876155e503b6819c5095", - "reference": "46cffad61942caa094dd876155e503b6819c5095", - "shasum": "" - }, - "require": { - "dingo/blueprint": "0.2.*", - "illuminate/routing": "^5.1", - "illuminate/support": "^5.1", - "league/fractal": ">=0.12.0", - "php": "^5.5.9 || ^7.0" - }, - "require-dev": { - "illuminate/auth": "^5.1", - "illuminate/cache": "^5.1", - "illuminate/console": "^5.1", - "illuminate/database": "^5.1", - "illuminate/events": "^5.1", - "illuminate/filesystem": "^5.1", - "illuminate/log": "^5.1", - "illuminate/pagination": "^5.1", - "laravel/lumen-framework": "5.1.* || 5.2.*", - "lucadegasperi/oauth2-server-laravel": "5.0.*", - "mockery/mockery": "~0.9", - "phpunit/phpunit": "^4.8 || ^5.0", - "squizlabs/php_codesniffer": "~2.0", - "tymon/jwt-auth": "1.0.*" - }, - "suggest": { - "lucadegasperi/oauth2-server-laravel": "Protect your API with OAuth 2.0.", - "tymon/jwt-auth": "Protect your API with JSON Web Tokens." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "Dingo\\Api\\": "src/" - }, - "files": [ - "src/helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jason Lewis", - "email": "jason.lewis1991@gmail.com" - } - ], - "description": "A RESTful API package for the Laravel and Lumen frameworks.", - "keywords": [ - "api", - "dingo", - "laravel", - "restful" - ], - "time": "2017-02-10 00:56:04" - }, - { - "name": "dingo/blueprint", - "version": "0.2.2", - "source": { - "type": "git", - "url": "https://github.com/dingo/blueprint.git", - "reference": "690bdf0f76b4428fd52835b9d778fb4551333867" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dingo/blueprint/zipball/690bdf0f76b4428fd52835b9d778fb4551333867", - "reference": "690bdf0f76b4428fd52835b9d778fb4551333867", - "shasum": "" - }, - "require": { - "doctrine/annotations": "~1.2", - "illuminate/filesystem": "5.1.* || 5.2.* || 5.3.* || 5.4.*", - "illuminate/support": "5.1.* || 5.2.* || 5.3.* || 5.4.*", - "php": ">=5.5.9", - "phpdocumentor/reflection-docblock": "3.1.*" - }, - "require-dev": { - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.2-dev" - } - }, - "autoload": { - "psr-4": { - "Dingo\\Blueprint\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jason Lewis", - "email": "jason.lewis1991@gmail.com" - } - ], - "description": "API Blueprint documentation generator.", - "keywords": [ - "api", - "blueprint", - "dingo", - "docs", - "laravel" - ], - "time": "2017-02-11 17:28:57" - }, { "name": "dnoegel/php-xdg-base-dir", "version": "0.1", @@ -2157,152 +2027,6 @@ ], "time": "2017-03-13 16:27:32" }, - { - "name": "phpdocumentor/reflection-common", - "version": "1.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2015-12-27 11:43:31" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", - "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0@dev", - "phpdocumentor/type-resolver": "^0.2.0", - "webmozart/assert": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-09-30 07:12:33" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "0.2.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", - "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "time": "2016-11-25 06:54:22" - }, { "name": "pragmarx/google2fa", "version": "v1.0.1", @@ -2766,6 +2490,115 @@ ], "time": "2016-08-21 15:57:09" }, + { + "name": "spatie/fractalistic", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/fractalistic.git", + "reference": "59a2e7dfbd49e58b7de7d5621c1e7365786809f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/fractalistic/zipball/59a2e7dfbd49e58b7de7d5621c1e7365786809f9", + "reference": "59a2e7dfbd49e58b7de7d5621c1e7365786809f9", + "shasum": "" + }, + "require": { + "league/fractal": "^0.14.0|^0.15.0", + "php": "^5.6|^7.0" + }, + "require-dev": { + "illuminate/pagination": "^5.3", + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Fractalistic\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A developer friendly wrapper around Fractal", + "homepage": "https://github.com/spatie/fractalistic", + "keywords": [ + "api", + "fractal", + "fractalistic", + "spatie", + "transform" + ], + "time": "2017-01-19 20:51:03" + }, + { + "name": "spatie/laravel-fractal", + "version": "3.5.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-fractal.git", + "reference": "16689b0ce340bc139ba767f0bf2904e4eab2b254" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-fractal/zipball/16689b0ce340bc139ba767f0bf2904e4eab2b254", + "reference": "16689b0ce340bc139ba767f0bf2904e4eab2b254", + "shasum": "" + }, + "require": { + "illuminate/contracts": "~5.1.0|~5.2.0|~5.3.0|~5.4.0", + "illuminate/support": "~5.1.0|~5.2.0|~5.3.0|~5.4.0", + "php": "^5.6|^7.0", + "spatie/fractalistic": "^1.0" + }, + "require-dev": { + "orchestra/testbench": "~3.2.0|3.3.0|~3.4.0", + "phpunit/phpunit": "^5.7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Fractal\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A Fractal service provider for Laravel and Lumen", + "homepage": "https://github.com/spatie/laravel-fractal", + "keywords": [ + "api", + "fractal", + "laravel", + "laravel-fractal", + "lumen", + "spatie", + "transform" + ], + "time": "2017-02-21 23:17:02" + }, { "name": "swiftmailer/swiftmailer", "version": "v5.4.6", @@ -3755,56 +3588,6 @@ ], "time": "2016-09-01 10:05:43" }, - { - "name": "webmozart/assert", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", - "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2016-11-23 20:04:58" - }, { "name": "webpatser/laravel-uuid", "version": "2.0.1", @@ -4223,6 +4006,152 @@ ], "time": "2017-01-26 22:05:40" }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27 11:43:31" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-09-30 07:12:33" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2016-11-25 06:54:22" + }, { "name": "phpspec/prophecy", "version": "v1.7.0", @@ -5299,13 +5228,61 @@ "description": "Symfony Yaml Component", "homepage": "https://symfony.com", "time": "2017-03-07 16:47:02" + }, + { + "name": "webmozart/assert", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2016-11-23 20:04:58" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "dingo/api": 10 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/config/api.php b/config/api.php deleted file mode 100644 index 2a847e7ac..000000000 --- a/config/api.php +++ /dev/null @@ -1,220 +0,0 @@ - env('API_STANDARDS_TREE', 'x'), - - /* - |-------------------------------------------------------------------------- - | API Subtype - |-------------------------------------------------------------------------- - | - | Your subtype will follow the standards tree you use when used in the - | "Accept" header to negotiate the content type and version. - | - | For example: Accept: application/x.SUBTYPE.v1+json - | - */ - - 'subtype' => env('API_SUBTYPE', ''), - - /* - |-------------------------------------------------------------------------- - | Default API Version - |-------------------------------------------------------------------------- - | - | This is the default version when strict mode is disabled and your API - | is accessed via a web browser. It's also used as the default version - | when generating your APIs documentation. - | - */ - - 'version' => env('API_VERSION', 'v1'), - - /* - |-------------------------------------------------------------------------- - | Default API Prefix - |-------------------------------------------------------------------------- - | - | A default prefix to use for your API routes so you don't have to - | specify it for each group. - | - */ - - 'prefix' => env('API_PREFIX', 'api'), - - /* - |-------------------------------------------------------------------------- - | Default API Domain - |-------------------------------------------------------------------------- - | - | A default domain to use for your API routes so you don't have to - | specify it for each group. - | - */ - - 'domain' => env('API_DOMAIN', null), - - /* - |-------------------------------------------------------------------------- - | Name - |-------------------------------------------------------------------------- - | - | When documenting your API using the API Blueprint syntax you can - | configure a default name to avoid having to manually specify - | one when using the command. - | - */ - - 'name' => env('API_NAME', null), - - /* - |-------------------------------------------------------------------------- - | Conditional Requests - |-------------------------------------------------------------------------- - | - | Globally enable conditional requests so that an ETag header is added to - | any successful response. Subsequent requests will perform a check and - | will return a 304 Not Modified. This can also be enabled or disabled - | on certain groups or routes. - | - */ - - 'conditionalRequest' => env('API_CONDITIONAL_REQUEST', true), - - /* - |-------------------------------------------------------------------------- - | Strict Mode - |-------------------------------------------------------------------------- - | - | Enabling strict mode will require clients to send a valid Accept header - | with every request. This also voids the default API version, meaning - | your API will not be browsable via a web browser. - | - */ - - 'strict' => env('API_STRICT', false), - - /* - |-------------------------------------------------------------------------- - | Debug Mode - |-------------------------------------------------------------------------- - | - | Enabling debug mode will result in error responses caused by thrown - | exceptions to have a "debug" key that will be populated with - | more detailed information on the exception. - | - */ - - 'debug' => env('API_DEBUG', false), - - /* - |-------------------------------------------------------------------------- - | Generic Error Format - |-------------------------------------------------------------------------- - | - | When some HTTP exceptions are not caught and dealt with the API will - | generate a generic error response in the format provided. Any - | keys that aren't replaced with corresponding values will be - | removed from the final response. - | - */ - - 'errorFormat' => [ - 'message' => ':message', - 'errors' => ':errors', - 'code' => ':code', - 'status_code' => ':status_code', - 'debug' => ':debug', - ], - - /* - |-------------------------------------------------------------------------- - | API Middleware - |-------------------------------------------------------------------------- - | - | Middleware that will be applied globally to all API requests. - | - */ - - 'middleware' => [ - - ], - - /* - |-------------------------------------------------------------------------- - | Authentication Providers - |-------------------------------------------------------------------------- - | - | The authentication providers that should be used when attempting to - | authenticate an incoming API request. - | - */ - - 'auth' => [ - 'custom' => 'Pterodactyl\Http\Middleware\APISecretToken', - ], - - /* - |-------------------------------------------------------------------------- - | Throttling / Rate Limiting - |-------------------------------------------------------------------------- - | - | Consumers of your API can be limited to the amount of requests they can - | make. You can create your own throttles or simply change the default - | throttles. - | - */ - - 'throttling' => [ - - ], - - /* - |-------------------------------------------------------------------------- - | Response Transformer - |-------------------------------------------------------------------------- - | - | Responses can be transformed so that they are easier to format. By - | default a Fractal transformer will be used to transform any - | responses prior to formatting. You can easily replace - | this with your own transformer. - | - */ - - 'transformer' => env('API_TRANSFORMER', Dingo\Api\Transformer\Adapter\Fractal::class), - - /* - |-------------------------------------------------------------------------- - | Response Formats - |-------------------------------------------------------------------------- - | - | Responses can be returned in multiple formats by registering different - | response formatters. You can also customize an existing response - | formatter. - | - */ - - 'defaultFormat' => env('API_DEFAULT_FORMAT', 'json'), - - 'formats' => [ - 'json' => Dingo\Api\Http\Response\Format\Json::class, - ], - -]; diff --git a/config/app.php b/config/app.php index 1e575d420..3c3fb772d 100644 --- a/config/app.php +++ b/config/app.php @@ -127,8 +127,6 @@ return [ 'providers' => [ - Dingo\Api\Provider\LaravelServiceProvider::class, - /* * Laravel Framework Service Providers... */ @@ -180,6 +178,7 @@ return [ Fideloper\Proxy\TrustedProxyServiceProvider::class, Laracasts\Utilities\JavaScript\JavaScriptServiceProvider::class, Lord\Laroute\LarouteServiceProvider::class, + Spatie\Fractal\FractalServiceProvider::class, ], @@ -210,11 +209,10 @@ return [ 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Debugbar' => Barryvdh\Debugbar\Facade::class, - 'Dingo' => Dingo\Api\Facade\API::class, - 'DingoRoute'=> Dingo\Api\Facade\Route::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, + 'Fractal' => Spatie\Fractal\FractalFacade::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Google2FA' => PragmaRX\Google2FA\Vendor\Laravel\Facade::class, 'Hash' => Illuminate\Support\Facades\Hash::class, diff --git a/routes/api-admin.php b/routes/api-admin.php new file mode 100644 index 000000000..649828046 --- /dev/null +++ b/routes/api-admin.php @@ -0,0 +1,34 @@ +. + * + * 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. + */ + +Route::get('/', 'CoreController@index')->name('api.admin'); + +/* +|-------------------------------------------------------------------------- +| Location Controller Routes +|-------------------------------------------------------------------------- +| +| Endpoint: /api/admin +| +*/ diff --git a/routes/api.php b/routes/api.php new file mode 100644 index 000000000..1a7b71f4a --- /dev/null +++ b/routes/api.php @@ -0,0 +1,40 @@ +. + * + * 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. + */ + +Route::get('/', 'CoreController@index')->name('api.user'); + +/* +|-------------------------------------------------------------------------- +| Server Controller Routes +|-------------------------------------------------------------------------- +| +| Endpoint: /api/user/server/{server} +| +*/ +Route::group(['prefix' => '/server/{server}'], function () { + Route::get('/', 'ServerController@index')->name('api.user.server'); + + Route::post('/power', 'ServerController@power')->name('api.user.server.power'); + Route::post('/command', 'ServerController@command')->name('api.user.server.command'); +}); From ddb82ac3ca29a03b76856f6d533fbded5415d16e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 2 Apr 2017 00:49:53 -0400 Subject: [PATCH 03/23] Add initial user server transformer for API. --- app/Extensions/NoDataSerializer.php | 43 ++++ .../Controllers/API/User/CoreController.php | 6 +- app/Http/Middleware/APISecretToken.php | 133 ------------ app/Http/Routes/ServerRoutes.php | 192 ------------------ app/Transformers/User/ServerTransformer.php | 50 +++++ config/laravel-fractal.php | 18 ++ 6 files changed, 116 insertions(+), 326 deletions(-) create mode 100644 app/Extensions/NoDataSerializer.php delete mode 100755 app/Http/Middleware/APISecretToken.php delete mode 100644 app/Http/Routes/ServerRoutes.php create mode 100644 app/Transformers/User/ServerTransformer.php create mode 100644 config/laravel-fractal.php diff --git a/app/Extensions/NoDataSerializer.php b/app/Extensions/NoDataSerializer.php new file mode 100644 index 000000000..6db8e633c --- /dev/null +++ b/app/Extensions/NoDataSerializer.php @@ -0,0 +1,43 @@ +. + * + * 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\Extensions; + +use League\Fractal\Serializer\ArraySerializer; + +class NoDataSerializer extends ArraySerializer +{ + /** + * Serialize a collection and don't insert as a member of `data` + * + * @param string $resourceKey + * @param array $data + * + * @return array + */ + public function collection($resourceKey, array $data) + { + return $data; + } +} diff --git a/app/Http/Controllers/API/User/CoreController.php b/app/Http/Controllers/API/User/CoreController.php index be9ce30ab..e0e0cedea 100644 --- a/app/Http/Controllers/API/User/CoreController.php +++ b/app/Http/Controllers/API/User/CoreController.php @@ -24,13 +24,17 @@ namespace Pterodactyl\Http\Controllers\API\User; +use Fractal; use Illuminate\Http\Request; use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Transformers\User\ServerTransformer; class CoreController extends Controller { public function index(Request $request) { - dd($request->user()); + $servers = $request->user()->access('service', 'node', 'allocation', 'option')->get(); + + return Fractal::collection($servers)->transformWith(new ServerTransformer)->toArray(); } } diff --git a/app/Http/Middleware/APISecretToken.php b/app/Http/Middleware/APISecretToken.php deleted file mode 100755 index 25bf891ba..000000000 --- a/app/Http/Middleware/APISecretToken.php +++ /dev/null @@ -1,133 +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\Middleware; - -use Auth; -use Crypt; -use Config; -use IPTools\IP; -use IPTools\Range; -use Dingo\Api\Routing\Route; -use Illuminate\Http\Request; -use Pterodactyl\Models\User; -use Pterodactyl\Models\APIKey; -use Pterodactyl\Models\APIPermission; -use Pterodactyl\Services\APILogService; -use Dingo\Api\Auth\Provider\Authorization; -use Symfony\Component\HttpKernel\Exception\HttpException; // 400 -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; // 401 -use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; // 403 -use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; //500 - -class APISecretToken extends Authorization -{ - protected $algo = 'sha256'; - - protected $permissionAllowed = false; - - protected $url = ''; - - public function __construct() - { - Config::set('session.driver', 'array'); - } - - public function getAuthorizationMethod() - { - return 'Authorization'; - } - - public function authenticate(Request $request, Route $route) - { - if (! $request->bearerToken() || empty($request->bearerToken())) { - APILogService::log($request, 'The authentication header was missing or malformed.'); - throw new UnauthorizedHttpException('The authentication header was missing or malformed.'); - } - - list($public, $hashed) = explode('.', $request->bearerToken()); - - $key = APIKey::where('public', $public)->first(); - if (! $key) { - APILogService::log($request, 'Invalid API Key.'); - throw new AccessDeniedHttpException('Invalid API Key.'); - } - - // Check for Resource Permissions - if (! empty($request->route()->getName())) { - if (! is_null($key->allowed_ips)) { - $inRange = false; - foreach (json_decode($key->allowed_ips) as $ip) { - if (Range::parse($ip)->contains(new IP($request->ip()))) { - $inRange = true; - break; - } - } - if (! $inRange) { - APILogService::log($request, 'This IP address <' . $request->ip() . '> does not have permission to use this API key.'); - throw new AccessDeniedHttpException('This IP address <' . $request->ip() . '> does not have permission to use this API key.'); - } - } - - $permission = APIPermission::where('key_id', $key->id)->where('permission', $request->route()->getName()); - - // Suport Wildcards - if (starts_with($request->route()->getName(), 'api.user')) { - $permission->orWhere('permission', 'api.user.*'); - } elseif (starts_with($request->route()->getName(), 'api.admin')) { - $permission->orWhere('permission', 'api.admin.*'); - } - - if (! $permission->first()) { - APILogService::log($request, 'You do not have permission to access this resource. This API Key requires the ' . $request->route()->getName() . ' permission node.'); - throw new AccessDeniedHttpException('You do not have permission to access this resource. This API Key requires the ' . $request->route()->getName() . ' permission node.'); - } - } - - try { - $decrypted = Crypt::decrypt($key->secret); - } catch (\Illuminate\Contracts\Encryption\DecryptException $ex) { - APILogService::log($request, 'There was an error while attempting to check your secret key.'); - throw new HttpException('There was an error while attempting to check your secret key.'); - } - - $this->url = urldecode($request->fullUrl()); - if ($this->_generateHMAC($request->getContent(), $decrypted) !== base64_decode($hashed)) { - APILogService::log($request, 'The hashed body was not valid. Potential modification of contents in route.'); - throw new BadRequestHttpException('The hashed body was not valid. Potential modification of contents in route.'); - } - - // Log the Route Access - APILogService::log($request, null, true); - - return Auth::loginUsingId($key->user_id); - } - - protected function _generateHMAC($body, $key) - { - $data = $this->url . $body; - - return hash_hmac($this->algo, $data, $key, true); - } -} diff --git a/app/Http/Routes/ServerRoutes.php b/app/Http/Routes/ServerRoutes.php deleted file mode 100644 index b03a530d6..000000000 --- a/app/Http/Routes/ServerRoutes.php +++ /dev/null @@ -1,192 +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\Routes; - -use Illuminate\Routing\Router; - -class ServerRoutes -{ - /** - * Server routes. - * - * @param \Illuminate\Routing\Router $router - * @return void - */ - public function map(Router $router) - { - // Returns Server Status - $router->get('/server/{server}/ajax/status', [ - 'middleware' => ['auth', 'csrf'], - 'as' => 'server.ajax.status', - 'uses' => 'Server\AjaxController@getStatus', - ]); - - $router->group([ - 'prefix' => 'server/{server}', - 'middleware' => [ - 'auth', - 'server', - 'csrf', - ], - ], function ($server) use ($router) { - - // Index View for Server - $router->get('/', [ - 'as' => 'server.index', - 'uses' => 'Server\ServerController@getIndex', - ]); - - $router->get('/settings/databases', [ - 'as' => 'server.settings.databases', - 'uses' => 'Server\ServerController@getDatabases', - ]); - - $router->get('/settings/sftp', [ - 'as' => 'server.settings.sftp', - 'uses' => 'Server\ServerController@getSFTP', - ]); - - $router->post('/settings/sftp', [ - 'uses' => 'Server\ServerController@postSettingsSFTP', - ]); - - $router->get('/settings/startup', [ - 'as' => 'server.settings.startup', - 'uses' => 'Server\ServerController@getStartup', - ]); - - $router->post('/settings/startup', [ - 'uses' => 'Server\ServerController@postSettingsStartup', - ]); - - $router->get('/settings/allocation', [ - 'as' => 'server.settings.allocation', - 'uses' => 'Server\ServerController@getAllocation', - ]); - - // File Manager Routes - $router->get('/files', [ - 'as' => 'server.files.index', - 'uses' => 'Server\ServerController@getFiles', - ]); - - $router->get('/files/edit/{file}', [ - 'as' => 'server.files.edit', - 'uses' => 'Server\ServerController@getEditFile', - ])->where('file', '.*'); - - $router->get('/files/download/{file}', [ - 'as' => 'server.files.download', - 'uses' => 'Server\ServerController@getDownloadFile', - ])->where('file', '.*'); - - $router->get('/files/add', [ - 'as' => 'server.files.add', - 'uses' => 'Server\ServerController@getAddFile', - ]); - - $router->post('files/directory-list', [ - 'as' => 'server.files.directory-list', - 'uses' => 'Server\AjaxController@postDirectoryList', - ]); - - $router->post('files/save', [ - 'as' => 'server.files.save', - 'uses' => 'Server\AjaxController@postSaveFile', - ]); - - // Sub-User Routes - $router->get('users', [ - 'as' => 'server.subusers', - 'uses' => 'Server\SubuserController@getIndex', - ]); - - $router->get('users/new', [ - 'as' => 'server.subusers.new', - 'uses' => 'Server\SubuserController@getNew', - ]); - - $router->post('users/new', [ - 'uses' => 'Server\SubuserController@postNew', - ]); - - $router->get('users/view/{id}', [ - 'as' => 'server.subusers.view', - 'uses' => 'Server\SubuserController@getView', - ]); - - $router->post('users/view/{id}', [ - 'uses' => 'Server\SubuserController@postView', - ]); - - $router->delete('users/delete/{id}', [ - 'as' => 'server.subusers.delete', - 'uses' => 'Server\SubuserController@deleteSubuser', - ]); - - $router->get('tasks/', [ - 'as' => 'server.tasks', - 'uses' => 'Server\TaskController@getIndex', - ]); - - $router->get('tasks/view/{id}', [ - 'as' => 'server.tasks.view', - 'uses' => 'Server\TaskController@getView', - ]); - - $router->get('tasks/new', [ - 'as' => 'server.tasks.new', - 'uses' => 'Server\TaskController@getNew', - ]); - - $router->post('tasks/new', [ - 'uses' => 'Server\TaskController@postNew', - ]); - - $router->delete('tasks/delete/{id}', [ - 'as' => 'server.tasks.delete', - 'uses' => 'Server\TaskController@deleteTask', - ]); - - $router->post('tasks/toggle/{id}', [ - 'as' => 'server.tasks.toggle', - 'uses' => 'Server\TaskController@toggleTask', - ]); - - // Assorted AJAX Routes - $router->group(['prefix' => 'ajax'], function ($server) use ($router) { - // Sets the Default Connection for the Server - $router->post('set-primary', [ - 'uses' => 'Server\AjaxController@postSetPrimary', - ]); - - $router->post('settings/reset-database-password', [ - 'as' => 'server.ajax.reset-database-password', - 'uses' => 'Server\AjaxController@postResetDatabasePassword', - ]); - }); - }); - } -} diff --git a/app/Transformers/User/ServerTransformer.php b/app/Transformers/User/ServerTransformer.php new file mode 100644 index 000000000..2dba2adc2 --- /dev/null +++ b/app/Transformers/User/ServerTransformer.php @@ -0,0 +1,50 @@ +. + * + * 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 Pterodactyl\Models\Server; +use League\Fractal\TransformerAbstract; + +class ServerTransformer extends TransformerAbstract +{ + /** + * Return a generic transformed server array. + * + * @return array + */ + public function transform(Server $server) + { + return [ + 'short' => $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/config/laravel-fractal.php b/config/laravel-fractal.php new file mode 100644 index 000000000..9406421d8 --- /dev/null +++ b/config/laravel-fractal.php @@ -0,0 +1,18 @@ + Pterodactyl\Extensions\NoDataSerializer::class, + +]; From 97773300ed05fcb0214da407e9824372c10e47c4 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 2 Apr 2017 13:19:39 -0400 Subject: [PATCH 04/23] Better middleware for routes, cleaned up API, removed old API calls New API routes for Server allow specifying which fractal objects to load into the request, thus making it possible to fine-tune what data is returned. --- app/Exceptions/Handler.php | 4 +- .../User/ServerController.php} | 41 ++-- .../Controllers/API_old/NodeController.php | 172 ------------- .../Controllers/API_old/ServerController.php | 231 ------------------ .../API_old/User/ServerController.php | 132 ---------- .../Controllers/API_old/UserController.php | 151 ------------ app/Http/Middleware/CheckServer.php | 77 +++++- app/Http/Middleware/HMACAuthorization.php | 2 +- .../User/AllocationTransformer.php} | 40 ++- .../User/OverviewTransformer.php} | 33 ++- app/Transformers/User/ServerTransformer.php | 60 ++++- app/Transformers/User/StatsTransformer.php | 62 +++++ .../User/SubuserTransformer.php} | 27 +- config/pterodactyl.php | 14 ++ routes/api.php | 5 +- 15 files changed, 304 insertions(+), 747 deletions(-) rename app/Http/Controllers/{API_old/User/InfoController.php => API/User/ServerController.php} (62%) delete mode 100755 app/Http/Controllers/API_old/NodeController.php delete mode 100755 app/Http/Controllers/API_old/ServerController.php delete mode 100644 app/Http/Controllers/API_old/User/ServerController.php delete mode 100755 app/Http/Controllers/API_old/UserController.php rename app/{Http/Controllers/API_old/BaseController.php => Transformers/User/AllocationTransformer.php} (57%) mode change 100755 => 100644 rename app/{Http/Controllers/API_old/ServiceController.php => Transformers/User/OverviewTransformer.php} (63%) mode change 100755 => 100644 create mode 100644 app/Transformers/User/StatsTransformer.php rename app/{Http/Controllers/API_old/LocationController.php => Transformers/User/SubuserTransformer.php} (68%) mode change 100755 => 100644 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'); From c071efd008fb99202a1c38333e917614443ee0e8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 2 Apr 2017 15:52:53 -0400 Subject: [PATCH 05/23] Finish API routes for users. --- .../Controllers/API/User/CoreController.php | 6 ++++ .../Controllers/API/User/ServerController.php | 35 +++++++++++++++++++ app/Http/Middleware/HMACAuthorization.php | 2 ++ app/Repositories/Daemon/CommandRepository.php | 17 ++++----- app/Repositories/Daemon/PowerRepository.php | 17 ++++----- 5 files changed, 61 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/API/User/CoreController.php b/app/Http/Controllers/API/User/CoreController.php index e0e0cedea..dfc119d50 100644 --- a/app/Http/Controllers/API/User/CoreController.php +++ b/app/Http/Controllers/API/User/CoreController.php @@ -31,6 +31,12 @@ use Pterodactyl\Transformers\User\ServerTransformer; class CoreController extends Controller { + /** + * Controller to handle base user request for all of their servers. + * + * @param \Illuminate\Http\Request $request + * @return array + */ public function index(Request $request) { $servers = $request->user()->access('service', 'node', 'allocation', 'option')->get(); diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index b868cdb0e..15f455ce1 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -27,11 +27,20 @@ namespace Pterodactyl\Http\Controllers\API\User; use Fractal; use Illuminate\Http\Request; use Pterodactyl\Models\Server; +use GuzzleHttp\Exception\ConnectException; use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Transformers\User\ServerTransformer; +use Pterodactyl\Repositories\Daemon\PowerRepository; class ServerController extends Controller { + /** + * Controller to handle base request for individual server information. + * + * @param \Illuminate\Http\Request $request + * @param string $uuid + * @return array + */ public function index(Request $request, $uuid) { $server = Server::byUuid($uuid); @@ -46,13 +55,39 @@ class ServerController extends Controller return $fractal->transformWith(new ServerTransformer)->toArray(); } + /** + * Controller to handle request for server power toggle. + * + * @param \Illuminate\Http\Request $request + * @param string $uuid + * @return \Illuminate\Http\Response + */ public function power(Request $request, $uuid) { + $server = Server::byUuid($uuid); + $request->user()->can('power-' . $request->input('action'), $server); + $repo = new PowerRepository($server); + $repo->do($request->input('action')); + + return response('', 204)->header('Content-Type', 'application/json'); } + /** + * Controller to handle base request for individual server information. + * + * @param \Illuminate\Http\Request $request + * @param string $uuid + * @return \Illuminate\Http\Response + */ public function command(Request $request, $uuid) { + $server = Server::byUuid($uuid); + $request->user()->can('send-command', $server); + $repo = new CommandRepository($server); + $repo->send($request->input('command')); + + return response('', 204)->header('Content-Type', 'application/json'); } } diff --git a/app/Http/Middleware/HMACAuthorization.php b/app/Http/Middleware/HMACAuthorization.php index 75b6a0f79..6eac236a2 100644 --- a/app/Http/Middleware/HMACAuthorization.php +++ b/app/Http/Middleware/HMACAuthorization.php @@ -29,6 +29,7 @@ use Crypt; use Config; use Closure; use Response; +use Debugbar; use IPTools\IP; use IPTools\Range; use Illuminate\Http\Request; @@ -74,6 +75,7 @@ class HMACAuthorization */ public function __construct() { + Debugbar::disable(); Config::set('session.driver', 'array'); } diff --git a/app/Repositories/Daemon/CommandRepository.php b/app/Repositories/Daemon/CommandRepository.php index 51afc6105..b7149b453 100644 --- a/app/Repositories/Daemon/CommandRepository.php +++ b/app/Repositories/Daemon/CommandRepository.php @@ -25,6 +25,7 @@ namespace Pterodactyl\Repositories\Daemon; use Pterodactyl\Models; +use GuzzleHttp\Exception\ConnectException; use Pterodactyl\Exceptions\DisplayException; class CommandRepository @@ -60,20 +61,20 @@ class CommandRepository { // We don't use the user's specific daemon secret here since we // are assuming that a call to this function has been validated. - // Additionally not all calls to this will be from a logged in user. - // (e.g. task queue or API) try { - $response = $this->server->node->guzzleClient([ - 'X-Access-Token' => $this->server->daemonSecret, - 'X-Access-Server' => $this->server->uuid, - ])->request('POST', '/server/command', ['json' => ['command' => $command]]); + $response = $this->server->guzzleClient()->request('PUT', '/server/command', [ + 'http_errors' => false, + 'json' => [ + 'command' => $command, + ], + ]); if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) { - throw new DisplayException('Command sending responded with a non-200 error code.'); + throw new DisplayException('Command sending responded with a non-200 error code (HTTP/' . $response->getStatusCode() . ').'); } return $response->getBody(); - } catch (\Exception $ex) { + } catch (ConnectException $ex) { throw $ex; } } diff --git a/app/Repositories/Daemon/PowerRepository.php b/app/Repositories/Daemon/PowerRepository.php index e4b4cbb18..bc5696986 100644 --- a/app/Repositories/Daemon/PowerRepository.php +++ b/app/Repositories/Daemon/PowerRepository.php @@ -25,6 +25,7 @@ namespace Pterodactyl\Repositories\Daemon; use Pterodactyl\Models; +use GuzzleHttp\Exception\ConnectException; use Pterodactyl\Exceptions\DisplayException; class PowerRepository @@ -60,20 +61,20 @@ class PowerRepository { // We don't use the user's specific daemon secret here since we // are assuming that a call to this function has been validated. - // Additionally not all calls to this will be from a logged in user. - // (e.g. task queue or API) try { - $response = $this->server->node->guzzleClient([ - 'X-Access-Token' => $this->server->daemonSecret, - 'X-Access-Server' => $this->server->uuid, - ])->request('PUT', '/server/power', ['json' => ['action' => $action]]); + $response = $this->server->guzzleClient()->request('PUT', '/server/power', [ + 'http_errors' => false, + 'json' => [ + 'action' => $action, + ], + ]); if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) { - throw new DisplayException('Power status responded with a non-200 error code.'); + throw new DisplayException('Power toggle endpoint responded with a non-200 error code (HTTP/' . $response->getStatusCode() . ').'); } return $response->getBody(); - } catch (\Exception $ex) { + } catch (ConnectException $ex) { throw $ex; } } From 65630bdcce801125cb15884ed649f2b280df2432 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 2 Apr 2017 16:51:56 -0400 Subject: [PATCH 06/23] Move API to use JSON:API standards and fractal serializer Makes the data slightly more complex, but forces a standard and can always be changed down the road simply by changing the default serializer. --- .../API/Admin/ServerController.php | 77 +++++++++++++++++ .../Controllers/API/User/CoreController.php | 7 +- .../Controllers/API/User/ServerController.php | 8 +- .../Admin/AllocationTransformer.php} | 16 ++-- app/Transformers/Admin/ServerTransformer.php | 82 +++++++++++++++++++ app/Transformers/Admin/SubuserTransformer.php | 50 +++++++++++ app/Transformers/Admin/UserTransformer.php | 41 ++++++++++ .../User/AllocationTransformer.php | 1 + app/Transformers/User/OverviewTransformer.php | 2 +- app/Transformers/User/ServerTransformer.php | 8 +- app/Transformers/User/StatsTransformer.php | 1 + app/Transformers/User/SubuserTransformer.php | 1 + config/laravel-fractal.php | 2 +- ..._163232_DropDeletedAtColumnFromServers.php | 32 ++++++++ routes/api-admin.php | 9 +- 15 files changed, 315 insertions(+), 22 deletions(-) create mode 100644 app/Http/Controllers/API/Admin/ServerController.php rename app/{Extensions/NoDataSerializer.php => Transformers/Admin/AllocationTransformer.php} (78%) create mode 100644 app/Transformers/Admin/ServerTransformer.php create mode 100644 app/Transformers/Admin/SubuserTransformer.php create mode 100644 app/Transformers/Admin/UserTransformer.php create mode 100644 database/migrations/2017_04_02_163232_DropDeletedAtColumnFromServers.php diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php new file mode 100644 index 000000000..651f70787 --- /dev/null +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -0,0 +1,77 @@ +. + * + * 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\Admin; + +use Fractal; +use Illuminate\Http\Request; +use Pterodactyl\Models\Server; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Transformers\Admin\ServerTransformer; +use League\Fractal\Pagination\IlluminatePaginatorAdapter; + +class ServerController extends Controller +{ + /** + * Controller to handle returning all servers on the system. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function index(Request $request) + { + $servers = Server::paginate(20); + + return Fractal::create() + ->collection($servers) + ->transformWith(new ServerTransformer) + ->paginateWith(new IlluminatePaginatorAdapter($servers)) + ->withResourceName('server') + ->toArray(); + } + + /** + * Controller to handle returning information on a single server. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function view(Request $request, $id) + { + $server = Server::findOrFail($id); + + $fractal = Fractal::create()->item($server); + + if ($request->input('include')) { + $fractal->parseIncludes(collect(explode(',', $request->input('include')))->intersect([ + 'allocations', 'subusers', 'user', + 'pack', 'service', 'option', + ])->toArray()); + } + + return $fractal->transformWith(new ServerTransformer) + ->withResourceName('server') + ->toArray(); + } +} diff --git a/app/Http/Controllers/API/User/CoreController.php b/app/Http/Controllers/API/User/CoreController.php index dfc119d50..b036c0db7 100644 --- a/app/Http/Controllers/API/User/CoreController.php +++ b/app/Http/Controllers/API/User/CoreController.php @@ -27,7 +27,7 @@ namespace Pterodactyl\Http\Controllers\API\User; use Fractal; use Illuminate\Http\Request; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Transformers\User\ServerTransformer; +use Pterodactyl\Transformers\User\OverviewTransformer; class CoreController extends Controller { @@ -41,6 +41,9 @@ class CoreController extends Controller { $servers = $request->user()->access('service', 'node', 'allocation', 'option')->get(); - return Fractal::collection($servers)->transformWith(new ServerTransformer)->toArray(); + return Fractal::collection($servers) + ->transformWith(new OverviewTransformer) + ->withResourceName('server') + ->toArray(); } } diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index 15f455ce1..6db58cb4b 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -46,13 +46,15 @@ class ServerController extends Controller $server = Server::byUuid($uuid); $fractal = Fractal::create()->item($server); - if ($request->input('with')) { - $fractal->parseIncludes(collect(explode(',', $request->input('with')))->intersect([ + if ($request->input('include')) { + $fractal->parseIncludes(collect(explode(',', $request->input('include')))->intersect([ 'allocations', 'subusers', 'stats', ])->toArray()); } - return $fractal->transformWith(new ServerTransformer)->toArray(); + return $fractal->transformWith(new ServerTransformer) + ->withResourceName('server') + ->toArray(); } /** diff --git a/app/Extensions/NoDataSerializer.php b/app/Transformers/Admin/AllocationTransformer.php similarity index 78% rename from app/Extensions/NoDataSerializer.php rename to app/Transformers/Admin/AllocationTransformer.php index 6db8e633c..d59d29a25 100644 --- a/app/Extensions/NoDataSerializer.php +++ b/app/Transformers/Admin/AllocationTransformer.php @@ -22,22 +22,20 @@ * SOFTWARE. */ -namespace Pterodactyl\Extensions; +namespace Pterodactyl\Transformers\Admin; -use League\Fractal\Serializer\ArraySerializer; +use Pterodactyl\Models\Allocation; +use League\Fractal\TransformerAbstract; -class NoDataSerializer extends ArraySerializer +class AllocationTransformer extends TransformerAbstract { /** - * Serialize a collection and don't insert as a member of `data` - * - * @param string $resourceKey - * @param array $data + * Return a generic transformed server array. * * @return array */ - public function collection($resourceKey, array $data) + public function transform(Allocation $allocation) { - return $data; + return $allocation->toArray(); } } diff --git a/app/Transformers/Admin/ServerTransformer.php b/app/Transformers/Admin/ServerTransformer.php new file mode 100644 index 000000000..875e2261c --- /dev/null +++ b/app/Transformers/Admin/ServerTransformer.php @@ -0,0 +1,82 @@ +. + * + * 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\Admin; + +use Pterodactyl\Models\Server; +use League\Fractal\TransformerAbstract; + +class ServerTransformer extends TransformerAbstract +{ + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = [ + 'allocations', + 'user', + 'subusers', + ]; + + /** + * Return a generic transformed server array. + * + * @return array + */ + public function transform(Server $server) + { + return $server->toArray(); + } + + /** + * Return a generic array of allocations for this server. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeAllocations(Server $server) + { + return $this->collection($server->allocations, new AllocationTransformer, 'allocation'); + } + + /** + * Return a generic array of data about subusers for this server. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeSubusers(Server $server) + { + return $this->collection($server->subusers, new SubuserTransformer, 'subuser'); + } + + /** + * Return a generic array of data about subusers for this server. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeUser(Server $server) + { + return $this->item($server->user, new UserTransformer, 'user'); + } +} diff --git a/app/Transformers/Admin/SubuserTransformer.php b/app/Transformers/Admin/SubuserTransformer.php new file mode 100644 index 000000000..1c76dcc99 --- /dev/null +++ b/app/Transformers/Admin/SubuserTransformer.php @@ -0,0 +1,50 @@ +. + * + * 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\Admin; + +use Pterodactyl\Models\Subuser; +use Pterodactyl\Models\Permission; +use League\Fractal\TransformerAbstract; + +class SubuserTransformer extends TransformerAbstract +{ + /** + * Return a generic transformed subuser array. + * + * @return array + */ + public function transform(Subuser $subuser) + { + return [ + 'id' => $subuser->id, + 'username' => $subuser->user->username, + 'email' => $subuser->user->email, + '2fa' => (bool) $subuser->user->use_totp, + 'permissions' => $subuser->permissions->pluck('permission'), + 'created_at' => $subuser->created_at, + 'updated_at' => $subuser->updated_at, + ]; + } +} diff --git a/app/Transformers/Admin/UserTransformer.php b/app/Transformers/Admin/UserTransformer.php new file mode 100644 index 000000000..75dd950a3 --- /dev/null +++ b/app/Transformers/Admin/UserTransformer.php @@ -0,0 +1,41 @@ +. + * + * 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\Admin; + +use Pterodactyl\Models\User; +use League\Fractal\TransformerAbstract; + +class UserTransformer extends TransformerAbstract +{ + /** + * Return a generic transformed subuser array. + * + * @return array + */ + public function transform(User $user) + { + return $user->toArray(); + } +} diff --git a/app/Transformers/User/AllocationTransformer.php b/app/Transformers/User/AllocationTransformer.php index 2e58574e6..0fd0be453 100644 --- a/app/Transformers/User/AllocationTransformer.php +++ b/app/Transformers/User/AllocationTransformer.php @@ -55,6 +55,7 @@ class AllocationTransformer extends TransformerAbstract public function transform(Allocation $allocation) { return [ + 'id' => $allocation->id, 'ip' => $allocation->alias, 'port' => $allocation->port, 'default' => ($allocation->id === $this->server->allocation_id), diff --git a/app/Transformers/User/OverviewTransformer.php b/app/Transformers/User/OverviewTransformer.php index 57c5b8d6c..c8e1db9ed 100644 --- a/app/Transformers/User/OverviewTransformer.php +++ b/app/Transformers/User/OverviewTransformer.php @@ -37,7 +37,7 @@ class OverviewTransformer extends TransformerAbstract public function transform(Server $server) { return [ - 'uuidShort' => $server->uuidShort, + 'id' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, 'node' => $server->node->name, diff --git a/app/Transformers/User/ServerTransformer.php b/app/Transformers/User/ServerTransformer.php index 063718863..4e5aacb56 100644 --- a/app/Transformers/User/ServerTransformer.php +++ b/app/Transformers/User/ServerTransformer.php @@ -48,7 +48,7 @@ class ServerTransformer extends TransformerAbstract public function transform(Server $server) { return [ - 'uuidShort' => $server->uuidShort, + 'id' => $server->uuidShort, 'uuid' => $server->uuid, 'name' => $server->name, 'description' => $server->description, @@ -73,7 +73,7 @@ class ServerTransformer extends TransformerAbstract { $allocations = $server->allocations; - return $this->collection($allocations, new AllocationTransformer($server)); + return $this->collection($allocations, new AllocationTransformer($server), 'allocation'); } /** @@ -85,7 +85,7 @@ class ServerTransformer extends TransformerAbstract { $server->load('subusers.permissions', 'subusers.user'); - return $this->collection($server->subusers, new SubuserTransformer); + return $this->collection($server->subusers, new SubuserTransformer, 'subuser'); } /** @@ -95,6 +95,6 @@ class ServerTransformer extends TransformerAbstract */ public function includeStats(Server $server) { - return $this->item($server->guzzleClient(), new StatsTransformer); + return $this->item($server->guzzleClient(), new StatsTransformer, 'stat'); } } diff --git a/app/Transformers/User/StatsTransformer.php b/app/Transformers/User/StatsTransformer.php index 15bfa699c..6b08ea8a5 100644 --- a/app/Transformers/User/StatsTransformer.php +++ b/app/Transformers/User/StatsTransformer.php @@ -49,6 +49,7 @@ class StatsTransformer extends TransformerAbstract $json = json_decode($res->getBody()); return [ + 'id' => 1, 'status' => $json->status, 'resources' => $json->proc, ]; diff --git a/app/Transformers/User/SubuserTransformer.php b/app/Transformers/User/SubuserTransformer.php index 0793eed3b..e1a122f1f 100644 --- a/app/Transformers/User/SubuserTransformer.php +++ b/app/Transformers/User/SubuserTransformer.php @@ -38,6 +38,7 @@ class SubuserTransformer extends TransformerAbstract public function transform(Subuser $subuser) { return [ + 'id' => $subuser->id, 'username' => $subuser->user->username, 'email' => $subuser->user->email, '2fa' => (bool) $subuser->user->use_totp, diff --git a/config/laravel-fractal.php b/config/laravel-fractal.php index 9406421d8..32ced203e 100644 --- a/config/laravel-fractal.php +++ b/config/laravel-fractal.php @@ -13,6 +13,6 @@ return [ | */ - 'default_serializer' => Pterodactyl\Extensions\NoDataSerializer::class, + 'default_serializer' => League\Fractal\Serializer\JsonApiSerializer::class, ]; diff --git a/database/migrations/2017_04_02_163232_DropDeletedAtColumnFromServers.php b/database/migrations/2017_04_02_163232_DropDeletedAtColumnFromServers.php new file mode 100644 index 000000000..ccd318654 --- /dev/null +++ b/database/migrations/2017_04_02_163232_DropDeletedAtColumnFromServers.php @@ -0,0 +1,32 @@ +dropColumn('deleted_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('servers', function (Blueprint $table) { + $table->timestamp('deleted_at')->nullable(); + }); + } +} diff --git a/routes/api-admin.php b/routes/api-admin.php index 649828046..7a0992fc1 100644 --- a/routes/api-admin.php +++ b/routes/api-admin.php @@ -24,11 +24,16 @@ Route::get('/', 'CoreController@index')->name('api.admin'); + /* |-------------------------------------------------------------------------- -| Location Controller Routes +| Server Controller Routes |-------------------------------------------------------------------------- | -| Endpoint: /api/admin +| Endpoint: /api/admin/servers | */ +Route::group(['prefix' => '/servers'], function () { + Route::get('/', 'ServerController@index')->name('api.admin.servers.list'); + Route::get('/{id}', 'ServerController@view')->name('api.admin.servers.view'); +}); From 51204b8d9d2ef9d8289ddc6ad4fbcfa4a57ea47f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 7 Apr 2017 20:28:58 -0400 Subject: [PATCH 07/23] Add all of the potential transformers that might be needed for now. --- .../API/Admin/ServerController.php | 5 +- .../Controllers/API/User/ServerController.php | 4 +- app/Models/Server.php | 10 ++ .../Admin/AllocationTransformer.php | 45 ++++++++- .../Admin/LocationTransformer.php | 71 ++++++++++++++ app/Transformers/Admin/NodeTransformer.php | 82 ++++++++++++++++ app/Transformers/Admin/OptionTransformer.php | 93 +++++++++++++++++++ app/Transformers/Admin/PackTransformer.php | 75 +++++++++++++++ app/Transformers/Admin/ServerTransformer.php | 68 +++++++++++++- .../Admin/ServerVariableTransformer.php | 58 ++++++++++++ app/Transformers/Admin/ServiceTransformer.php | 82 ++++++++++++++++ .../Admin/ServiceVariableTransformer.php | 58 ++++++++++++ 12 files changed, 642 insertions(+), 9 deletions(-) create mode 100644 app/Transformers/Admin/LocationTransformer.php create mode 100644 app/Transformers/Admin/NodeTransformer.php create mode 100644 app/Transformers/Admin/OptionTransformer.php create mode 100644 app/Transformers/Admin/PackTransformer.php create mode 100644 app/Transformers/Admin/ServerVariableTransformer.php create mode 100644 app/Transformers/Admin/ServiceTransformer.php create mode 100644 app/Transformers/Admin/ServiceVariableTransformer.php diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php index 651f70787..716d39dca 100644 --- a/app/Http/Controllers/API/Admin/ServerController.php +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -64,10 +64,7 @@ class ServerController extends Controller $fractal = Fractal::create()->item($server); if ($request->input('include')) { - $fractal->parseIncludes(collect(explode(',', $request->input('include')))->intersect([ - 'allocations', 'subusers', 'user', - 'pack', 'service', 'option', - ])->toArray()); + $fractal->parseIncludes(explode(',', $request->input('include'))); } return $fractal->transformWith(new ServerTransformer) diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index 6db58cb4b..36fdc0fac 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -47,9 +47,7 @@ class ServerController extends Controller $fractal = Fractal::create()->item($server); if ($request->input('include')) { - $fractal->parseIncludes(collect(explode(',', $request->input('include')))->intersect([ - 'allocations', 'subusers', 'stats', - ])->toArray()); + $fractal->parseIncludes(explode(',', $request->input('include'))); } return $fractal->transformWith(new ServerTransformer) diff --git a/app/Models/Server.php b/app/Models/Server.php index 633c1a542..ee2e1a89e 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -313,4 +313,14 @@ class Server extends Model { return $this->hasMany(Database::class); } + + /** + * Gets the location of the server. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function location() + { + return $this->node->location(); + } } diff --git a/app/Transformers/Admin/AllocationTransformer.php b/app/Transformers/Admin/AllocationTransformer.php index d59d29a25..c7fa85724 100644 --- a/app/Transformers/Admin/AllocationTransformer.php +++ b/app/Transformers/Admin/AllocationTransformer.php @@ -30,12 +30,55 @@ use League\Fractal\TransformerAbstract; class AllocationTransformer extends TransformerAbstract { /** - * Return a generic transformed server array. + * The filter to be applied to this transformer. + * + * @var bool|string + */ + protected $filter; + + /** + * Transformer constructor. + * + * @param bool|string $filter + * @return void + */ + public function __construct($filter = false) + { + $this->filter = $filter; + } + + /** + * Return a generic transformed allocation array. * * @return array */ public function transform(Allocation $allocation) { + return $this->transformWithFilter($allocation); + } + + /** + * Determine which transformer filter to apply. + * + * @return array + */ + protected function transformWithFilter(Allocation $allocation) + { + if ($this->filter === 'server') { + return $this->transformForServer($allocation); + } + return $allocation->toArray(); } + + /** + * Transform the allocation to only return information not duplicated + * in the server response (discard node_id and server_id). + * + * @return array + */ + protected function transformForServer(Allocation $allocation) + { + return collect($allocation)->only('id', 'ip', 'ip_alias', 'port')->toArray(); + } } diff --git a/app/Transformers/Admin/LocationTransformer.php b/app/Transformers/Admin/LocationTransformer.php new file mode 100644 index 000000000..f41ead289 --- /dev/null +++ b/app/Transformers/Admin/LocationTransformer.php @@ -0,0 +1,71 @@ +. + * + * 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\Admin; + +use Pterodactyl\Models\Location; +use League\Fractal\TransformerAbstract; + +class LocationTransformer extends TransformerAbstract +{ + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = [ + 'nodes', + 'servers', + ]; + + /** + * Return a generic transformed pack array. + * + * @return array + */ + public function transform(Location $location) + { + return $location->toArray(); + } + + /** + * Return the nodes associated with this location. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeServers(Location $location) + { + return $this->collection($location->servers, new ServerTransformer, 'server'); + } + + /** + * Return the nodes associated with this location. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeNodes(Location $location) + { + return $this->collection($location->nodes, new NodeTransformer, 'node'); + } +} diff --git a/app/Transformers/Admin/NodeTransformer.php b/app/Transformers/Admin/NodeTransformer.php new file mode 100644 index 000000000..779f96059 --- /dev/null +++ b/app/Transformers/Admin/NodeTransformer.php @@ -0,0 +1,82 @@ +. + * + * 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\Admin; + +use Pterodactyl\Models\Node; +use League\Fractal\TransformerAbstract; + +class NodeTransformer extends TransformerAbstract +{ + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = [ + 'allocations', + 'location', + 'servers', + ]; + + /** + * Return a generic transformed pack array. + * + * @return array + */ + public function transform(Node $node) + { + return $node->toArray(); + } + + /** + * Return the nodes associated with this location. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeAllocations(Node $node) + { + return $this->collection($node->allocations, new AllocationTransformer, 'allocation'); + } + + /** + * Return the nodes associated with this location. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeLocation(Node $node) + { + return $this->item($node->location, new LocationTransformer, 'location'); + } + + /** + * Return the nodes associated with this location. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeServers(Node $node) + { + return $this->collection($node->servers, new ServerTransformer, 'server'); + } +} diff --git a/app/Transformers/Admin/OptionTransformer.php b/app/Transformers/Admin/OptionTransformer.php new file mode 100644 index 000000000..bdc0b1baf --- /dev/null +++ b/app/Transformers/Admin/OptionTransformer.php @@ -0,0 +1,93 @@ +. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +namespace Pterodactyl\Transformers\Admin; + +use Pterodactyl\Models\ServiceOption; +use League\Fractal\TransformerAbstract; + +class OptionTransformer extends TransformerAbstract +{ + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = [ + 'service', + 'packs', + 'servers', + 'variables', + ]; + + /** + * Return a generic transformed service option array. + * + * @return array + */ + public function transform(ServiceOption $option) + { + return $option->toArray(); + } + + /** + * Return the parent service for this service option. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeService(ServiceOption $option) + { + return $this->item($option->service, new ServiceTransformer, 'service'); + } + + /** + * Return the packs associated with this service option. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includePacks(ServiceOption $option) + { + return $this->collection($option->packs, new PackTransformer, 'pack'); + } + + /** + * Return the servers associated with this service option. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeServers(ServiceOption $option) + { + return $this->collection($option->servers, new ServerTransformer, 'server'); + } + + /** + * Return the variables for this service option. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeVariables(ServiceOption $option) + { + return $this->collection($option->variables, new ServiceVariableTransformer, 'variable'); + } +} diff --git a/app/Transformers/Admin/PackTransformer.php b/app/Transformers/Admin/PackTransformer.php new file mode 100644 index 000000000..309280fd1 --- /dev/null +++ b/app/Transformers/Admin/PackTransformer.php @@ -0,0 +1,75 @@ +. + * + * 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\Admin; + +use Pterodactyl\Models\Pack; +use League\Fractal\TransformerAbstract; + +class PackTransformer extends TransformerAbstract +{ + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = [ + 'option', + 'servers', + ]; + + /** + * Return a generic transformed pack array. + * + * @return array + */ + public function transform($pack) + { + if (! $pack instanceof Pack) { + return ['id' => null]; + } + + return $pack->toArray(); + } + + /** + * Return the packs associated with this service. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeOption(Pack $pack) + { + return $this->item($pack->option, new OptionTransformer, 'option'); + } + + /** + * Return the packs associated with this service. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeServers(Pack $pack) + { + return $this->collection($pack->servers, new ServerTransformer, 'server'); + } +} diff --git a/app/Transformers/Admin/ServerTransformer.php b/app/Transformers/Admin/ServerTransformer.php index 875e2261c..e17ba8ae5 100644 --- a/app/Transformers/Admin/ServerTransformer.php +++ b/app/Transformers/Admin/ServerTransformer.php @@ -38,6 +38,12 @@ class ServerTransformer extends TransformerAbstract 'allocations', 'user', 'subusers', + 'pack', + 'service', + 'option', + 'variables', + 'location', + 'node', ]; /** @@ -57,7 +63,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeAllocations(Server $server) { - return $this->collection($server->allocations, new AllocationTransformer, 'allocation'); + return $this->collection($server->allocations, new AllocationTransformer('server'), 'allocation'); } /** @@ -79,4 +85,64 @@ class ServerTransformer extends TransformerAbstract { return $this->item($server->user, new UserTransformer, 'user'); } + + /** + * Return a generic array with pack information for this server. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includePack(Server $server) + { + return $this->item($server->pack, new PackTransformer, 'pack'); + } + + /** + * Return a generic array with service information for this server. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeService(Server $server) + { + return $this->item($server->service, new ServiceTransformer, 'service'); + } + + /** + * Return a generic array with service option information for this server. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeOption(Server $server) + { + return $this->item($server->option, new OptionTransformer, 'option'); + } + + /** + * Return a generic array of data about subusers for this server. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeVariables(Server $server) + { + return $this->collection($server->variables, new ServerVariableTransformer, 'server_variable'); + } + + /** + * Return a generic array with pack information for this server. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeLocation(Server $server) + { + return $this->item($server->location, new LocationTransformer, 'location'); + } + + /** + * Return a generic array with pack information for this server. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeNode(Server $server) + { + return $this->item($server->node, new NodeTransformer, 'node'); + } } diff --git a/app/Transformers/Admin/ServerVariableTransformer.php b/app/Transformers/Admin/ServerVariableTransformer.php new file mode 100644 index 000000000..9d2247418 --- /dev/null +++ b/app/Transformers/Admin/ServerVariableTransformer.php @@ -0,0 +1,58 @@ +. + * + * 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\Admin; + +use Pterodactyl\Models\ServerVariable; +use League\Fractal\TransformerAbstract; + +class ServerVariableTransformer extends TransformerAbstract +{ + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = ['parent']; + + /** + * Return a generic transformed server variable array. + * + * @return array + */ + public function transform(ServerVariable $variable) + { + return $variable->toArray(); + } + + /** + * Return the parent service variable data. + * + * @return \Leauge\Fractal\Resource\Item + */ + public function includeParent(ServerVariable $variable) + { + return $this->item($variable->variable, new ServiceVariableTransformer, 'variable'); + } +} diff --git a/app/Transformers/Admin/ServiceTransformer.php b/app/Transformers/Admin/ServiceTransformer.php new file mode 100644 index 000000000..eb1fb2ab1 --- /dev/null +++ b/app/Transformers/Admin/ServiceTransformer.php @@ -0,0 +1,82 @@ +. + * + * 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\Admin; + +use Pterodactyl\Models\Service; +use League\Fractal\TransformerAbstract; + +class ServiceTransformer extends TransformerAbstract +{ + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = [ + 'options', + 'servers', + 'packs', + ]; + + /** + * Return a generic transformed service array. + * + * @return array + */ + public function transform(Service $service) + { + return $service->toArray(); + } + + /** + * Return the the service options. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeOptions(Service $service) + { + return $this->collection($service->options, new OptionTransformer, 'option'); + } + + /** + * Return the servers associated with this service. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeServers(Service $service) + { + return $this->collection($service->servers, new ServerTransformer, 'server'); + } + + /** + * Return the packs associated with this service. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includePacks(Service $service) + { + return $this->collection($service->packs, new PackTransformer, 'pack'); + } +} diff --git a/app/Transformers/Admin/ServiceVariableTransformer.php b/app/Transformers/Admin/ServiceVariableTransformer.php new file mode 100644 index 000000000..1a15c7ee0 --- /dev/null +++ b/app/Transformers/Admin/ServiceVariableTransformer.php @@ -0,0 +1,58 @@ +. + * + * 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\Admin; + +use Pterodactyl\Models\ServiceVariable; +use League\Fractal\TransformerAbstract; + +class ServiceVariableTransformer extends TransformerAbstract +{ + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = ['variables']; + + /** + * Return a generic transformed server variable array. + * + * @return array + */ + public function transform(ServiceVariable $variable) + { + return $variable->toArray(); + } + + /** + * Return the server variables associated with this variable. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeVariables(ServiceVariable $variable) + { + return $this->collection($variable->serverVariable, new ServerVariableTransformer, 'server_variable'); + } +} From db4df2bfa1705e62286e1744ac694ffcb15e4d3f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Fri, 7 Apr 2017 21:25:17 -0400 Subject: [PATCH 08/23] Push basis of new API key policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Will need to revisit this another day when I’m fresh to figure out the best method to do this. --- .../API/Admin/ServerController.php | 10 ++- app/Http/Middleware/HMACAuthorization.php | 18 +---- app/Policies/APIKeyPolicy.php | 77 +++++++++++++++++++ app/Policies/ServerPolicy.php | 2 +- app/Providers/AuthServiceProvider.php | 1 + app/Providers/MacroServiceProvider.php | 15 ++++ 6 files changed, 104 insertions(+), 19 deletions(-) create mode 100644 app/Policies/APIKeyPolicy.php diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php index 716d39dca..793af13ec 100644 --- a/app/Http/Controllers/API/Admin/ServerController.php +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -60,9 +60,17 @@ class ServerController extends Controller public function view(Request $request, $id) { $server = Server::findOrFail($id); - $fractal = Fractal::create()->item($server); + // dd($request->user()->can('view-node', $request->apiKey())); + + // Have the api key model return a list of includes that would be allowed + // given the permissions they have aleady been granted? + // + // If someone has 'view-node' they would then be able to use ->parseIncludes(['*.node.*']); + // How that logic will work is beyond me currently, but should keep things + // fairly clean? + if ($request->input('include')) { $fractal->parseIncludes(explode(',', $request->input('include'))); } diff --git a/app/Http/Middleware/HMACAuthorization.php b/app/Http/Middleware/HMACAuthorization.php index 6eac236a2..7b4e84b7f 100644 --- a/app/Http/Middleware/HMACAuthorization.php +++ b/app/Http/Middleware/HMACAuthorization.php @@ -92,6 +92,7 @@ class HMACAuthorization $this->checkBearer(); $this->validateRequest(); + $this->validateIPAccess(); $this->validateContents(); Auth::loginUsingId($this->key()->user_id); @@ -137,23 +138,6 @@ class HMACAuthorization if (! $this->key) { throw new AccessDeniedHttpException('Unable to identify requester. Authorization token is invalid.'); } - - if (empty($this->request()->route()->getName())) { - throw new \Exception('Attempting to access un-named route. This should not be possible.'); - } - - $this->validateIPAccess(); - - $query = APIPermission::where('key_id', $this->key()->id) - ->where('permission', $this->request()->route()->getName()); - - if (starts_with($this->request()->route()->getName(), 'api.user')) { - $query->orWhere('permission', 'api.user.*'); - } - - if (! $query->first()) { - throw new AccessDeniedHttpException('You do not have permission to access this resource on the API.'); - } } /** diff --git a/app/Policies/APIKeyPolicy.php b/app/Policies/APIKeyPolicy.php new file mode 100644 index 000000000..caeaae5df --- /dev/null +++ b/app/Policies/APIKeyPolicy.php @@ -0,0 +1,77 @@ +. + * + * 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\Policies; + +use Cache; +use Carbon; +use Pterodactyl\Models\User; +use Pterodactyl\Models\APIKey as Key; +use Pterodactyl\Models\APIPermission as Permission; + +class APIKeyPolicy +{ + /** + * Checks if the API key has permission to perform an action. + * + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @param string $permission + * @return bool + */ + private function checkPermission(User $user, Key $key, $permission) + { + $permissions = Cache::remember('APIKeyPolicy.' . $user->uuid . $key->public, Carbon::now()->addSeconds(5), function () use ($key) { + return $key->permissions()->get()->transform(function ($item) { + return $item->permission; + })->values(); + }); + + return $permissions->search($permission, true) !== false; + } + + /** + * Determine if API key is allowed to view all nodes. + * + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function listNodes(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'list-nodes'); + } + + /** + * Determine if API key is allowed to view a specific node. + * + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function viewNode(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'view-node'); + } +} diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index f375afecc..6b73258fa 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -45,7 +45,7 @@ class ServerPolicy return true; } - $permissions = Cache::remember('ServerPolicy.' . $user->uuid . $server->uuid, Carbon::now()->addSeconds(10), function () use ($user, $server) { + $permissions = Cache::remember('ServerPolicy.' . $user->uuid . $server->uuid, Carbon::now()->addSeconds(5), function () use ($user, $server) { return $user->permissions()->server($server)->get()->transform(function ($item) { return $item->permission; })->values(); diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 674d7600a..e1401e844 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -13,6 +13,7 @@ class AuthServiceProvider extends ServiceProvider */ protected $policies = [ 'Pterodactyl\Models\Server' => 'Pterodactyl\Policies\ServerPolicy', + 'Pterodactyl\Models\APIKey' => 'Pterodactyl\Policies\APIKeyPolicy', ]; /** diff --git a/app/Providers/MacroServiceProvider.php b/app/Providers/MacroServiceProvider.php index ad23aaf74..eb5a52c56 100644 --- a/app/Providers/MacroServiceProvider.php +++ b/app/Providers/MacroServiceProvider.php @@ -25,6 +25,7 @@ namespace Pterodactyl\Providers; use File; +use Request; use Illuminate\Support\ServiceProvider; class MacroServiceProvider extends ServiceProvider @@ -48,5 +49,19 @@ class MacroServiceProvider extends ServiceProvider return round($size, ($i < 2) ? 0 : $precision) . ' ' . $units[$i]; }); + + Request::macro('apiKey', function () { + if (! Request::bearerToken()) { + return false; + } + + $parts = explode('.', Request::bearerToken()); + + if (count($parts) === 2) { + return \Pterodactyl\Models\APIKey::where('public', $parts[0])->first(); + } + + return false; + }); } } From 4479d3bf197b0256284d2ab017b121ded35f225f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 8 Apr 2017 12:05:29 -0400 Subject: [PATCH 09/23] Improved logic for handling permissions on API routes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Still only partially implemented, however this method will allow the inclusion of data that is granted with servers (such as viewing more about the node, node location, allocations, etc) while still limiting someone from doing `?include=node.servers` and listing all servers when they don’t have list-servers as a permission. --- .../API/Admin/ServerController.php | 13 +----- app/Models/APIKey.php | 7 +++ app/Policies/APIKeyPolicy.php | 4 +- app/Providers/MacroServiceProvider.php | 23 +++++++++- .../Admin/AllocationTransformer.php | 20 +++++++-- .../Admin/LocationTransformer.php | 23 ++++++++++ app/Transformers/Admin/NodeTransformer.php | 27 ++++++++++++ app/Transformers/Admin/OptionTransformer.php | 23 ++++++++++ app/Transformers/Admin/PackTransformer.php | 23 ++++++++++ app/Transformers/Admin/ServerTransformer.php | 43 ++++++++++++++----- .../Admin/ServerVariableTransformer.php | 23 ++++++++++ app/Transformers/Admin/ServiceTransformer.php | 23 ++++++++++ .../Admin/ServiceVariableTransformer.php | 23 ++++++++++ app/Transformers/Admin/SubuserTransformer.php | 23 ++++++++++ app/Transformers/Admin/UserTransformer.php | 23 ++++++++++ config/debugbar.php | 4 +- 16 files changed, 296 insertions(+), 29 deletions(-) diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php index 793af13ec..4fc4a3a14 100644 --- a/app/Http/Controllers/API/Admin/ServerController.php +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -45,7 +45,7 @@ class ServerController extends Controller return Fractal::create() ->collection($servers) - ->transformWith(new ServerTransformer) + ->transformWith(new ServerTransformer($request)) ->paginateWith(new IlluminatePaginatorAdapter($servers)) ->withResourceName('server') ->toArray(); @@ -62,20 +62,11 @@ class ServerController extends Controller $server = Server::findOrFail($id); $fractal = Fractal::create()->item($server); - // dd($request->user()->can('view-node', $request->apiKey())); - - // Have the api key model return a list of includes that would be allowed - // given the permissions they have aleady been granted? - // - // If someone has 'view-node' they would then be able to use ->parseIncludes(['*.node.*']); - // How that logic will work is beyond me currently, but should keep things - // fairly clean? - if ($request->input('include')) { $fractal->parseIncludes(explode(',', $request->input('include'))); } - return $fractal->transformWith(new ServerTransformer) + return $fractal->transformWith(new ServerTransformer($request)) ->withResourceName('server') ->toArray(); } diff --git a/app/Models/APIKey.php b/app/Models/APIKey.php index f560fda85..6ed73b7c2 100644 --- a/app/Models/APIKey.php +++ b/app/Models/APIKey.php @@ -28,6 +28,13 @@ use Illuminate\Database\Eloquent\Model; class APIKey extends Model { + /** + * Public key defined length used in verification methods. + * + * @var int + */ + const PUBLIC_KEY_LEN = 16; + /** * The table associated with the model. * diff --git a/app/Policies/APIKeyPolicy.php b/app/Policies/APIKeyPolicy.php index caeaae5df..10aee1e4d 100644 --- a/app/Policies/APIKeyPolicy.php +++ b/app/Policies/APIKeyPolicy.php @@ -42,7 +42,9 @@ class APIKeyPolicy */ private function checkPermission(User $user, Key $key, $permission) { - $permissions = Cache::remember('APIKeyPolicy.' . $user->uuid . $key->public, Carbon::now()->addSeconds(5), function () use ($key) { + // We don't tag this cache key with the user uuid because the key is already unique, + // and multiple users are not defiend for a single key. + $permissions = Cache::remember('APIKeyPolicy.' . $key->public, Carbon::now()->addSeconds(5), function () use ($key) { return $key->permissions()->get()->transform(function ($item) { return $item->permission; })->values(); diff --git a/app/Providers/MacroServiceProvider.php b/app/Providers/MacroServiceProvider.php index eb5a52c56..980634dd6 100644 --- a/app/Providers/MacroServiceProvider.php +++ b/app/Providers/MacroServiceProvider.php @@ -25,7 +25,10 @@ namespace Pterodactyl\Providers; use File; +use Cache; +use Carbon; use Request; +use Pterodactyl\Models\APIKey; use Illuminate\Support\ServiceProvider; class MacroServiceProvider extends ServiceProvider @@ -57,11 +60,27 @@ class MacroServiceProvider extends ServiceProvider $parts = explode('.', Request::bearerToken()); - if (count($parts) === 2) { - return \Pterodactyl\Models\APIKey::where('public', $parts[0])->first(); + if (count($parts) === 2 && strlen($parts[0]) === APIKey::PUBLIC_KEY_LEN) { + // Because the key itself isn't changing frequently, we simply cache this for + // 15 minutes to speed up the API and keep requests flowing. + return Cache::tags([ + 'ApiKeyMacro', + 'ApiKeyMacro:Key:' . $parts[0], + ])->remember('ApiKeyMacro.' . $parts[0], Carbon::now()->addMinutes(15), function() use ($parts) { + return APIKey::where('public', $parts[0])->first(); + }); } return false; }); + + Request::macro('apiKeyHasPermission', function($permission) { + $key = Request::apiKey(); + if (! $key) { + return false; + } + + return Request::user()->can($permission, $key); + }); } } diff --git a/app/Transformers/Admin/AllocationTransformer.php b/app/Transformers/Admin/AllocationTransformer.php index c7fa85724..e7bd15c36 100644 --- a/app/Transformers/Admin/AllocationTransformer.php +++ b/app/Transformers/Admin/AllocationTransformer.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\Allocation; use League\Fractal\TransformerAbstract; @@ -37,13 +38,26 @@ class AllocationTransformer extends TransformerAbstract protected $filter; /** - * Transformer constructor. + * The Illuminate Request object if provided. * - * @param bool|string $filter + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @param bool $filter * @return void */ - public function __construct($filter = false) + public function __construct($request = false, $filter = false) { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; $this->filter = $filter; } diff --git a/app/Transformers/Admin/LocationTransformer.php b/app/Transformers/Admin/LocationTransformer.php index f41ead289..86980917b 100644 --- a/app/Transformers/Admin/LocationTransformer.php +++ b/app/Transformers/Admin/LocationTransformer.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\Location; use League\Fractal\TransformerAbstract; @@ -39,6 +40,28 @@ class LocationTransformer extends TransformerAbstract 'servers', ]; + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed pack array. * diff --git a/app/Transformers/Admin/NodeTransformer.php b/app/Transformers/Admin/NodeTransformer.php index 779f96059..cc42719a9 100644 --- a/app/Transformers/Admin/NodeTransformer.php +++ b/app/Transformers/Admin/NodeTransformer.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\Node; use League\Fractal\TransformerAbstract; @@ -40,6 +41,28 @@ class NodeTransformer extends TransformerAbstract 'servers', ]; + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed pack array. * @@ -77,6 +100,10 @@ class NodeTransformer extends TransformerAbstract */ public function includeServers(Node $node) { + if ($this->request && ! $this->request->apiKeyHasPermission('list-servers')) { + return; + } + return $this->collection($node->servers, new ServerTransformer, 'server'); } } diff --git a/app/Transformers/Admin/OptionTransformer.php b/app/Transformers/Admin/OptionTransformer.php index bdc0b1baf..1d38b4a94 100644 --- a/app/Transformers/Admin/OptionTransformer.php +++ b/app/Transformers/Admin/OptionTransformer.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\ServiceOption; use League\Fractal\TransformerAbstract; @@ -41,6 +42,28 @@ class OptionTransformer extends TransformerAbstract 'variables', ]; + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed service option array. * diff --git a/app/Transformers/Admin/PackTransformer.php b/app/Transformers/Admin/PackTransformer.php index 309280fd1..50160744e 100644 --- a/app/Transformers/Admin/PackTransformer.php +++ b/app/Transformers/Admin/PackTransformer.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\Pack; use League\Fractal\TransformerAbstract; @@ -39,6 +40,28 @@ class PackTransformer extends TransformerAbstract 'servers', ]; + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed pack array. * diff --git a/app/Transformers/Admin/ServerTransformer.php b/app/Transformers/Admin/ServerTransformer.php index e17ba8ae5..f33afce76 100644 --- a/app/Transformers/Admin/ServerTransformer.php +++ b/app/Transformers/Admin/ServerTransformer.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\Server; use League\Fractal\TransformerAbstract; @@ -46,6 +47,28 @@ class ServerTransformer extends TransformerAbstract 'node', ]; + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed server array. * @@ -63,7 +86,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeAllocations(Server $server) { - return $this->collection($server->allocations, new AllocationTransformer('server'), 'allocation'); + return $this->collection($server->allocations, new AllocationTransformer($this->request, 'server'), 'allocation'); } /** @@ -73,7 +96,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeSubusers(Server $server) { - return $this->collection($server->subusers, new SubuserTransformer, 'subuser'); + return $this->collection($server->subusers, new SubuserTransformer($this->request), 'subuser'); } /** @@ -83,7 +106,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeUser(Server $server) { - return $this->item($server->user, new UserTransformer, 'user'); + return $this->item($server->user, new UserTransformer($this->request), 'user'); } /** @@ -93,7 +116,7 @@ class ServerTransformer extends TransformerAbstract */ public function includePack(Server $server) { - return $this->item($server->pack, new PackTransformer, 'pack'); + return $this->item($server->pack, new PackTransformer($this->request), 'pack'); } /** @@ -103,7 +126,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeService(Server $server) { - return $this->item($server->service, new ServiceTransformer, 'service'); + return $this->item($server->service, new ServiceTransformer($this->request), 'service'); } /** @@ -113,7 +136,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeOption(Server $server) { - return $this->item($server->option, new OptionTransformer, 'option'); + return $this->item($server->option, new OptionTransformer($this->request), 'option'); } /** @@ -123,7 +146,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeVariables(Server $server) { - return $this->collection($server->variables, new ServerVariableTransformer, 'server_variable'); + return $this->collection($server->variables, new ServerVariableTransformer($this->request), 'server_variable'); } /** @@ -133,16 +156,16 @@ class ServerTransformer extends TransformerAbstract */ public function includeLocation(Server $server) { - return $this->item($server->location, new LocationTransformer, 'location'); + return $this->item($server->location, new LocationTransformer($this->request), 'location'); } /** * Return a generic array with pack information for this server. * - * @return \Leauge\Fractal\Resource\Item + * @return \Leauge\Fractal\Resource\Item|void */ public function includeNode(Server $server) { - return $this->item($server->node, new NodeTransformer, 'node'); + return $this->item($server->node, new NodeTransformer($this->request), 'node'); } } diff --git a/app/Transformers/Admin/ServerVariableTransformer.php b/app/Transformers/Admin/ServerVariableTransformer.php index 9d2247418..3521e0840 100644 --- a/app/Transformers/Admin/ServerVariableTransformer.php +++ b/app/Transformers/Admin/ServerVariableTransformer.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\ServerVariable; use League\Fractal\TransformerAbstract; @@ -36,6 +37,28 @@ class ServerVariableTransformer extends TransformerAbstract */ protected $availableIncludes = ['parent']; + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed server variable array. * diff --git a/app/Transformers/Admin/ServiceTransformer.php b/app/Transformers/Admin/ServiceTransformer.php index eb1fb2ab1..15e8859b2 100644 --- a/app/Transformers/Admin/ServiceTransformer.php +++ b/app/Transformers/Admin/ServiceTransformer.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\Service; use League\Fractal\TransformerAbstract; @@ -40,6 +41,28 @@ class ServiceTransformer extends TransformerAbstract 'packs', ]; + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed service array. * diff --git a/app/Transformers/Admin/ServiceVariableTransformer.php b/app/Transformers/Admin/ServiceVariableTransformer.php index 1a15c7ee0..9f87a1a81 100644 --- a/app/Transformers/Admin/ServiceVariableTransformer.php +++ b/app/Transformers/Admin/ServiceVariableTransformer.php @@ -24,6 +24,7 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\ServiceVariable; use League\Fractal\TransformerAbstract; @@ -36,6 +37,28 @@ class ServiceVariableTransformer extends TransformerAbstract */ protected $availableIncludes = ['variables']; + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed server variable array. * diff --git a/app/Transformers/Admin/SubuserTransformer.php b/app/Transformers/Admin/SubuserTransformer.php index 1c76dcc99..ab95ceb27 100644 --- a/app/Transformers/Admin/SubuserTransformer.php +++ b/app/Transformers/Admin/SubuserTransformer.php @@ -24,12 +24,35 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\Subuser; use Pterodactyl\Models\Permission; use League\Fractal\TransformerAbstract; class SubuserTransformer extends TransformerAbstract { + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed subuser array. * diff --git a/app/Transformers/Admin/UserTransformer.php b/app/Transformers/Admin/UserTransformer.php index 75dd950a3..95e5bef09 100644 --- a/app/Transformers/Admin/UserTransformer.php +++ b/app/Transformers/Admin/UserTransformer.php @@ -24,11 +24,34 @@ namespace Pterodactyl\Transformers\Admin; +use Illuminate\Http\Request; use Pterodactyl\Models\User; use League\Fractal\TransformerAbstract; class UserTransformer extends TransformerAbstract { + /** + * The Illuminate Request object if provided. + * + * @var \Illuminate\Http\Request|bool + */ + protected $request; + + /** + * Setup request object for transformer. + * + * @param \Illuminate\Http\Request|bool $request + * @return void + */ + public function __construct($request = false) + { + if (! $request instanceof Request && $request !== false) { + throw new DisplayException('Request passed to constructor must be of type Request or false.'); + } + + $this->request = $request; + } + /** * Return a generic transformed subuser array. * diff --git a/config/debugbar.php b/config/debugbar.php index 4d9d8c45e..05e78c34c 100644 --- a/config/debugbar.php +++ b/config/debugbar.php @@ -28,7 +28,7 @@ return [ */ 'storage' => [ 'enabled' => true, - 'driver' => 'file', // redis, file, pdo + 'driver' => env('DEBUGBAR_DRIVER', 'file'), // redis, file, pdo 'path' => storage_path() . '/debugbar', // For file driver 'connection' => null, // Leave null for default connection (Redis/PDO) ], @@ -125,7 +125,7 @@ return [ 'enabled' => false, 'types' => ['SELECT', 'INSERT', 'UPDATE', 'DELETE'], // array('SELECT', 'INSERT', 'UPDATE', 'DELETE'); for MySQL 5.6.3+ ], - 'hints' => true, // Show hints for common mistakes + 'hints' => false, // Show hints for common mistakes ], 'mail' => [ 'full_log' => false, From 463f465deac75691bac6440576949c79ea7112a8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 8 Apr 2017 12:07:17 -0400 Subject: [PATCH 10/23] Block viewing node allocations and location unless user has permission Blocks viewing the allocation list and location for a node unless a user has permission to view the node in the first place. --- app/Transformers/Admin/NodeTransformer.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/Transformers/Admin/NodeTransformer.php b/app/Transformers/Admin/NodeTransformer.php index cc42719a9..7f93410c8 100644 --- a/app/Transformers/Admin/NodeTransformer.php +++ b/app/Transformers/Admin/NodeTransformer.php @@ -80,6 +80,10 @@ class NodeTransformer extends TransformerAbstract */ public function includeAllocations(Node $node) { + if ($this->request && ! $this->request->apiKeyHasPermission('view-node')) { + return; + } + return $this->collection($node->allocations, new AllocationTransformer, 'allocation'); } @@ -90,6 +94,10 @@ class NodeTransformer extends TransformerAbstract */ public function includeLocation(Node $node) { + if ($this->request && ! $this->request->apiKeyHasPermission('view-node')) { + return; + } + return $this->item($node->location, new LocationTransformer, 'location'); } From c492446513ce3efc34d4a5a73dfd8650e1400155 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 13:15:15 -0400 Subject: [PATCH 11/23] Implement initial server and location API routes. Also fixes a few exception handler issues causing incorrect HTTP status codes on authorization errors. --- app/Exceptions/Handler.php | 1 + .../API/Admin/LocationController.php | 51 +++ .../API/Admin/ServerController.php | 336 ++++++++++++++++++ .../Controllers/API/User/CoreController.php | 2 + .../Controllers/API/User/ServerController.php | 6 + .../Controllers/Admin/ServersController.php | 16 +- app/Models/APIPermission.php | 42 +++ app/Models/Server.php | 10 + app/Policies/APIKeyPolicy.php | 152 +++++++- app/Repositories/ServerRepository.php | 35 +- app/Transformers/Admin/ServerTransformer.php | 2 +- routes/api-admin.php | 31 +- 12 files changed, 639 insertions(+), 45 deletions(-) create mode 100644 app/Http/Controllers/API/Admin/LocationController.php diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index c8025acde..22d79a952 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -47,6 +47,7 @@ class Handler extends ExceptionHandler public function render($request, Exception $exception) { if ($request->expectsJson() || $request->isJson() || $request->is(...config('pterodactyl.json_routes'))) { + $exception = $this->prepareException($exception); if (config('app.debug')) { $report = [ diff --git a/app/Http/Controllers/API/Admin/LocationController.php b/app/Http/Controllers/API/Admin/LocationController.php new file mode 100644 index 000000000..41405e91e --- /dev/null +++ b/app/Http/Controllers/API/Admin/LocationController.php @@ -0,0 +1,51 @@ +. + * + * 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\Admin; + +use Fractal; +use Illuminate\Http\Request; +use Pterodactyl\Models\Location; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Transformers\Admin\LocationTransformer; + +class LocationController extends Controller +{ + /** + * Controller to handle returning all locations on the system. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function index(Request $request) + { + $this->authorize('location-list', $request->apiKey()); + + return Fractal::create() + ->collection(Location::all()) + ->transformWith(new LocationTransformer($request)) + ->withResourceName('location') + ->toArray(); + } +} diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php index 4fc4a3a14..7562e013d 100644 --- a/app/Http/Controllers/API/Admin/ServerController.php +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -27,8 +27,12 @@ namespace Pterodactyl\Http\Controllers\API\Admin; use Fractal; use Illuminate\Http\Request; use Pterodactyl\Models\Server; +use GuzzleHttp\Exception\TransferException; +use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Repositories\ServerRepository; use Pterodactyl\Transformers\Admin\ServerTransformer; +use Pterodactyl\Exceptions\DisplayValidationException; use League\Fractal\Pagination\IlluminatePaginatorAdapter; class ServerController extends Controller @@ -41,6 +45,8 @@ class ServerController extends Controller */ public function index(Request $request) { + $this->authorize('server-list', $request->apiKey()); + $servers = Server::paginate(20); return Fractal::create() @@ -59,6 +65,8 @@ class ServerController extends Controller */ public function view(Request $request, $id) { + $this->authorize('server-view', $request->apiKey()); + $server = Server::findOrFail($id); $fractal = Fractal::create()->item($server); @@ -70,4 +78,332 @@ class ServerController extends Controller ->withResourceName('server') ->toArray(); } + + /** + * Create a new server on the system. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse|array + */ + public function store(Request $request) + { + $this->authorize('server-create', $request->apiKey()); + + $repo = new ServerRepository; + try { + $server = $repo->create($request->all()); + + $fractal = Fractal::create()->item($server)->transformWith(new ServerTransformer($request)); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->withResourceName('server')->toArray(); + } catch (DisplayValidationException $ex) { + return response()->json([ + 'error' => json_decode($ex->getMessage()), + ], 400); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (TransferException $ex) { + Log::warning($ex); + return response()->json([ + 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', + ], 504); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to add this server. Please try again.', + ], 500); + } + } + + /** + * Delete a server from the system. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse + */ + public function delete(Request $request, $id) + { + $this->authorize('server-delete', $request->apiKey()); + + $repo = new ServerRepository; + try { + $repo->delete($id, $request->has('force_delete')); + + return response('', 204); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (TransferException $ex) { + Log::warning($ex); + return response()->json([ + 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', + ], 504); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to add this server. Please try again.', + ], 500); + } + } + + /** + * Update the details for a server. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\JsonResponse|array + */ + public function details(Request $request, $id) + { + $this->authorize('server-edit-details', $request->apiKey()); + + $repo = new ServerRepository; + try { + $server = $repo->updateDetails($id, $request->intersect([ + 'owner_id', 'name', 'description', 'reset_token', + ])); + + $fractal = Fractal::create()->item($server)->transformWith(new ServerTransformer($request)); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->withResourceName('server')->toArray(); + } catch (DisplayValidationException $ex) { + return response()->json([ + 'error' => json_decode($ex->getMessage()), + ], 400); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to modify this server. Please try again.', + ], 500); + } + } + + /** + * Set the new docker container for a server. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\RedirectResponse|array + */ + public function container(Request $request, $id) + { + $this->authorize('server-edit-container', $request->apiKey()); + + $repo = new ServerRepository; + try { + $server = $repo->updateContainer($id, $request->intersect('docker_image')); + + $fractal = Fractal::create()->item($server)->transformWith(new ServerTransformer($request)); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->withResourceName('server')->toArray(); + } catch (DisplayValidationException $ex) { + return response()->json([ + 'error' => json_decode($ex->getMessage()), + ], 400); + } catch (TransferException $ex) { + Log::warning($ex); + return response()->json([ + 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', + ], 504); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to modify this server container. Please try again.', + ], 500); + } + } + + /** + * Toggles the install status for a server. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse + */ + public function install(Request $request, $id) + { + $this->authorize('server-install', $request->apiKey()); + + $repo = new ServerRepository; + try { + $repo->toggleInstall($id); + + return response('', 204); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to toggle the install status for this server. Please try again.', + ], 500); + } + } + + /** + * Setup a server to have a container rebuild. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse + */ + public function rebuild(Request $request, $id) + { + $this->authorize('server-rebuild', $request->apiKey()); + $server = Server::with('node')->findOrFail($id); + + try { + $server->node->guzzleClient([ + 'X-Access-Server' => $server->uuid, + 'X-Access-Token' => $server->node->daemonSecret, + ])->request('POST', '/server/rebuild'); + + return response('', 204); + } catch (TransferException $ex) { + Log::warning($ex); + return response()->json([ + 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', + ], 504); + } + } + + /** + * Manage the suspension status for a server. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse + */ + public function suspend(Request $request, $id) + { + $this->authorize('server-suspend', $request->apiKey()); + + $repo = new ServerRepository; + $action = $request->input('action'); + if (! in_array($action, ['suspend', 'unsuspend'])) { + return response()->json([ + 'error' => 'The action provided was invalid. Action should be one of: suspend, unsuspend.', + ], 400); + } + + try { + $repo->$action($id); + + return response('', 204); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (TransferException $ex) { + Log::warning($ex); + return response()->json([ + 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', + ], 504); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to ' . $action . ' this server. Please try again.', + ], 500); + } + } + + /** + * Update the build configuration for a server. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\JsonResponse|array + */ + public function build(Request $request, $id) + { + $this->authorize('server-edit-build', $request->apiKey()); + + $repo = new ServerRepository; + try { + $server = $repo->changeBuild($id, $request->intersect([ + 'allocation_id', 'add_allocations', 'remove_allocations', + 'memory', 'swap', 'io', 'cpu', + ])); + + $fractal = Fractal::create()->item($server)->transformWith(new ServerTransformer($request)); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->withResourceName('server')->toArray(); + } catch (DisplayValidationException $ex) { + return response()->json([ + 'error' => json_decode($ex->getMessage()), + ], 400); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (TransferException $ex) { + Log::warning($ex); + return response()->json([ + 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', + ], 504); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to modify the build settings for this server. Please try again.', + ], 500); + } + } + + /** + * Update the startup command as well as variables. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse + */ + public function startup(Request $request, $id) + { + $this->authorize('server-edit-startup', $request->apiKey()); + + $repo = new ServerRepository; + try { + $repo->updateStartup($id, $request->all(), true); + + return response('', 204); + } catch (DisplayValidationException $ex) { + return response()->json([ + 'error' => json_decode($ex->getMessage()), + ], 400); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (TransferException $ex) { + Log::warning($ex); + return response()->json([ + 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', + ], 504); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to modify the startup settings for this server. Please try again.', + ], 500); + } + } } diff --git a/app/Http/Controllers/API/User/CoreController.php b/app/Http/Controllers/API/User/CoreController.php index b036c0db7..926cb3a62 100644 --- a/app/Http/Controllers/API/User/CoreController.php +++ b/app/Http/Controllers/API/User/CoreController.php @@ -39,6 +39,8 @@ class CoreController extends Controller */ public function index(Request $request) { + $this->authorize('user-server-list', $request->apiKey()); + $servers = $request->user()->access('service', 'node', 'allocation', 'option')->get(); return Fractal::collection($servers) diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index 36fdc0fac..32f18eb2f 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -43,6 +43,8 @@ class ServerController extends Controller */ public function index(Request $request, $uuid) { + $this->authorize('user-server-view', $request->apiKey()); + $server = Server::byUuid($uuid); $fractal = Fractal::create()->item($server); @@ -64,6 +66,8 @@ class ServerController extends Controller */ public function power(Request $request, $uuid) { + $this->authorize('user-server-power', $request->apiKey()); + $server = Server::byUuid($uuid); $request->user()->can('power-' . $request->input('action'), $server); @@ -82,6 +86,8 @@ class ServerController extends Controller */ public function command(Request $request, $uuid) { + $this->authorize('user-server-command', $request->apiKey()); + $server = Server::byUuid($uuid); $request->user()->can('send-command', $server); diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 07cba84fd..1016f802c 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -97,6 +97,9 @@ class ServersController extends Controller return redirect()->route('admin.servers.new')->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); + } catch (TransferException $ex) { + Log::warning($ex); + Alert::danger('A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.')->flash(); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled exception occured while attemping to add this server. Please try again.')->flash(); @@ -284,8 +287,9 @@ class ServersController extends Controller Alert::success('Successfully updated this server\'s docker image.')->flash(); } catch (DisplayValidationException $ex) { return redirect()->route('admin.servers.view.details', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); - } catch (DisplayException $ex) { - Alert::danger($ex->getMessage())->flash(); + } catch (TransferException $ex) { + Log::warning($ex); + Alert::danger('A TransferException occured while attempting to update the container image. Is the daemon online? This error has been logged.'); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled exception occured while attemping to update this server\'s docker image. This error has been logged.')->flash(); @@ -366,8 +370,9 @@ class ServersController extends Controller $repo->$action($id); Alert::success('Server has been ' . $action . 'ed.'); - } catch (DisplayException $ex) { - Alert::danger($ex->getMessage())->flash(); + } catch (TransferException $ex) { + Log::warning($ex); + Alert::danger('A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.')->flash(); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled exception occured while attemping to ' . $action . ' this server. This error has been logged.')->flash(); @@ -398,6 +403,9 @@ class ServersController extends Controller return redirect()->route('admin.servers.view.build', $id)->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); + } catch (TransferException $ex) { + Log::warning($ex); + Alert::danger('A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.')->flash(); } catch (\Exception $ex) { Log::error($ex); Alert::danger('An unhandled exception occured while attemping to add this server. This error has been logged.')->flash(); diff --git a/app/Models/APIPermission.php b/app/Models/APIPermission.php index 90e7ff16e..7450392d8 100644 --- a/app/Models/APIPermission.php +++ b/app/Models/APIPermission.php @@ -57,4 +57,46 @@ class APIPermission extends Model * @var bool */ public $timestamps = false; + + /** + * List of permissions available for the API. + * + * @var array + */ + protected static $permissions = [ + // Items within this block are available to non-adminitrative users. + '_user' => [ + 'server' => [ + 'list', + 'view', + 'power', + 'command', + ] + ], + + // All other pemissions below are administrative actions. + 'server' => [ + 'list', + 'view', + 'delete', + 'create', + 'edit-details', + 'edit-container', + 'suspend', + 'install', + 'rebuild', + 'edit-build', + 'edit-startup', + ], + ]; + + /** + * Return permissions for API + * + * @return array + */ + public static function permissions() + { + return self::$permissions; + } } diff --git a/app/Models/Server.php b/app/Models/Server.php index ee2e1a89e..18c86c157 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -27,6 +27,7 @@ namespace Pterodactyl\Models; use Auth; use Cache; use Carbon; +use Schema; use Javascript; use Illuminate\Database\Eloquent\Model; use Illuminate\Notifications\Notifiable; @@ -203,6 +204,15 @@ class Server extends Model return Javascript::put($response); } + /** + * Return the columns available for this table. + * + * @return array + */ + public function getTableColumns() { + return Schema::getColumnListing($this->getTable()); + } + /** * Gets the user who owns the server. * diff --git a/app/Policies/APIKeyPolicy.php b/app/Policies/APIKeyPolicy.php index 10aee1e4d..2e8520a46 100644 --- a/app/Policies/APIKeyPolicy.php +++ b/app/Policies/APIKeyPolicy.php @@ -54,26 +54,162 @@ class APIKeyPolicy } /** - * Determine if API key is allowed to view all nodes. - * * @param \Pterodactyl\Models\User $user * @param \Pterodactyl\Models\APIKey $key * @return bool */ - public function listNodes(User $user, Key $key) + public function locationList(User $user, Key $key) { - return $this->checkPermission($user, $key, 'list-nodes'); + return $this->checkPermission($user, $key, 'location-list'); } /** - * Determine if API key is allowed to view a specific node. - * * @param \Pterodactyl\Models\User $user * @param \Pterodactyl\Models\APIKey $key * @return bool */ - public function viewNode(User $user, Key $key) + public function serverList(User $user, Key $key) { - return $this->checkPermission($user, $key, 'view-node'); + return $this->checkPermission($user, $key, 'server-list'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function serverView(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-view'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function serverCreate(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-create'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function serverDelete(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-delete'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function serverEditDetails(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-edit-details'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function serverEditContainer(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-edit-container'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function serverEditBuild(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-edit-build'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function serverEditStartup(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-edit-startup'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function serverSuspend(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-suspend'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function servrerInstall(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-install'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function serverRebuild(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'server-rebuild'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function userServerList(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'user-server-list'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function userServerView(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'user-server-view'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function userServerPower(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'user-server-power'); + } + + /** + * @param \Pterodactyl\Models\User $user + * @param \Pterodactyl\Models\APIKey $key + * @return bool + */ + public function userServerCommand(User $user, Key $key) + { + return $this->checkPermission($user, $key, 'user-server-command'); } } diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php index b4dcd1c81..28ca9a22b 100644 --- a/app/Repositories/ServerRepository.php +++ b/app/Repositories/ServerRepository.php @@ -337,9 +337,6 @@ class ServerRepository DB::commit(); return $server; - } catch (TransferException $ex) { - DB::rollBack(); - throw new DisplayException('There was an error while attempting to connect to the daemon to add this server.', $ex); } catch (\Exception $ex) { DB::rollBack(); throw $ex; @@ -351,7 +348,7 @@ class ServerRepository * * @param int $id * @param array $data - * @return bool + * @return \Pterodactyl\Models\Server * * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayValidationException @@ -409,7 +406,9 @@ class ServerRepository ]); if ($res->getStatusCode() === 204) { - return DB::commit(); + DB::commit(); + + return $server; } else { throw new DisplayException('Daemon returned a a non HTTP/204 error code. HTTP/' + $res->getStatusCode()); } @@ -424,9 +423,8 @@ class ServerRepository * * @param int $id * @param array $data - * @return bool + * @return \Pterodactyl\Models\Server * - * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayValidationException */ public function updateContainer($id, array $data) @@ -461,10 +459,7 @@ class ServerRepository DB::commit(); - return true; - } catch (TransferException $ex) { - DB::rollBack(); - throw new DisplayException('A TransferException occured while attempting to update the container image. Is the daemon online? This error has been logged.', $ex); + return $server; } catch (\Exception $ex) { DB::rollBack(); throw $ex; @@ -609,9 +604,6 @@ class ServerRepository DB::commit(); return $server; - } catch (TransferException $ex) { - DB::rollBack(); - throw new DisplayException('A TransferException occured while attempting to update the server configuration, check that the daemon is online. This error has been logged.', $ex); } catch (\Exception $ex) { DB::rollBack(); throw $ex; @@ -799,8 +791,6 @@ class ServerRepository * @param int $id * @param bool $deleted * @return void - * - * @throws \Pterodactyl\Exceptions\DisplayException */ public function suspend($id, $deleted = false) { @@ -824,9 +814,6 @@ class ServerRepository ])->request('POST', '/server/suspend'); return DB::commit(); - } catch (TransferException $ex) { - DB::rollBack(); - throw new DisplayException('An error occured while attempting to contact the remote daemon to suspend this server.', $ex); } catch (\Exception $ex) { DB::rollBack(); throw $ex; @@ -838,8 +825,6 @@ class ServerRepository * * @param int $id * @return void - * - * @throws \Pterodactyl\Exceptions\DisplayException */ public function unsuspend($id) { @@ -848,7 +833,6 @@ class ServerRepository DB::beginTransaction(); try { - // Already unsuspended, no need to make more requests. if ($server->suspended === 0) { return true; @@ -863,9 +847,6 @@ class ServerRepository ])->request('POST', '/server/unsuspend'); return DB::commit(); - } catch (TransferException $ex) { - DB::rollBack(); - throw new DisplayException('An error occured while attempting to contact the remote daemon to un-suspend this server.', $ex); } catch (\Exception $ex) { DB::rollBack(); throw $ex; @@ -879,7 +860,6 @@ class ServerRepository * @param string $password * @return void * - * @throws \Pterodactyl\Exceptions\DisplayException * @throws \Pterodactyl\Exceptions\DisplayValidationException */ public function updateSFTPPassword($id, $password) @@ -910,9 +890,6 @@ class ServerRepository DB::commit(); return true; - } catch (TransferException $ex) { - DB::rollBack(); - throw new DisplayException('There was an error while attmping to contact the remote service to change the password.', $ex); } catch (\Exception $ex) { DB::rollBack(); throw $ex; diff --git a/app/Transformers/Admin/ServerTransformer.php b/app/Transformers/Admin/ServerTransformer.php index f33afce76..23c754b5d 100644 --- a/app/Transformers/Admin/ServerTransformer.php +++ b/app/Transformers/Admin/ServerTransformer.php @@ -76,7 +76,7 @@ class ServerTransformer extends TransformerAbstract */ public function transform(Server $server) { - return $server->toArray(); + return collect($server->toArray())->only($server->getTableColumns())->toArray(); } /** diff --git a/routes/api-admin.php b/routes/api-admin.php index 7a0992fc1..9bcfa7480 100644 --- a/routes/api-admin.php +++ b/routes/api-admin.php @@ -22,7 +22,7 @@ * SOFTWARE. */ -Route::get('/', 'CoreController@index')->name('api.admin'); +Route::get('/', 'CoreController@index'); /* @@ -34,6 +34,31 @@ Route::get('/', 'CoreController@index')->name('api.admin'); | */ Route::group(['prefix' => '/servers'], function () { - Route::get('/', 'ServerController@index')->name('api.admin.servers.list'); - Route::get('/{id}', 'ServerController@view')->name('api.admin.servers.view'); + Route::get('/', 'ServerController@index'); + Route::get('/{id}', 'ServerController@view'); + + Route::post('/', 'ServerController@store'); + + Route::put('/{id}/details', 'ServerController@details'); + Route::put('/{id}/container', 'ServerController@container'); + Route::put('/{id}/build', 'ServerController@build'); + Route::put('/{id}/startup', 'ServerController@startup'); + + Route::patch('/{id}/install', 'ServerController@install'); + Route::patch('/{id}/rebuild', 'ServerController@rebuild'); + Route::patch('/{id}/suspend', 'ServerController@suspend'); + + Route::delete('/{id}', 'ServerController@delete'); +}); + +/* +|-------------------------------------------------------------------------- +| Location Controller Routes +|-------------------------------------------------------------------------- +| +| Endpoint: /api/admin/locations +| +*/ +Route::group(['prefix' => '/locations'], function () { + Route::get('/', 'LocationController@index'); }); From 75b8753533016cdaed4cc2b71791cff55c3ac2e5 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 13:34:47 -0400 Subject: [PATCH 12/23] Simplify server and api key policy. --- app/Policies/APIKeyPolicy.php | 159 +---------- app/Policies/ServerPolicy.php | 484 +--------------------------------- 2 files changed, 13 insertions(+), 630 deletions(-) diff --git a/app/Policies/APIKeyPolicy.php b/app/Policies/APIKeyPolicy.php index 2e8520a46..e946433e5 100644 --- a/app/Policies/APIKeyPolicy.php +++ b/app/Policies/APIKeyPolicy.php @@ -40,7 +40,7 @@ class APIKeyPolicy * @param string $permission * @return bool */ - private function checkPermission(User $user, Key $key, $permission) + protected function checkPermission(User $user, Key $key, $permission) { // We don't tag this cache key with the user uuid because the key is already unique, // and multiple users are not defiend for a single key. @@ -54,162 +54,15 @@ class APIKeyPolicy } /** + * Determine if a user has permission to perform this action against the system. + * * @param \Pterodactyl\Models\User $user + * @param string $permission * @param \Pterodactyl\Models\APIKey $key * @return bool */ - public function locationList(User $user, Key $key) + public function before(User $user, $permission, Key $key) { - return $this->checkPermission($user, $key, 'location-list'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverList(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-list'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverView(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-view'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverCreate(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-create'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverDelete(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-delete'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverEditDetails(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-edit-details'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverEditContainer(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-edit-container'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverEditBuild(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-edit-build'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverEditStartup(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-edit-startup'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverSuspend(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-suspend'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function servrerInstall(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-install'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function serverRebuild(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'server-rebuild'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function userServerList(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'user-server-list'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function userServerView(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'user-server-view'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function userServerPower(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'user-server-power'); - } - - /** - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\APIKey $key - * @return bool - */ - public function userServerCommand(User $user, Key $key) - { - return $this->checkPermission($user, $key, 'user-server-command'); + return $this->checkPermission($user, $key, $permission); } } diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index 6b73258fa..56cd359e1 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -39,12 +39,8 @@ class ServerPolicy * @param string $permission * @return bool */ - private function checkPermission(User $user, Server $server, $permission) + protected function checkPermission(User $user, Server $server, $permission) { - if ($this->isOwner($user, $server)) { - return true; - } - $permissions = Cache::remember('ServerPolicy.' . $user->uuid . $server->uuid, Carbon::now()->addSeconds(5), function () use ($user, $server) { return $user->permissions()->server($server)->get()->transform(function ($item) { return $item->permission; @@ -54,486 +50,20 @@ class ServerPolicy return $permissions->search($permission, true) !== false; } - /** - * Determine if current user is the owner of a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - protected function isOwner(User $user, Server $server) - { - return $server->owner_id === $user->id; - } - /** * Runs before any of the functions are called. Used to determine if user is root admin, if so, ignore permissions. * - * @param \Pterodactyl\Models\User $user - * @param string $ability + * @param \Pterodactyl\Models\User $user + * @param string $ability + * @param \Pterodactyl\Models\Server $server * @return bool */ - public function before(User $user, $ability) + public function before(User $user, $ability, Server $server) { - if ($user->root_admin === 1) { + if ($user->isRootAdmin() || $server->owner_id === $user->id) { return true; } - } - /** - * Check if user has permission to control power for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function power(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'power'); - } - - /** - * Check if user has permission to start a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function powerStart(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'power-start'); - } - - /** - * Check if user has permission to stop a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function powerStop(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'power-stop'); - } - - /** - * Check if user has permission to restart a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function powerRestart(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'power-restart'); - } - - /** - * Check if user has permission to kill a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function powerKill(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'power-kill'); - } - - /** - * Check if user has permission to run a command on a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function sendCommand(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'send-command'); - } - - /** - * Check if user has permission to list files on a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function listFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'list-files'); - } - - /** - * Check if user has permission to edit files on a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function editFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'edit-files'); - } - - /** - * Check if user has permission to save files on a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function saveFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'save-files'); - } - - /** - * Check if user has permission to move and rename files and folders on a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function moveFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'move-files'); - } - - /** - * Check if user has permission to copy folders and files on a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function copyFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'copy-files'); - } - - /** - * Check if user has permission to compress files and folders on a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function compressFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'compress-files'); - } - - /** - * Check if user has permission to decompress files on a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function decompressFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'decompress-files'); - } - - /** - * Check if user has permission to add files to a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function createFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'create-files'); - } - - /** - * Check if user has permission to upload files to a server. - * This permission relies on the user having the 'create-files' permission as well due to page authorization. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function uploadFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'upload-files'); - } - - /** - * Check if user has permission to download files from a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function downloadFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'download-files'); - } - - /** - * Check if user has permission to delete files from a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function deleteFiles(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'delete-files'); - } - - /** - * Check if user has permission to view subusers for the server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function listSubusers(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'list-subusers'); - } - - /** - * Check if user has permission to view specific subuser permissions. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function viewSubuser(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'view-subuser'); - } - - /** - * Check if user has permission to edit a subuser. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function editSubuser(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'edit-subuser'); - } - - /** - * Check if user has permission to delete a subuser. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function deleteSubuser(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'delete-subuser'); - } - - /** - * Check if user has permission to edit a subuser. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function createSubuser(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'create-subuser'); - } - - /** - * Check if user has permission to set the default connection for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function setConnection(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'set-connection'); - } - - /** - * Check if user has permission to view the startup command used for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function viewStartup(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'view-startup'); - } - - /** - * Check if user has permission to edit the startup command used for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function editStartup(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'edit-startup'); - } - - /** - * Check if user has permission to view the SFTP information for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function viewSftp(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'view-sftp'); - } - - /** - * Check if user has permission to reset the SFTP password for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function resetSftp(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'reset-sftp'); - } - - /** - * Check if user has permission to view the SFTP password for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function viewSftpPassword(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'view-sftp-password'); - } - - /** - * Check if user has permission to view databases for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function viewDatabases(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'view-databases'); - } - - /** - * Check if user has permission to reset database passwords. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function resetDbPassword(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'reset-db-password'); - } - - /** - * Check if user has permission to view all tasks for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function listTasks(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'list-tasks'); - } - - /** - * Check if user has permission to view a specific task for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function viewTask(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'view-task'); - } - - /** - * Check if user has permission to view a toggle a task for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function toggleTask(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'toggle-task'); - } - - /** - * Check if user has permission to queue a task for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function queueTask(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'queue-task'); - } - - /** - * Check if user has permission to delete a specific task for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function deleteTask(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'delete-task'); - } - - /** - * Check if user has permission to create a task for a server. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function createTask(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'create-task'); - } - - /** - * Check if user has permission to view server allocations. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function viewAllocation(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'view-allocation'); - } - - /** - * Check if user has permission to set the default allocation. - * - * @param \Pterodactyl\Models\User $user - * @param \Pterodactyl\Models\Server $server - * @return bool - */ - public function setAllocation(User $user, Server $server) - { - return $this->checkPermission($user, $server, 'set-allocation'); + return $this->checkPermission($user, $server, $ability); } } From f24b238e303a9ac460b9c7299f3893ca04756aa3 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 13:52:31 -0400 Subject: [PATCH 13/23] Base node route implementation --- .../Controllers/API/Admin/NodeController.php | 75 +++++++++++++++++++ app/Transformers/Admin/NodeTransformer.php | 6 +- routes/api-admin.php | 13 ++++ 3 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 app/Http/Controllers/API/Admin/NodeController.php diff --git a/app/Http/Controllers/API/Admin/NodeController.php b/app/Http/Controllers/API/Admin/NodeController.php new file mode 100644 index 000000000..256f12771 --- /dev/null +++ b/app/Http/Controllers/API/Admin/NodeController.php @@ -0,0 +1,75 @@ +. + * + * 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\Admin; + +use Fractal; +use Illuminate\Http\Request; +use Pterodactyl\Models\Node; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Transformers\Admin\NodeTransformer; + +class NodeController extends Controller +{ + /** + * Controller to handle returning all nodes on the system. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function index(Request $request) + { + $this->authorize('node-list', $request->apiKey()); + + $fractal = Fractal::create()->collection(Node::all()); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->transformWith(new NodeTransformer($request)) + ->withResourceName('node') + ->toArray(); + } + + /** + * Display information about a single node on the system. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return array + */ + public function view(Request $request, $id) + { + $this->authorize('node-view', $request->apiKey()); + + $fractal = Fractal::create()->item(Node::findOrFail($id)); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->transformWith(new NodeTransformer($request)) + ->withResourceName('node') + ->toArray(); + } +} diff --git a/app/Transformers/Admin/NodeTransformer.php b/app/Transformers/Admin/NodeTransformer.php index 7f93410c8..5f55e425f 100644 --- a/app/Transformers/Admin/NodeTransformer.php +++ b/app/Transformers/Admin/NodeTransformer.php @@ -80,7 +80,7 @@ class NodeTransformer extends TransformerAbstract */ public function includeAllocations(Node $node) { - if ($this->request && ! $this->request->apiKeyHasPermission('view-node')) { + if ($this->request && ! $this->request->apiKeyHasPermission('node-view')) { return; } @@ -94,7 +94,7 @@ class NodeTransformer extends TransformerAbstract */ public function includeLocation(Node $node) { - if ($this->request && ! $this->request->apiKeyHasPermission('view-node')) { + if ($this->request && ! $this->request->apiKeyHasPermission('node-view')) { return; } @@ -108,7 +108,7 @@ class NodeTransformer extends TransformerAbstract */ public function includeServers(Node $node) { - if ($this->request && ! $this->request->apiKeyHasPermission('list-servers')) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-list')) { return; } diff --git a/routes/api-admin.php b/routes/api-admin.php index 9bcfa7480..ae7de6f09 100644 --- a/routes/api-admin.php +++ b/routes/api-admin.php @@ -62,3 +62,16 @@ Route::group(['prefix' => '/servers'], function () { Route::group(['prefix' => '/locations'], function () { Route::get('/', 'LocationController@index'); }); + +/* +|-------------------------------------------------------------------------- +| Node Controller Routes +|-------------------------------------------------------------------------- +| +| Endpoint: /api/admin/nodes +| +*/ +Route::group(['prefix' => '/nodes'], function () { + Route::get('/', 'NodeController@index'); + Route::get('/{id}', 'NodeController@view'); +}); From 820d2bf17272a47e6f74b567d5958222b139b3c3 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 15:31:10 -0400 Subject: [PATCH 14/23] Node and user API routes implemented. More attempts at the logic for API permissions, most likely will need continued tweaking in the future, but base is there. --- .../Controllers/API/Admin/NodeController.php | 92 +++++++++ .../Controllers/API/Admin/UserController.php | 177 ++++++++++++++++++ app/Http/Controllers/Admin/UserController.php | 14 +- app/Repositories/UserRepository.php | 6 +- .../Admin/LocationTransformer.php | 12 +- app/Transformers/Admin/NodeTransformer.php | 6 +- app/Transformers/Admin/OptionTransformer.php | 24 ++- app/Transformers/Admin/PackTransformer.php | 12 +- app/Transformers/Admin/ServerTransformer.php | 36 ++++ .../Admin/ServerVariableTransformer.php | 6 +- app/Transformers/Admin/ServiceTransformer.php | 18 +- .../Admin/ServiceVariableTransformer.php | 6 +- app/Transformers/Admin/SubuserTransformer.php | 4 + app/Transformers/Admin/UserTransformer.php | 38 ++++ routes/api-admin.php | 22 +++ 15 files changed, 447 insertions(+), 26 deletions(-) create mode 100644 app/Http/Controllers/API/Admin/UserController.php diff --git a/app/Http/Controllers/API/Admin/NodeController.php b/app/Http/Controllers/API/Admin/NodeController.php index 256f12771..a88d5054b 100644 --- a/app/Http/Controllers/API/Admin/NodeController.php +++ b/app/Http/Controllers/API/Admin/NodeController.php @@ -28,7 +28,10 @@ use Fractal; use Illuminate\Http\Request; use Pterodactyl\Models\Node; use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Repositories\NodeRepository; use Pterodactyl\Transformers\Admin\NodeTransformer; +use Pterodactyl\Exceptions\DisplayValidationException; class NodeController extends Controller { @@ -72,4 +75,93 @@ class NodeController extends Controller ->withResourceName('node') ->toArray(); } + + /** + * Display information about a single node on the system. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\JsonResponse + */ + public function viewConfig(Request $request, $id) + { + $this->authorize('node-view-config', $request->apiKey()); + + $node = Node::findOrFail($id); + + return response()->json(json_decode($node->getConfigurationAsJson())); + } + + /** + * Create a new node on the system. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse|array + */ + public function store(Request $request) + { + $this->authorize('node-create', $request->apiKey()); + + $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', + ]) + )); + + $fractal = Fractal::create()->item($node)->transformWith(new NodeTransformer($request)); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->withResourceName('node')->toArray(); + } catch (DisplayValidationException $ex) { + return response()->json([ + 'error' => json_decode($ex->getMessage()), + ], 400); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to create this node. Please try again.', + ], 500); + } + } + + /** + * Delete a node from the system. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse + */ + public function delete(Request $request, $id) + { + $this->authorize('node-delete', $request->apiKey()); + + $repo = new NodeRepository; + try { + $repo->delete($id); + + return response('', 204); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to delete this node. Please try again.', + ], 500); + } + } } diff --git a/app/Http/Controllers/API/Admin/UserController.php b/app/Http/Controllers/API/Admin/UserController.php new file mode 100644 index 000000000..1f0dfb69a --- /dev/null +++ b/app/Http/Controllers/API/Admin/UserController.php @@ -0,0 +1,177 @@ +. + * + * 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\Admin; + +use Fractal; +use Illuminate\Http\Request; +use Pterodactyl\Models\User; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Repositories\UserRepository; +use Pterodactyl\Transformers\Admin\UserTransformer; +use Pterodactyl\Exceptions\DisplayValidationException; + +class UserController extends Controller +{ + /** + * Controller to handle returning all users on the system. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function index(Request $request) + { + $this->authorize('user-list', $request->apiKey()); + + $fractal = Fractal::create()->collection(User::all()); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->transformWith(new UserTransformer($request)) + ->withResourceName('user') + ->toArray(); + } + + /** + * Display information about a single user on the system. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return array + */ + public function view(Request $request, $id) + { + $this->authorize('user-view', $request->apiKey()); + + $fractal = Fractal::create()->item(User::findOrFail($id)); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->transformWith(new UserTransformer($request)) + ->withResourceName('user') + ->toArray(); + } + + /** + * Create a new user on the system. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse|array + */ + public function store(Request $request) + { + $this->authorize('user-create', $request->apiKey()); + + $repo = new UserRepository; + try { + $user = $repo->create($request->only([ + 'custom_id', 'email', 'password', 'name_first', + 'name_last', 'username', 'root_admin', + ])); + + $fractal = Fractal::create()->item($user)->transformWith(new UserTransformer($request)); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->withResourceName('user')->toArray(); + } catch (DisplayValidationException $ex) { + return response()->json([ + 'error' => json_decode($ex->getMessage()), + ], 400); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to create this user. Please try again.', + ], 500); + } + } + + /** + * Update a user. + * + * @param \Illuminate\Http\Request $request + * @param int $user + * @return \Illuminate\Http\RedirectResponse + */ + public function update(Request $request, $user) + { + $this->authorize('user-edit', $request->apiKey()); + + $repo = new UserRepository; + try { + $user = $repo->update($user, $request->intersect([ + 'email', 'password', 'name_first', + 'name_last', 'username', 'root_admin', + ])); + + $fractal = Fractal::create()->item($user)->transformWith(new UserTransformer($request)); + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->withResourceName('user')->toArray(); + } catch (DisplayValidationException $ex) { + return response()->json([ + 'error' => json_decode($ex->getMessage()), + ], 400); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to update this user. Please try again.', + ], 500); + } + } + + /** + * Delete a user from the system. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse + */ + public function delete(Request $request, $id) + { + $this->authorize('user-delete', $request->apiKey()); + + $repo = new UserRepository; + try { + $repo->delete($id); + + return response('', 204); + } catch (DisplayException $ex) { + return response()->json([ + 'error' => $ex->getMessage(), + ], 400); + } catch (\Exception $ex) { + Log::error($ex); + return response()->json([ + 'error' => 'An unhandled exception occured while attemping to delete this user. Please try again.', + ], 500); + } + } +} diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index 8439cc2ab..f7324456b 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -136,26 +136,26 @@ class UserController extends Controller * Update a user. * * @param \Illuminate\Http\Request $request - * @param int $user + * @param int $id * @return \Illuminate\Http\RedirectResponse */ - public function updateUser(Request $request, $user) + public function updateUser(Request $request, $id) { try { $repo = new UserRepository; - $repo->update($user, $request->only([ + $user = $repo->update($user, $request->intersect([ 'email', 'password', 'name_first', 'name_last', 'username', 'root_admin', ])); Alert::success('User account was successfully updated.')->flash(); } catch (DisplayValidationException $ex) { - return redirect()->route('admin.users.view', $user)->withErrors(json_decode($ex->getMessage())); - } catch (\Exception $e) { - Log::error($e); + return redirect()->route('admin.users.view', $id)->withErrors(json_decode($ex->getMessage())); + } catch (\Exception $ex) { + Log::error($ex); Alert::danger('An error occured while attempting to update this user.')->flash(); } - return redirect()->route('admin.users.view', $user); + return redirect()->route('admin.users.view', $id); } /** diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index 5619f26d5..902cebf15 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -114,7 +114,7 @@ class UserRepository * * @param int $id * @param array $data - * @return bool + * @return \Pterodactyl\Models\User * * @throws \Pterodactyl\Exceptions\DisplayValidationException */ @@ -147,9 +147,9 @@ class UserRepository unset($data['password']); } - $user->fill($data); + $user->fill($data)->save();; - return $user->save(); + return $user; } /** diff --git a/app/Transformers/Admin/LocationTransformer.php b/app/Transformers/Admin/LocationTransformer.php index 86980917b..0ef0e8875 100644 --- a/app/Transformers/Admin/LocationTransformer.php +++ b/app/Transformers/Admin/LocationTransformer.php @@ -79,7 +79,11 @@ class LocationTransformer extends TransformerAbstract */ public function includeServers(Location $location) { - return $this->collection($location->servers, new ServerTransformer, 'server'); + if ($this->request && ! $this->request->apiKeyHasPermission('server-list')) { + return; + } + + return $this->collection($location->servers, new ServerTransformer($this->request), 'server'); } /** @@ -89,6 +93,10 @@ class LocationTransformer extends TransformerAbstract */ public function includeNodes(Location $location) { - return $this->collection($location->nodes, new NodeTransformer, 'node'); + if ($this->request && ! $this->request->apiKeyHasPermission('location-list')) { + return; + } + + return $this->collection($location->nodes, new NodeTransformer($this->request), 'node'); } } diff --git a/app/Transformers/Admin/NodeTransformer.php b/app/Transformers/Admin/NodeTransformer.php index 5f55e425f..da49a17dd 100644 --- a/app/Transformers/Admin/NodeTransformer.php +++ b/app/Transformers/Admin/NodeTransformer.php @@ -84,7 +84,7 @@ class NodeTransformer extends TransformerAbstract return; } - return $this->collection($node->allocations, new AllocationTransformer, 'allocation'); + return $this->collection($node->allocations, new AllocationTransformer($this->request), 'allocation'); } /** @@ -98,7 +98,7 @@ class NodeTransformer extends TransformerAbstract return; } - return $this->item($node->location, new LocationTransformer, 'location'); + return $this->item($node->location, new LocationTransformer($this->request), 'location'); } /** @@ -112,6 +112,6 @@ class NodeTransformer extends TransformerAbstract return; } - return $this->collection($node->servers, new ServerTransformer, 'server'); + return $this->collection($node->servers, new ServerTransformer($this->request), 'server'); } } diff --git a/app/Transformers/Admin/OptionTransformer.php b/app/Transformers/Admin/OptionTransformer.php index 1d38b4a94..a5dd9a4b8 100644 --- a/app/Transformers/Admin/OptionTransformer.php +++ b/app/Transformers/Admin/OptionTransformer.php @@ -81,7 +81,11 @@ class OptionTransformer extends TransformerAbstract */ public function includeService(ServiceOption $option) { - return $this->item($option->service, new ServiceTransformer, 'service'); + if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { + return; + } + + return $this->item($option->service, new ServiceTransformer($this->request), 'service'); } /** @@ -91,7 +95,11 @@ class OptionTransformer extends TransformerAbstract */ public function includePacks(ServiceOption $option) { - return $this->collection($option->packs, new PackTransformer, 'pack'); + if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { + return; + } + + return $this->collection($option->packs, new PackTransformer($this->request), 'pack'); } /** @@ -101,7 +109,11 @@ class OptionTransformer extends TransformerAbstract */ public function includeServers(ServiceOption $option) { - return $this->collection($option->servers, new ServerTransformer, 'server'); + if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { + return; + } + + return $this->collection($option->servers, new ServerTransformer($this->request), 'server'); } /** @@ -111,6 +123,10 @@ class OptionTransformer extends TransformerAbstract */ public function includeVariables(ServiceOption $option) { - return $this->collection($option->variables, new ServiceVariableTransformer, 'variable'); + if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { + return; + } + + return $this->collection($option->variables, new ServiceVariableTransformer($this->request), 'variable'); } } diff --git a/app/Transformers/Admin/PackTransformer.php b/app/Transformers/Admin/PackTransformer.php index 50160744e..99603b6de 100644 --- a/app/Transformers/Admin/PackTransformer.php +++ b/app/Transformers/Admin/PackTransformer.php @@ -83,7 +83,11 @@ class PackTransformer extends TransformerAbstract */ public function includeOption(Pack $pack) { - return $this->item($pack->option, new OptionTransformer, 'option'); + if ($this->request && ! $this->request->apiKeyHasPermission('pack-view')) { + return; + } + + return $this->item($pack->option, new OptionTransformer($this->request), 'option'); } /** @@ -93,6 +97,10 @@ class PackTransformer extends TransformerAbstract */ public function includeServers(Pack $pack) { - return $this->collection($pack->servers, new ServerTransformer, 'server'); + if ($this->request && ! $this->request->apiKeyHasPermission('pack-view')) { + return; + } + + return $this->collection($pack->servers, new ServerTransformer($this->request), 'server'); } } diff --git a/app/Transformers/Admin/ServerTransformer.php b/app/Transformers/Admin/ServerTransformer.php index 23c754b5d..9bb23896c 100644 --- a/app/Transformers/Admin/ServerTransformer.php +++ b/app/Transformers/Admin/ServerTransformer.php @@ -86,6 +86,10 @@ class ServerTransformer extends TransformerAbstract */ public function includeAllocations(Server $server) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return $this->collection($server->allocations, new AllocationTransformer($this->request, 'server'), 'allocation'); } @@ -96,6 +100,10 @@ class ServerTransformer extends TransformerAbstract */ public function includeSubusers(Server $server) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return $this->collection($server->subusers, new SubuserTransformer($this->request), 'subuser'); } @@ -106,6 +114,10 @@ class ServerTransformer extends TransformerAbstract */ public function includeUser(Server $server) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return $this->item($server->user, new UserTransformer($this->request), 'user'); } @@ -116,6 +128,10 @@ class ServerTransformer extends TransformerAbstract */ public function includePack(Server $server) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return $this->item($server->pack, new PackTransformer($this->request), 'pack'); } @@ -126,6 +142,10 @@ class ServerTransformer extends TransformerAbstract */ public function includeService(Server $server) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return $this->item($server->service, new ServiceTransformer($this->request), 'service'); } @@ -136,6 +156,10 @@ class ServerTransformer extends TransformerAbstract */ public function includeOption(Server $server) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return $this->item($server->option, new OptionTransformer($this->request), 'option'); } @@ -146,6 +170,10 @@ class ServerTransformer extends TransformerAbstract */ public function includeVariables(Server $server) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return $this->collection($server->variables, new ServerVariableTransformer($this->request), 'server_variable'); } @@ -156,6 +184,10 @@ class ServerTransformer extends TransformerAbstract */ public function includeLocation(Server $server) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return $this->item($server->location, new LocationTransformer($this->request), 'location'); } @@ -166,6 +198,10 @@ class ServerTransformer extends TransformerAbstract */ public function includeNode(Server $server) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return $this->item($server->node, new NodeTransformer($this->request), 'node'); } } diff --git a/app/Transformers/Admin/ServerVariableTransformer.php b/app/Transformers/Admin/ServerVariableTransformer.php index 3521e0840..835ba41be 100644 --- a/app/Transformers/Admin/ServerVariableTransformer.php +++ b/app/Transformers/Admin/ServerVariableTransformer.php @@ -76,6 +76,10 @@ class ServerVariableTransformer extends TransformerAbstract */ public function includeParent(ServerVariable $variable) { - return $this->item($variable->variable, new ServiceVariableTransformer, 'variable'); + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + + return $this->item($variable->variable, new ServiceVariableTransformer($this->request), 'variable'); } } diff --git a/app/Transformers/Admin/ServiceTransformer.php b/app/Transformers/Admin/ServiceTransformer.php index 15e8859b2..61d544fa6 100644 --- a/app/Transformers/Admin/ServiceTransformer.php +++ b/app/Transformers/Admin/ServiceTransformer.php @@ -80,7 +80,11 @@ class ServiceTransformer extends TransformerAbstract */ public function includeOptions(Service $service) { - return $this->collection($service->options, new OptionTransformer, 'option'); + if ($this->request && ! $this->request->apiKeyHasPermission('service-view')) { + return; + } + + return $this->collection($service->options, new OptionTransformer($this->request), 'option'); } /** @@ -90,7 +94,11 @@ class ServiceTransformer extends TransformerAbstract */ public function includeServers(Service $service) { - return $this->collection($service->servers, new ServerTransformer, 'server'); + if ($this->request && ! $this->request->apiKeyHasPermission('service-view')) { + return; + } + + return $this->collection($service->servers, new ServerTransformer($this->request), 'server'); } /** @@ -100,6 +108,10 @@ class ServiceTransformer extends TransformerAbstract */ public function includePacks(Service $service) { - return $this->collection($service->packs, new PackTransformer, 'pack'); + if ($this->request && ! $this->request->apiKeyHasPermission('service-view')) { + return; + } + + return $this->collection($service->packs, new PackTransformer($this->request), 'pack'); } } diff --git a/app/Transformers/Admin/ServiceVariableTransformer.php b/app/Transformers/Admin/ServiceVariableTransformer.php index 9f87a1a81..c9105f68f 100644 --- a/app/Transformers/Admin/ServiceVariableTransformer.php +++ b/app/Transformers/Admin/ServiceVariableTransformer.php @@ -76,6 +76,10 @@ class ServiceVariableTransformer extends TransformerAbstract */ public function includeVariables(ServiceVariable $variable) { - return $this->collection($variable->serverVariable, new ServerVariableTransformer, 'server_variable'); + if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { + return; + } + + return $this->collection($variable->serverVariable, new ServerVariableTransformer($this->request), 'server_variable'); } } diff --git a/app/Transformers/Admin/SubuserTransformer.php b/app/Transformers/Admin/SubuserTransformer.php index ab95ceb27..129da7ad3 100644 --- a/app/Transformers/Admin/SubuserTransformer.php +++ b/app/Transformers/Admin/SubuserTransformer.php @@ -60,6 +60,10 @@ class SubuserTransformer extends TransformerAbstract */ public function transform(Subuser $subuser) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + return; + } + return [ 'id' => $subuser->id, 'username' => $subuser->user->username, diff --git a/app/Transformers/Admin/UserTransformer.php b/app/Transformers/Admin/UserTransformer.php index 95e5bef09..5349aa144 100644 --- a/app/Transformers/Admin/UserTransformer.php +++ b/app/Transformers/Admin/UserTransformer.php @@ -30,6 +30,16 @@ use League\Fractal\TransformerAbstract; class UserTransformer extends TransformerAbstract { + /** + * List of resources that can be included. + * + * @var array + */ + protected $availableIncludes = [ + 'access', + 'servers', + ]; + /** * The Illuminate Request object if provided. * @@ -61,4 +71,32 @@ class UserTransformer extends TransformerAbstract { return $user->toArray(); } + + /** + * Return the servers associated with this user. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeServers(User $user) + { + if ($this->request && ! $this->request->apiKeyHasPermission('user-view')) { + return; + } + + return $this->collection($user->servers, new ServerTransformer($this->request), 'server'); + } + + /** + * Return the servers that this user can access. + * + * @return \Leauge\Fractal\Resource\Collection + */ + public function includeAccess(User $user) + { + if ($this->request && ! $this->request->apiKeyHasPermission('user-view')) { + return; + } + + return $this->collection($user->access()->get(), new ServerTransformer($this->request), 'server'); + } } diff --git a/routes/api-admin.php b/routes/api-admin.php index ae7de6f09..d62510c94 100644 --- a/routes/api-admin.php +++ b/routes/api-admin.php @@ -74,4 +74,26 @@ Route::group(['prefix' => '/locations'], function () { Route::group(['prefix' => '/nodes'], function () { Route::get('/', 'NodeController@index'); Route::get('/{id}', 'NodeController@view'); + Route::get('/{id}/config', 'NodeController@viewConfig'); + + Route::post('/', 'NodeController@store'); + + Route::delete('/{id}', 'NodeController@delete'); +}); + +/* +|-------------------------------------------------------------------------- +| User Controller Routes +|-------------------------------------------------------------------------- +| +| Endpoint: /api/admin/users +| +*/ +Route::group(['prefix' => '/users'], function () { + Route::get('/', 'UserController@index'); + Route::get('/{id}', 'UserController@view'); + + Route::post('/', 'UserController@store'); + + Route::delete('/{id}', 'UserController@delete'); }); From a2a4ab05c88ff3e2e474db07edf32499f17e446f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 15:35:49 -0400 Subject: [PATCH 15/23] Corrected permissions to go with the more logical thought process --- app/Transformers/Admin/LocationTransformer.php | 2 +- app/Transformers/Admin/NodeTransformer.php | 2 +- app/Transformers/Admin/OptionTransformer.php | 6 +++--- app/Transformers/Admin/PackTransformer.php | 4 ++-- app/Transformers/Admin/ServerTransformer.php | 12 ++++++------ app/Transformers/Admin/ServerVariableTransformer.php | 2 +- app/Transformers/Admin/ServiceTransformer.php | 6 +++--- .../Admin/ServiceVariableTransformer.php | 2 +- app/Transformers/Admin/UserTransformer.php | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/Transformers/Admin/LocationTransformer.php b/app/Transformers/Admin/LocationTransformer.php index 0ef0e8875..f3fd95885 100644 --- a/app/Transformers/Admin/LocationTransformer.php +++ b/app/Transformers/Admin/LocationTransformer.php @@ -93,7 +93,7 @@ class LocationTransformer extends TransformerAbstract */ public function includeNodes(Location $location) { - if ($this->request && ! $this->request->apiKeyHasPermission('location-list')) { + if ($this->request && ! $this->request->apiKeyHasPermission('node-list')) { return; } diff --git a/app/Transformers/Admin/NodeTransformer.php b/app/Transformers/Admin/NodeTransformer.php index da49a17dd..672a05e79 100644 --- a/app/Transformers/Admin/NodeTransformer.php +++ b/app/Transformers/Admin/NodeTransformer.php @@ -94,7 +94,7 @@ class NodeTransformer extends TransformerAbstract */ public function includeLocation(Node $node) { - if ($this->request && ! $this->request->apiKeyHasPermission('node-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('location-view')) { return; } diff --git a/app/Transformers/Admin/OptionTransformer.php b/app/Transformers/Admin/OptionTransformer.php index a5dd9a4b8..5b86b53d6 100644 --- a/app/Transformers/Admin/OptionTransformer.php +++ b/app/Transformers/Admin/OptionTransformer.php @@ -81,7 +81,7 @@ class OptionTransformer extends TransformerAbstract */ public function includeService(ServiceOption $option) { - if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('service-view')) { return; } @@ -95,7 +95,7 @@ class OptionTransformer extends TransformerAbstract */ public function includePacks(ServiceOption $option) { - if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('pack-list')) { return; } @@ -109,7 +109,7 @@ class OptionTransformer extends TransformerAbstract */ public function includeServers(ServiceOption $option) { - if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-list')) { return; } diff --git a/app/Transformers/Admin/PackTransformer.php b/app/Transformers/Admin/PackTransformer.php index 99603b6de..8d059faaf 100644 --- a/app/Transformers/Admin/PackTransformer.php +++ b/app/Transformers/Admin/PackTransformer.php @@ -83,7 +83,7 @@ class PackTransformer extends TransformerAbstract */ public function includeOption(Pack $pack) { - if ($this->request && ! $this->request->apiKeyHasPermission('pack-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { return; } @@ -97,7 +97,7 @@ class PackTransformer extends TransformerAbstract */ public function includeServers(Pack $pack) { - if ($this->request && ! $this->request->apiKeyHasPermission('pack-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-list')) { return; } diff --git a/app/Transformers/Admin/ServerTransformer.php b/app/Transformers/Admin/ServerTransformer.php index 9bb23896c..366c3d63d 100644 --- a/app/Transformers/Admin/ServerTransformer.php +++ b/app/Transformers/Admin/ServerTransformer.php @@ -114,7 +114,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeUser(Server $server) { - if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('user-view')) { return; } @@ -128,7 +128,7 @@ class ServerTransformer extends TransformerAbstract */ public function includePack(Server $server) { - if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('pack-view')) { return; } @@ -142,7 +142,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeService(Server $server) { - if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('service-view')) { return; } @@ -156,7 +156,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeOption(Server $server) { - if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { return; } @@ -184,7 +184,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeLocation(Server $server) { - if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('location-view')) { return; } @@ -198,7 +198,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeNode(Server $server) { - if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('node-view')) { return; } diff --git a/app/Transformers/Admin/ServerVariableTransformer.php b/app/Transformers/Admin/ServerVariableTransformer.php index 835ba41be..3211e0295 100644 --- a/app/Transformers/Admin/ServerVariableTransformer.php +++ b/app/Transformers/Admin/ServerVariableTransformer.php @@ -76,7 +76,7 @@ class ServerVariableTransformer extends TransformerAbstract */ public function includeParent(ServerVariable $variable) { - if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { return; } diff --git a/app/Transformers/Admin/ServiceTransformer.php b/app/Transformers/Admin/ServiceTransformer.php index 61d544fa6..2df1fc8cc 100644 --- a/app/Transformers/Admin/ServiceTransformer.php +++ b/app/Transformers/Admin/ServiceTransformer.php @@ -80,7 +80,7 @@ class ServiceTransformer extends TransformerAbstract */ public function includeOptions(Service $service) { - if ($this->request && ! $this->request->apiKeyHasPermission('service-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('option-list')) { return; } @@ -94,7 +94,7 @@ class ServiceTransformer extends TransformerAbstract */ public function includeServers(Service $service) { - if ($this->request && ! $this->request->apiKeyHasPermission('service-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-list')) { return; } @@ -108,7 +108,7 @@ class ServiceTransformer extends TransformerAbstract */ public function includePacks(Service $service) { - if ($this->request && ! $this->request->apiKeyHasPermission('service-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('pack-list')) { return; } diff --git a/app/Transformers/Admin/ServiceVariableTransformer.php b/app/Transformers/Admin/ServiceVariableTransformer.php index c9105f68f..7f41a1079 100644 --- a/app/Transformers/Admin/ServiceVariableTransformer.php +++ b/app/Transformers/Admin/ServiceVariableTransformer.php @@ -76,7 +76,7 @@ class ServiceVariableTransformer extends TransformerAbstract */ public function includeVariables(ServiceVariable $variable) { - if ($this->request && ! $this->request->apiKeyHasPermission('option-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-view')) { return; } diff --git a/app/Transformers/Admin/UserTransformer.php b/app/Transformers/Admin/UserTransformer.php index 5349aa144..0d26961b9 100644 --- a/app/Transformers/Admin/UserTransformer.php +++ b/app/Transformers/Admin/UserTransformer.php @@ -79,7 +79,7 @@ class UserTransformer extends TransformerAbstract */ public function includeServers(User $user) { - if ($this->request && ! $this->request->apiKeyHasPermission('user-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-list')) { return; } @@ -93,7 +93,7 @@ class UserTransformer extends TransformerAbstract */ public function includeAccess(User $user) { - if ($this->request && ! $this->request->apiKeyHasPermission('user-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('server-list')) { return; } From f0c3f6f9b65d7263b48ff6017bbc21eb3f57affc Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 15:39:44 -0400 Subject: [PATCH 16/23] Fix location permission name --- app/Transformers/Admin/NodeTransformer.php | 2 +- app/Transformers/Admin/ServerTransformer.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Transformers/Admin/NodeTransformer.php b/app/Transformers/Admin/NodeTransformer.php index 672a05e79..d18b64f23 100644 --- a/app/Transformers/Admin/NodeTransformer.php +++ b/app/Transformers/Admin/NodeTransformer.php @@ -94,7 +94,7 @@ class NodeTransformer extends TransformerAbstract */ public function includeLocation(Node $node) { - if ($this->request && ! $this->request->apiKeyHasPermission('location-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('location-list')) { return; } diff --git a/app/Transformers/Admin/ServerTransformer.php b/app/Transformers/Admin/ServerTransformer.php index 366c3d63d..4d94b7e10 100644 --- a/app/Transformers/Admin/ServerTransformer.php +++ b/app/Transformers/Admin/ServerTransformer.php @@ -184,7 +184,7 @@ class ServerTransformer extends TransformerAbstract */ public function includeLocation(Server $server) { - if ($this->request && ! $this->request->apiKeyHasPermission('location-view')) { + if ($this->request && ! $this->request->apiKeyHasPermission('location-list')) { return; } From 69dfd380ad7ea358564e73460cbe4840761e6905 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 15:53:53 -0400 Subject: [PATCH 17/23] Finalize API routes --- .../API/Admin/ServerController.php | 1 + .../API/Admin/ServiceController.php | 74 +++++++++++++++++++ .../Controllers/API/Admin/UserController.php | 11 ++- routes/api-admin.php | 13 ++++ 4 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 app/Http/Controllers/API/Admin/ServiceController.php diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php index 7562e013d..111d33009 100644 --- a/app/Http/Controllers/API/Admin/ServerController.php +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -61,6 +61,7 @@ class ServerController extends Controller * Controller to handle returning information on a single server. * * @param \Illuminate\Http\Request $request + * @param int $id * @return array */ public function view(Request $request, $id) diff --git a/app/Http/Controllers/API/Admin/ServiceController.php b/app/Http/Controllers/API/Admin/ServiceController.php new file mode 100644 index 000000000..fbe911f14 --- /dev/null +++ b/app/Http/Controllers/API/Admin/ServiceController.php @@ -0,0 +1,74 @@ +. + * + * 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\Admin; + +use Fractal; +use Illuminate\Http\Request; +use Pterodactyl\Models\Service; +use Pterodactyl\Http\Controllers\Controller; +use Pterodactyl\Transformers\Admin\ServiceTransformer; + +class ServiceController extends Controller +{ + /** + * Controller to handle returning all locations on the system. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + public function index(Request $request) + { + $this->authorize('service-list', $request->apiKey()); + + return Fractal::create() + ->collection(Service::all()) + ->transformWith(new ServiceTransformer($request)) + ->withResourceName('service') + ->toArray(); + } + + /** + * Controller to handle returning information on a single server. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return array + */ + public function view(Request $request, $id) + { + $this->authorize('service-view', $request->apiKey()); + + $service = Service::findOrFail($id); + $fractal = Fractal::create()->item($service); + + if ($request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->transformWith(new ServiceTransformer($request)) + ->withResourceName('service') + ->toArray(); + } +} diff --git a/app/Http/Controllers/API/Admin/UserController.php b/app/Http/Controllers/API/Admin/UserController.php index 1f0dfb69a..5d7ffdf09 100644 --- a/app/Http/Controllers/API/Admin/UserController.php +++ b/app/Http/Controllers/API/Admin/UserController.php @@ -32,6 +32,7 @@ use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Repositories\UserRepository; use Pterodactyl\Transformers\Admin\UserTransformer; use Pterodactyl\Exceptions\DisplayValidationException; +use League\Fractal\Pagination\IlluminatePaginatorAdapter; class UserController extends Controller { @@ -44,14 +45,12 @@ class UserController extends Controller public function index(Request $request) { $this->authorize('user-list', $request->apiKey()); + $users = User::paginate(50); - $fractal = Fractal::create()->collection(User::all()); - if ($request->input('include')) { - $fractal->parseIncludes(explode(',', $request->input('include'))); - } - - return $fractal->transformWith(new UserTransformer($request)) + return Fractal::create()->collection($users) + ->transformWith(new UserTransformer($request)) ->withResourceName('user') + ->paginateWith(new IlluminatePaginatorAdapter($users)) ->toArray(); } diff --git a/routes/api-admin.php b/routes/api-admin.php index d62510c94..b4aff6c53 100644 --- a/routes/api-admin.php +++ b/routes/api-admin.php @@ -97,3 +97,16 @@ Route::group(['prefix' => '/users'], function () { Route::delete('/{id}', 'UserController@delete'); }); + +/* +|-------------------------------------------------------------------------- +| Service Controller Routes +|-------------------------------------------------------------------------- +| +| Endpoint: /api/admin/services +| +*/ +Route::group(['prefix' => '/services'], function () { + Route::get('/', 'ServiceController@index'); + Route::get('/{id}', 'ServiceController@view'); +}); From de8bbcd098db8593e782b9cb15b1937adb926996 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 16:04:08 -0400 Subject: [PATCH 18/23] Configuration for API pagination and includes on listing --- .../Controllers/API/Admin/NodeController.php | 14 +++++++++----- .../Controllers/API/Admin/ServerController.php | 17 ++++++++++------- .../Controllers/API/Admin/UserController.php | 13 +++++++++---- config/pterodactyl.php | 18 +++++++++++++++++- 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/app/Http/Controllers/API/Admin/NodeController.php b/app/Http/Controllers/API/Admin/NodeController.php index a88d5054b..655a7575d 100644 --- a/app/Http/Controllers/API/Admin/NodeController.php +++ b/app/Http/Controllers/API/Admin/NodeController.php @@ -32,6 +32,7 @@ use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Repositories\NodeRepository; use Pterodactyl\Transformers\Admin\NodeTransformer; use Pterodactyl\Exceptions\DisplayValidationException; +use League\Fractal\Pagination\IlluminatePaginatorAdapter; class NodeController extends Controller { @@ -45,14 +46,17 @@ class NodeController extends Controller { $this->authorize('node-list', $request->apiKey()); - $fractal = Fractal::create()->collection(Node::all()); - if ($request->input('include')) { + $nodes = Node::paginate(config('pterodactyl.paginate.api.nodes')); + $fractal = Fractal::create()->collection($nodes) + ->transformWith(new NodeTransformer($request)) + ->withResourceName('user') + ->paginateWith(new IlluminatePaginatorAdapter($nodes)); + + if (config('pterodactyl.api.allow_includes_on_list') && $request->input('include')) { $fractal->parseIncludes(explode(',', $request->input('include'))); } - return $fractal->transformWith(new NodeTransformer($request)) - ->withResourceName('node') - ->toArray(); + return $fractal->toArray(); } /** diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php index 111d33009..643e67296 100644 --- a/app/Http/Controllers/API/Admin/ServerController.php +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -47,14 +47,17 @@ class ServerController extends Controller { $this->authorize('server-list', $request->apiKey()); - $servers = Server::paginate(20); - - return Fractal::create() - ->collection($servers) + $servers = Server::paginate(config('pterodactyl.paginate.api.servers')); + $fractal = Fractal::create()->collection($servers) ->transformWith(new ServerTransformer($request)) - ->paginateWith(new IlluminatePaginatorAdapter($servers)) - ->withResourceName('server') - ->toArray(); + ->withResourceName('user') + ->paginateWith(new IlluminatePaginatorAdapter($servers)); + + if (config('pterodactyl.api.allow_includes_on_list') && $request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->toArray(); } /** diff --git a/app/Http/Controllers/API/Admin/UserController.php b/app/Http/Controllers/API/Admin/UserController.php index 5d7ffdf09..15af793d0 100644 --- a/app/Http/Controllers/API/Admin/UserController.php +++ b/app/Http/Controllers/API/Admin/UserController.php @@ -45,13 +45,18 @@ class UserController extends Controller public function index(Request $request) { $this->authorize('user-list', $request->apiKey()); - $users = User::paginate(50); - return Fractal::create()->collection($users) + $users = User::paginate(config('pterodactyl.paginate.api.users')); + $fractal = Fractal::create()->collection($users) ->transformWith(new UserTransformer($request)) ->withResourceName('user') - ->paginateWith(new IlluminatePaginatorAdapter($users)) - ->toArray(); + ->paginateWith(new IlluminatePaginatorAdapter($users)); + + if (config('pterodactyl.api.allow_includes_on_list') && $request->input('include')) { + $fractal->parseIncludes(explode(',', $request->input('include'))); + } + + return $fractal->toArray(); } /** diff --git a/config/pterodactyl.php b/config/pterodactyl.php index bbe93f4da..7d6916891 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -26,8 +26,24 @@ return [ */ 'paginate' => [ 'frontend' => [ - 'servers' => 15, + 'servers' => env('APP_PAGINATE_FRONT_SERVERS', 15), ], + 'api' => [ + 'nodes' => env('APP_PAGINATE_API_NODES', 25), + 'servers' => env('APP_PAGINATE_API_SERVERS', 25), + 'users' => env('APP_PAGINATE_API_USERS', 25), + ] + ], + + /* + |-------------------------------------------------------------------------- + | API Options + |-------------------------------------------------------------------------- + | + | Configuration options for the API. + */ + 'api' => [ + 'allow_includes_on_list' => env('API_ALLOW_INCLUDE_ON_LIST', false), ], /* From 87c09a921b955ed8c7d3ff2b8f62d5a7c6ba2bfa Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 16:05:18 -0400 Subject: [PATCH 19/23] More defined naming scheme for config --- app/Http/Controllers/API/Admin/NodeController.php | 2 +- app/Http/Controllers/API/Admin/ServerController.php | 2 +- app/Http/Controllers/API/Admin/UserController.php | 2 +- config/pterodactyl.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/API/Admin/NodeController.php b/app/Http/Controllers/API/Admin/NodeController.php index 655a7575d..4992638b2 100644 --- a/app/Http/Controllers/API/Admin/NodeController.php +++ b/app/Http/Controllers/API/Admin/NodeController.php @@ -52,7 +52,7 @@ class NodeController extends Controller ->withResourceName('user') ->paginateWith(new IlluminatePaginatorAdapter($nodes)); - if (config('pterodactyl.api.allow_includes_on_list') && $request->input('include')) { + if (config('pterodactyl.api.include_on_list') && $request->input('include')) { $fractal->parseIncludes(explode(',', $request->input('include'))); } diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php index 643e67296..8d1962822 100644 --- a/app/Http/Controllers/API/Admin/ServerController.php +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -53,7 +53,7 @@ class ServerController extends Controller ->withResourceName('user') ->paginateWith(new IlluminatePaginatorAdapter($servers)); - if (config('pterodactyl.api.allow_includes_on_list') && $request->input('include')) { + if (config('pterodactyl.api.include_on_list') && $request->input('include')) { $fractal->parseIncludes(explode(',', $request->input('include'))); } diff --git a/app/Http/Controllers/API/Admin/UserController.php b/app/Http/Controllers/API/Admin/UserController.php index 15af793d0..7268c263c 100644 --- a/app/Http/Controllers/API/Admin/UserController.php +++ b/app/Http/Controllers/API/Admin/UserController.php @@ -52,7 +52,7 @@ class UserController extends Controller ->withResourceName('user') ->paginateWith(new IlluminatePaginatorAdapter($users)); - if (config('pterodactyl.api.allow_includes_on_list') && $request->input('include')) { + if (config('pterodactyl.api.include_on_list') && $request->input('include')) { $fractal->parseIncludes(explode(',', $request->input('include'))); } diff --git a/config/pterodactyl.php b/config/pterodactyl.php index 7d6916891..f217e4c05 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -43,7 +43,7 @@ return [ | Configuration options for the API. */ 'api' => [ - 'allow_includes_on_list' => env('API_ALLOW_INCLUDE_ON_LIST', false), + 'include_on_list' => env('API_INCLUDE_ON_LIST', false), ], /* From 722fd614a147455b8cc67dff847f41529f8f561f Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 18:59:54 -0400 Subject: [PATCH 20/23] Add new dynamic view for creating API keys --- .../Controllers/API/User/CoreController.php | 2 +- .../Controllers/API/User/ServerController.php | 6 +- app/Http/Controllers/Base/APIController.php | 16 +- app/Models/APIPermission.php | 37 +- app/Policies/APIKeyPolicy.php | 5 + app/Repositories/APIRepository.php | 145 +++----- resources/lang/en/base.php | 262 ++++++++------ .../themes/pterodactyl/base/api/new.blade.php | 324 +++--------------- routes/api-admin.php | 2 + routes/base.php | 4 +- 10 files changed, 311 insertions(+), 492 deletions(-) diff --git a/app/Http/Controllers/API/User/CoreController.php b/app/Http/Controllers/API/User/CoreController.php index 926cb3a62..5c1d07406 100644 --- a/app/Http/Controllers/API/User/CoreController.php +++ b/app/Http/Controllers/API/User/CoreController.php @@ -39,7 +39,7 @@ class CoreController extends Controller */ public function index(Request $request) { - $this->authorize('user-server-list', $request->apiKey()); + $this->authorize('user.server-list', $request->apiKey()); $servers = $request->user()->access('service', 'node', 'allocation', 'option')->get(); diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index 32f18eb2f..4064ad8c1 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -43,7 +43,7 @@ class ServerController extends Controller */ public function index(Request $request, $uuid) { - $this->authorize('user-server-view', $request->apiKey()); + $this->authorize('user.server-view', $request->apiKey()); $server = Server::byUuid($uuid); $fractal = Fractal::create()->item($server); @@ -66,7 +66,7 @@ class ServerController extends Controller */ public function power(Request $request, $uuid) { - $this->authorize('user-server-power', $request->apiKey()); + $this->authorize('user.server-power', $request->apiKey()); $server = Server::byUuid($uuid); $request->user()->can('power-' . $request->input('action'), $server); @@ -86,7 +86,7 @@ class ServerController extends Controller */ public function command(Request $request, $uuid) { - $this->authorize('user-server-command', $request->apiKey()); + $this->authorize('user.server-command', $request->apiKey()); $server = Server::byUuid($uuid); $request->user()->can('send-command', $server); diff --git a/app/Http/Controllers/Base/APIController.php b/app/Http/Controllers/Base/APIController.php index bc0ce7be4..9c3816db3 100644 --- a/app/Http/Controllers/Base/APIController.php +++ b/app/Http/Controllers/Base/APIController.php @@ -27,8 +27,9 @@ namespace Pterodactyl\Http\Controllers\Base; use Log; use Alert; -use Pterodactyl\Models; use Illuminate\Http\Request; +use Pterodactyl\Models\APIKey; +use Pterodactyl\Models\APIPermission; use Pterodactyl\Repositories\APIRepository; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Http\Controllers\Controller; @@ -45,7 +46,7 @@ class APIController extends Controller public function index(Request $request) { return view('base.api.index', [ - 'keys' => Models\APIKey::where('user_id', $request->user()->id)->get(), + 'keys' => APIKey::where('user_id', $request->user()->id)->get(), ]); } @@ -57,7 +58,12 @@ class APIController extends Controller */ public function create(Request $request) { - return view('base.api.new'); + return view('base.api.new', [ + 'permissions' => [ + 'user' => collect(APIPermission::permissions())->pull('_user'), + 'admin' => collect(APIPermission::permissions())->except('_user')->toArray(), + ], + ]); } /** @@ -66,13 +72,13 @@ class APIController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\RedirectResponse */ - public function save(Request $request) + public function store(Request $request) { try { $repo = new APIRepository($request->user()); $secret = $repo->create($request->intersect([ 'memo', 'allowed_ips', - 'adminPermissions', 'permissions', + 'admin_permissions', 'permissions', ])); Alert::success('An API Key-Pair has successfully been generated. The API secret for this public key is shown below and will not be shown again.

' . $secret . '')->flash(); diff --git a/app/Models/APIPermission.php b/app/Models/APIPermission.php index 7450392d8..67eec35be 100644 --- a/app/Models/APIPermission.php +++ b/app/Models/APIPermission.php @@ -77,16 +77,45 @@ class APIPermission extends Model // All other pemissions below are administrative actions. 'server' => [ 'list', - 'view', - 'delete', 'create', + 'view', 'edit-details', 'edit-container', + 'edit-build', + 'edit-startup', 'suspend', 'install', 'rebuild', - 'edit-build', - 'edit-startup', + 'delete', + ], + 'location' => [ + 'list', + ], + 'node' => [ + 'list', + 'view', + 'view-config', + 'create', + 'delete', + ], + 'user' => [ + 'list', + 'view', + 'create', + 'edit', + 'delete', + ], + 'service' => [ + 'list', + 'view', + ], + 'option' => [ + 'list', + 'view', + ], + 'pack' => [ + 'list', + 'view', ], ]; diff --git a/app/Policies/APIKeyPolicy.php b/app/Policies/APIKeyPolicy.php index e946433e5..58b187b48 100644 --- a/app/Policies/APIKeyPolicy.php +++ b/app/Policies/APIKeyPolicy.php @@ -42,6 +42,11 @@ class APIKeyPolicy */ protected function checkPermission(User $user, Key $key, $permission) { + // Non-administrative users cannot use administrative routes. + if (! starts_with('user.') && ! $user->isRootAdmin()) { + return false; + } + // We don't tag this cache key with the user uuid because the key is already unique, // and multiple users are not defiend for a single key. $permissions = Cache::remember('APIKeyPolicy.' . $key->public, Carbon::now()->addSeconds(5), function () use ($key) { diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index ff2c15c87..561266c3f 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -29,65 +29,14 @@ use Auth; use Crypt; use Validator; use IPTools\Network; -use Pterodactyl\Models; +use Pterodactyl\Models\User; +use Pterodactyl\Models\APIKey as Key; +use Pterodactyl\Models\APIPermission as Permission; use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayValidationException; class APIRepository { - /** - * Valid API permissions. - * - * @var array - */ - protected $permissions = [ - 'admin' => [ - '*', - - // User Management Routes - 'users.list', - 'users.create', - 'users.view', - 'users.update', - 'users.delete', - - // Server Manaement Routes - 'servers.list', - 'servers.create', - 'servers.view', - 'servers.config', - 'servers.build', - 'servers.suspend', - 'servers.unsuspend', - 'servers.delete', - - // Node Management Routes - 'nodes.list', - 'nodes.view', - 'nodes.create', - 'nodes.allocations', - 'nodes.delete', - - // Service Routes - 'services.list', - 'services.view', - - // Location Routes - 'locations.list', - - ], - 'user' => [ - '*', - - // Informational - 'me', - - // Server Control - 'server', - 'server.power', - ], - ]; - /** * Holder for listing of allowed IPs when creating a new key. * @@ -108,11 +57,11 @@ class APIRepository * @param null|\Pterodactyl\Models\User $user * @return void */ - public function __construct(Models\User $user = null) + public function __construct(User $user = null) { $this->user = is_null($user) ? Auth::user() : $user; if (is_null($this->user)) { - throw new \Exception('Cannot access API Repository without passing a user to constructor.'); + throw new \Exception('Unable to initialize user for API repository instance.'); } } @@ -129,8 +78,9 @@ class APIRepository { $validator = Validator::make($data, [ 'memo' => 'string|max:500', + 'allowed_ips' => 'sometimes|string', 'permissions' => 'sometimes|required|array', - 'adminPermissions' => 'sometimes|required|array', + 'admin_permissions' => 'sometimes|required|array', ]); $validator->after(function ($validator) use ($data) { @@ -156,8 +106,7 @@ class APIRepository DB::beginTransaction(); try { $secretKey = str_random(16) . '.' . str_random(7) . '.' . str_random(7); - $key = new Models\APIKey; - $key->fill([ + $key = Key::create([ 'user_id' => $this->user->id, 'public' => str_random(16), 'secret' => Crypt::encrypt($secretKey), @@ -165,44 +114,61 @@ class APIRepository 'memo' => $data['memo'], 'expires_at' => null, ]); - $key->save(); $totalPermissions = 0; + $pNodes = Permission::permissions(); + if (isset($data['permissions'])) { - foreach ($data['permissions'] as $permNode) { - if (! strpos($permNode, ':')) { + foreach ($data['permissions'] as $permission) { + $parts = explode('-', $permission); + + if (count($parts) !== 2) { continue; } - list($toss, $permission) = explode(':', $permNode); - if (in_array($permission, $this->permissions['user'])) { - $totalPermissions++; - $model = new Models\APIPermission; - $model->fill([ - 'key_id' => $key->id, - 'permission' => 'api.user.' . $permission, - ]); - $model->save(); + list($block, $search) = $parts; + + if (! array_key_exists($block, $pNodes['_user'])) { + continue; } + + if (! in_array($search, $pNodes['_user'][$block])) { + continue; + } + + $totalPermissions++; + Permission::create([ + 'key_id' => $key->id, + 'permission' => 'user.' . $permission, + ]); } } - if ($this->user->isRootAdmin() && isset($data['adminPermissions'])) { - foreach ($data['adminPermissions'] as $permNode) { - if (! strpos($permNode, ':')) { + if ($this->user->isRootAdmin() && isset($data['admin_permissions'])) { + unset($pNodes['_user']); + + foreach ($data['admin_permissions'] as $permNode) { + $parts = explode('-', $permission); + + if (count($parts) !== 2) { continue; } - list($toss, $permission) = explode(':', $permNode); - if (in_array($permission, $this->permissions['admin'])) { - $totalPermissions++; - $model = new Models\APIPermission; - $model->fill([ - 'key_id' => $key->id, - 'permission' => 'api.admin.' . $permission, - ]); - $model->save(); + list($block, $search) = $parts; + + if (! array_key_exists($block, $pNodes)) { + continue; } + + if (! in_array($search, $pNodes[$block])) { + continue; + } + + $totalPermissions++; + Permission::create([ + 'key_id' => $key->id, + 'permission' => $permission, + ]); } } @@ -229,20 +195,13 @@ class APIRepository */ public function revoke($key) { - DB::beginTransaction(); - - try { - $model = Models\APIKey::with('permissions')->where('public', $key)->where('user_id', $this->user->id)->firstOrFail(); + DB::transaction(function () use ($key) { + $model = Key::with('permissions')->where('public', $key)->where('user_id', $this->user->id)->firstOrFail(); foreach ($model->permissions as &$permission) { $permission->delete(); } $model->delete(); - - DB::commit(); - } catch (\Exception $ex) { - DB::rollBack(); - throw $ex; - } + }); } } diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php index 5d1a18cb2..ca5aa923c 100644 --- a/resources/lang/en/base.php +++ b/resources/lang/en/base.php @@ -46,122 +46,162 @@ return [ 'title' => 'Allowed IPs', 'description' => 'Enter a line delimitated list of IPs that are allowed to access the API using this key. CIDR notation is allowed. Leave blank to allow any IP.', ], - 'base' => [ - 'title' => 'Base Information', - 'information' => [ - 'title' => 'Base Information', - 'description' => 'Returns a listing of all servers that this account has access to.', - ], - ], - 'user_management' => [ - 'title' => 'User Management', - 'list' => [ - 'title' => 'List Users', - 'description' => 'Allows listing of all users currently on the system.', - ], - 'create' => [ - 'title' => 'Create User', - 'description' => 'Allows creating a new user on the system.', - ], - 'view' => [ - 'title' => 'List Single User', - 'description' => 'Allows viewing details about a specific user including active services.', - ], - 'update' => [ - 'title' => 'Update User', - 'description' => 'Allows modifying user details (email, password, TOTP information).', - ], - 'delete' => [ - 'title' => 'Delete User', - 'description' => 'Allows deleting a user.', - ], - ], - 'node_management' => [ - 'title' => 'Node Management', - 'list' => [ - 'title' => 'List Nodes', - 'description' => 'Allows listing of all nodes currently on the system.', - ], - 'create' => [ - 'title' => 'Create Node', - 'description' => 'Allows creating a new node on the system.', - ], - 'view' => [ - 'title' => 'List Single Node', - 'description' => 'Allows viewing details about a specific node including active services.', - ], - 'allocations' => [ - 'title' => 'List Allocations', - 'description' => 'Allows viewing all allocations on the panel for all nodes.', - ], - 'delete' => [ - 'title' => 'Delete Node', - 'description' => 'Allows deleting a node.', - ], - ], - 'server_management' => [ - 'title' => 'Server Management', + ], + 'permissions' => [ + 'user' => [ + 'server_header' => 'User Server Permissions', 'server' => [ - 'title' => 'Server Info', - 'description' => 'Allows access to viewing information about a single server including current stats and allocations.', - ], - 'power' => [ - 'title' => 'Server Power', - 'description' => 'Allows access to control server power status.', - ], - 'command' => [ - 'title' => 'Send Command', - 'description' => 'Allows a user to send a command to a specified server.', - ], - 'view' => [ - 'title' => 'Show Single Server', - 'description' => 'Allows viewing details about a specific server including the daemon_token as well as current process information.', - ], - 'list' => [ - 'title' => 'List Servers', - 'description' => 'Allows listing of all servers currently on the system.', - ], - 'create' => [ - 'title' => 'Create Server', - 'description' => 'Allows creating a new server on the system.', - ], - 'config' => [ - 'title' => 'Update Configuration', - 'description' => 'Allows modifying server config (name, owner, and access token).', - ], - 'build' => [ - 'title' => 'Update Build', - 'description' => 'Allows modifying a server\'s build parameters such as memory, CPU, and disk space along with assigned and default IPs.', - ], - 'suspend' => [ - 'title' => 'Suspend Server', - 'description' => 'Allows suspending a server instance.', - ], - 'unsuspend' => [ - 'title' => 'Unsuspend Server', - 'description' => 'Allows unsuspending a server instance.', - ], - 'delete' => [ - 'title' => 'Delete Server', - 'description' => 'Allows deleting a server.', + 'list' => [ + 'title' => 'List Servers', + 'desc' => 'Allows listing of all servers a user owns or has access to as a subuser.', + ], + 'view' => [ + 'title' => 'View Server', + 'desc'=> 'Allows viewing of specific server user can access.', + ], + 'power' => [ + 'title' => 'Toggle Power', + 'desc'=> 'Allow toggling of power status for a server.', + ], + 'command' => [ + 'title' => 'Send Command', + 'desc'=> 'Allow sending of a command to a running server.', + ], ], ], - 'service_management' => [ - 'title' => 'Service Management', - 'list' => [ - 'title' => 'List Services', - 'description' => 'Allows listing of all services configured on the system.', + 'admin' => [ + 'server_header' => 'Server Control', + 'server' => [ + 'list' => [ + 'title' => 'List Servers', + 'desc' => 'Allows listing of all servers currently on the system.', + ], + 'view' => [ + 'title' => 'View Server', + 'desc' => 'Allows view of single server including service and details.', + ], + 'delete' => [ + 'title' => 'Delete Server', + 'desc' => 'Allows deletion of a server from the system.', + ], + 'create' => [ + 'title' => 'Create Server', + 'desc' => 'Allows creation of a new server on the system.', + ], + 'edit-details' => [ + 'title' => 'Edit Server Details', + 'desc' => 'Allows editing of server details such as name, owner, description, and secret key.', + ], + 'edit-container' => [ + 'title' => 'Edit Server Container', + 'desc' => 'Allows for modification of the docker container the server runs in.', + ], + 'suspend' => [ + 'title' => 'Suspend Server', + 'desc' => 'Allows for the suspension and unsuspension of a given server.', + ], + 'install' => [ + 'title' => 'Toggle Install Status', + 'desc' => '', + ], + 'rebuild' => [ + 'title' => 'Rebuild Server', + 'desc' => '', + ], + 'edit-build' => [ + 'title' => 'Edit Server Build', + 'desc' => 'Allows editing of server build setting such as CPU and memory allocations.', + ], + 'edit-startup' => [ + 'title' => 'Edit Server Startup', + 'desc' => 'Allows modification of server startup commands and parameters.', + ], ], - 'view' => [ - 'title' => 'List Single Service', - 'description' => 'Allows listing details about each service on the system including service options and variables.', + 'location_header' => 'Location Control', + 'location' => [ + 'list' => [ + 'title' => 'List Locations', + 'desc' => 'Allows listing all locations and thier associated nodes.', + ], ], - ], - 'location_management' => [ - 'title' => 'Location Management', - 'list' => [ - 'title' => 'List Locations', - 'description' => 'Allows listing all locations and thier associated nodes.', + 'node_header' => 'Node Control', + 'node' => [ + 'list' => [ + 'title' => 'List Nodes', + 'desc' => 'Allows listing of all nodes currently on the system.', + ], + 'view' => [ + 'title' => 'View Node', + 'desc' => 'llows viewing details about a specific node including active services.', + ], + 'view-config' => [ + 'title' => 'View Node Configuration', + 'desc' => 'Danger. This allows the viewing of the node configuration file used by the daemon, and exposes secret daemon tokens.', + ], + 'create' => [ + 'title' => 'Create Node', + 'desc' => 'Allows creating a new node on the system.', + ], + 'delete' => [ + 'title' => 'Delete Node', + 'desc' => 'Allows deletion of a node from the system.', + ], + ], + 'user_header' => 'User Control', + 'user' => [ + 'list' => [ + 'title' => 'List Users', + 'desc' => 'Allows listing of all users currently on the system.', + ], + 'view' => [ + 'title' => 'View User', + 'desc' => 'Allows viewing details about a specific user including active services.', + ], + 'create' => [ + 'title' => 'Create User', + 'desc' => 'Allows creating a new user on the system.', + ], + 'edit' => [ + 'title' => 'Update User', + 'desc' => 'Allows modification of user details.', + ], + 'delete' => [ + 'title' => 'Delete User', + 'desc' => 'Allows deleting a user.', + ], + ], + 'service_header' => 'Service Control', + 'service' => [ + 'list' => [ + 'title' => 'List Services', + 'desc' => 'Allows listing of all services configured on the system.', + ], + 'view' => [ + 'title' => 'View Service', + 'desc' => 'Allows listing details about each service on the system including service options and variables.', + ], + ], + 'option_header' => 'Option Control', + 'option' => [ + 'list' => [ + 'title' => 'List Options', + 'desc' => '', + ], + 'view' => [ + 'title' => 'View Option', + 'desc' => '', + ], + ], + 'pack_header' => 'Pack Control', + 'pack' => [ + 'list' => [ + 'title' => 'List Packs', + 'desc' => '', + ], + 'view' => [ + 'title' => 'View Pack', + 'desc' => '', + ], ], ], ], diff --git a/resources/themes/pterodactyl/base/api/new.blade.php b/resources/themes/pterodactyl/base/api/new.blade.php index be972d67a..8f8c90a22 100644 --- a/resources/themes/pterodactyl/base/api/new.blade.php +++ b/resources/themes/pterodactyl/base/api/new.blade.php @@ -47,8 +47,8 @@ @endsection @section('content') -
-
+ +
@@ -75,292 +75,70 @@
+ {!! csrf_field() !!}
-
-
-
-
-
-
@lang('base.api.new.base.title')
-
-
-
-
- - -
-

@lang('base.api.new.base.information.description')

+
+
+ @foreach($permissions['user'] as $block => $perms) +
+
+
+

@lang('base.api.permissions.user.' . $block . '_header')

+
+
+ @foreach($perms as $permission) +
+
+ + +
+

@lang('base.api.permissions.user.' . $block . '.' . $permission . '.desc')

+
+ @endforeach
- @if(Auth::user()->isRootAdmin()) -
-
-
@lang('base.api.new.user_management.title')
-
-
-
-
- - -
-

@lang('base.api.new.user_management.list.description')

-
-
-
- - -
-

@lang('base.api.new.user_management.create.description')

-
-
-
- - -
-

@lang('base.api.new.user_management.view.description')

-
-
-
- - -
-

@lang('base.api.new.user_management.update.description')

-
-
-
- - -
-

@lang('base.api.new.user_management.delete.description')

-
-
-
-
-
-
@lang('base.api.new.node_management.title')
-
-
-
-
- - -
-

@lang('base.api.new.node_management.list.description')

-
-
-
- - -
-

@lang('base.api.new.node_management.create.description')

-
-
-
- - -
-

@lang('base.api.new.node_management.view.description')

-
-
-
- - -
-

@lang('base.api.new.node_management.allocations.description')

-
-
-
- - -
-

@lang('base.api.new.node_management.delete.description')

-
-
-
-
-
-
@lang('base.api.new.location_management.title')
-
-
-
-
- - -
-

@lang('base.api.new.location_management.list.description')

-
-
-
+ @if ($loop->iteration % 2 === 0) +
@endif -
-
-
-
-
@lang('base.api.new.server_management.title')
-
-
-
-
- - -
-

@lang('base.api.new.server_management.server.description')

-
-
-
- - -
-

@lang('base.api.new.server_management.power.description')

-
-
-
- - -
-

@lang('base.api.new.server_management.command.description')

-
- @if(Auth::user()->isRootAdmin()) -
-
- - -
-

@lang('base.api.new.server_management.view.description')

-
-
-
- - -
-

@lang('base.api.new.server_management.list.description')

-
-
-
- - -
-

@lang('base.api.new.server_management.create.description')

-
-
-
- - -
-

@lang('base.api.new.server_management.config.description')

-
-
-
- - -
-

@lang('base.api.new.server_management.build.description')

-
-
-
- - -
-

@lang('base.api.new.server_management.suspend.description')

-
-
-
- - -
-

@lang('base.api.new.server_management.unsuspend.description')

-
-
-
- - -
-

@lang('base.api.new.server_management.delete.description')

-
- @endif -
-
- @if(Auth::user()->isRootAdmin()) -
+ @endforeach +
+
+ @foreach($permissions['admin'] as $block => $perms) +
+
-
@lang('base.api.new.service_management.title')
+

@lang('base.api.permissions.admin.' . $block . '_header')

-
-
- - + @foreach($perms as $permission) +
+
+ + +
+

@lang('base.api.permissions.admin.' . $block . '.' . $permission . '.desc')

-

@lang('base.api.new.service_management.list.description')

-
-
-
- - -
-

@lang('base.api.new.service_management.view.description')

-
+ @endforeach
+
+ @if ($loop->iteration % 3 === 0) +
@endif -
- {!! csrf_field() !!} - -
+ @if ($loop->iteration % 2 === 0) +
+ @endif + @endforeach +
+ @endsection diff --git a/routes/api-admin.php b/routes/api-admin.php index b4aff6c53..fcd0a0a70 100644 --- a/routes/api-admin.php +++ b/routes/api-admin.php @@ -95,6 +95,8 @@ Route::group(['prefix' => '/users'], function () { Route::post('/', 'UserController@store'); + Route::put('/{id}', 'UserController@update'); + Route::delete('/{id}', 'UserController@delete'); }); diff --git a/routes/base.php b/routes/base.php index cea722192..e63f5b43b 100644 --- a/routes/base.php +++ b/routes/base.php @@ -51,9 +51,9 @@ Route::group(['prefix' => 'account'], function () { */ Route::group(['prefix' => 'account/api'], function () { Route::get('/', 'APIController@index')->name('account.api'); - Route::get('/new', 'APIController@new')->name('account.api.new'); + Route::get('/new', 'APIController@create')->name('account.api.new'); - Route::post('/new', 'APIController@save'); + Route::post('/new', 'APIController@store'); Route::delete('/revoke/{key}', 'APIController@revoke')->name('account.api.revoke'); }); From 1e43f2049bdc18f5f2970e271322970eb1ad66b7 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 19:13:22 -0400 Subject: [PATCH 21/23] Fix up routes and controller names --- .../Controllers/Admin/NodesController.php | 4 +-- .../Controllers/Admin/OptionController.php | 4 +-- app/Http/Controllers/Admin/PackController.php | 4 +-- .../Controllers/Admin/ServersController.php | 6 ++-- .../Controllers/Admin/ServiceController.php | 4 +-- app/Http/Controllers/Admin/UserController.php | 14 ++++---- .../Controllers/Server/SubuserController.php | 12 +++---- .../Controllers/Server/TaskController.php | 10 +++--- routes/admin.php | 36 +++++++++---------- routes/server.php | 24 ++++++------- 10 files changed, 58 insertions(+), 60 deletions(-) diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 0c895fe15..1300b9643 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -60,7 +60,7 @@ class NodesController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View|\Illuminate\Http\RedirectResponse */ - public function new(Request $request) + public function create(Request $request) { $locations = Models\Location::all(); if (! $locations->count()) { @@ -78,7 +78,7 @@ class NodesController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\RedirectResponse */ - public function create(Request $request) + public function store(Request $request) { try { $repo = new NodeRepository; diff --git a/app/Http/Controllers/Admin/OptionController.php b/app/Http/Controllers/Admin/OptionController.php index 4dfe34321..d4f383a92 100644 --- a/app/Http/Controllers/Admin/OptionController.php +++ b/app/Http/Controllers/Admin/OptionController.php @@ -44,7 +44,7 @@ class OptionController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View */ - public function new(Request $request) + public function create(Request $request) { $services = Service::with('options')->get(); Javascript::put(['services' => $services->keyBy('id')]); @@ -58,7 +58,7 @@ class OptionController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\Response\RedirectResponse */ - public function create(Request $request) + public function store(Request $request) { $repo = new OptionRepository; diff --git a/app/Http/Controllers/Admin/PackController.php b/app/Http/Controllers/Admin/PackController.php index 14d248dc8..d02273672 100644 --- a/app/Http/Controllers/Admin/PackController.php +++ b/app/Http/Controllers/Admin/PackController.php @@ -60,7 +60,7 @@ class PackController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View */ - public function new(Request $request) + public function create(Request $request) { return view('admin.packs.new', [ 'services' => Service::with('options')->get(), @@ -86,7 +86,7 @@ class PackController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View */ - public function create(Request $request) + public function store(Request $request) { $repo = new PackRepository; diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php index 1016f802c..85bc1a4db 100644 --- a/app/Http/Controllers/Admin/ServersController.php +++ b/app/Http/Controllers/Admin/ServersController.php @@ -63,7 +63,7 @@ class ServersController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View */ - public function new(Request $request) + public function create(Request $request) { $services = Models\Service::with('options.packs', 'options.variables')->get(); Javascript::put([ @@ -86,7 +86,7 @@ class ServersController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\Response\RedirectResponse */ - public function create(Request $request) + public function store(Request $request) { try { $repo = new ServerRepository; @@ -114,7 +114,7 @@ class ServersController extends Controller * @param \Illuminate\Http\Request $request * @return array */ - public function newServerNodes(Request $request) + public function nodes(Request $request) { $nodes = Models\Node::with('allocations')->where('location_id', $request->input('location'))->get(); diff --git a/app/Http/Controllers/Admin/ServiceController.php b/app/Http/Controllers/Admin/ServiceController.php index 2e63e5306..beaac5340 100644 --- a/app/Http/Controllers/Admin/ServiceController.php +++ b/app/Http/Controllers/Admin/ServiceController.php @@ -54,7 +54,7 @@ class ServiceController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View */ - public function new(Request $request) + public function create(Request $request) { return view('admin.services.new'); } @@ -91,7 +91,7 @@ class ServiceController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\RedirectResponse */ - public function create(Request $request) + public function store(Request $request) { $repo = new ServiceRepository; diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index f7324456b..238f2e1e2 100644 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -42,7 +42,7 @@ class UserController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View */ - public function getIndex(Request $request) + public function index(Request $request) { $users = User::withCount('servers'); @@ -61,7 +61,7 @@ class UserController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\View\View */ - public function getNew(Request $request) + public function create(Request $request) { return view('admin.users.new'); } @@ -73,7 +73,7 @@ class UserController extends Controller * @param int $id * @return \Illuminate\View\View */ - public function getView(Request $request, $id) + public function view(Request $request, $id) { return view('admin.users.view', [ 'user' => User::with('servers.node')->findOrFail($id), @@ -87,7 +87,7 @@ class UserController extends Controller * @param int $id * @return \Illuminate\Http\RedirectResponse */ - public function deleteUser(Request $request, $id) + public function delete(Request $request, $id) { try { $repo = new UserRepository; @@ -111,7 +111,7 @@ class UserController extends Controller * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\RedirectResponse */ - public function postNew(Request $request) + public function store(Request $request) { try { $user = new UserRepository; @@ -139,7 +139,7 @@ class UserController extends Controller * @param int $id * @return \Illuminate\Http\RedirectResponse */ - public function updateUser(Request $request, $id) + public function update(Request $request, $id) { try { $repo = new UserRepository; @@ -164,7 +164,7 @@ class UserController extends Controller * @param \Illuminate\Http\Request $request * @return \Pterodactyl\Models\User */ - public function getJson(Request $request) + public function json(Request $request) { return User::select('id', 'email', 'username', 'name_first', 'name_last') ->search($request->input('q')) diff --git a/app/Http/Controllers/Server/SubuserController.php b/app/Http/Controllers/Server/SubuserController.php index 3caba0e0e..c0c15f29d 100644 --- a/app/Http/Controllers/Server/SubuserController.php +++ b/app/Http/Controllers/Server/SubuserController.php @@ -43,7 +43,7 @@ class SubuserController extends Controller * @param string $uuid * @return \Illuminate\View\View */ - public function getIndex(Request $request, $uuid) + public function index(Request $request, $uuid) { $server = Models\Server::byUuid($uuid)->load('subusers.user'); $this->authorize('list-subusers', $server); @@ -65,7 +65,7 @@ class SubuserController extends Controller * @param int $id * @return \Illuminate\View\View */ - public function getView(Request $request, $uuid, $id) + public function view(Request $request, $uuid, $id) { $server = Models\Server::byUuid($uuid)->load('node'); $this->authorize('view-subuser', $server); @@ -94,7 +94,7 @@ class SubuserController extends Controller * @param int $id * @return \Illuminate\Http\RedirectResponse */ - public function postView(Request $request, $uuid, $id) + public function update(Request $request, $uuid, $id) { $server = Models\Server::byUuid($uuid); $this->authorize('edit-subuser', $server); @@ -139,7 +139,7 @@ class SubuserController extends Controller * @param string $uuid * @return \Illuminate\View\View */ - public function getNew(Request $request, $uuid) + public function create(Request $request, $uuid) { $server = Models\Server::byUuid($uuid); $this->authorize('create-subuser', $server); @@ -159,7 +159,7 @@ class SubuserController extends Controller * @param string $uuid * @return \Illuminate\Http\RedirectResponse */ - public function postNew(Request $request, $uuid) + public function store(Request $request, $uuid) { $server = Models\Server::byUuid($uuid); $this->authorize('create-subuser', $server); @@ -195,7 +195,7 @@ class SubuserController extends Controller * @param int $id * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response */ - public function deleteSubuser(Request $request, $uuid, $id) + public function delete(Request $request, $uuid, $id) { $server = Models\Server::byUuid($uuid); $this->authorize('delete-subuser', $server); diff --git a/app/Http/Controllers/Server/TaskController.php b/app/Http/Controllers/Server/TaskController.php index 1ddc3eac2..1bd7f3244 100644 --- a/app/Http/Controllers/Server/TaskController.php +++ b/app/Http/Controllers/Server/TaskController.php @@ -42,7 +42,7 @@ class TaskController extends Controller * @param string $uuid * @return \Illuminate\View\View */ - public function getIndex(Request $request, $uuid) + public function index(Request $request, $uuid) { $server = Models\Server::byUuid($uuid)->load('tasks'); $this->authorize('list-tasks', $server); @@ -66,7 +66,7 @@ class TaskController extends Controller * @param string $uuid * @return \Illuminate\View\View */ - public function getNew(Request $request, $uuid) + public function create(Request $request, $uuid) { $server = Models\Server::byUuid($uuid); $this->authorize('create-task', $server); @@ -85,7 +85,7 @@ class TaskController extends Controller * @param string $uuid * @return \Illuminate\Http\RedirectResponse */ - public function postNew(Request $request, $uuid) + public function store(Request $request, $uuid) { $server = Models\Server::byUuid($uuid); $this->authorize('create-task', $server); @@ -117,7 +117,7 @@ class TaskController extends Controller * @param int $id * @return \Illuminate\Http\JsonResponse */ - public function deleteTask(Request $request, $uuid, $id) + public function delete(Request $request, $uuid, $id) { $server = Models\Server::byUuid($uuid)->load('tasks'); $this->authorize('delete-task', $server); @@ -151,7 +151,7 @@ class TaskController extends Controller * @param int $id * @return \Illuminate\Http\JsonResponse */ - public function toggleTask(Request $request, $uuid, $id) + public function toggle(Request $request, $uuid, $id) { $server = Models\Server::byUuid($uuid)->load('tasks'); $this->authorize('toggle-task', $server); diff --git a/routes/admin.php b/routes/admin.php index a940c8617..96fa47256 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -79,15 +79,15 @@ Route::group(['prefix' => 'settings'], function () { | */ Route::group(['prefix' => 'users'], function () { - Route::get('/', 'UserController@getIndex')->name('admin.users'); - Route::get('/accounts.json', 'UserController@getJson')->name('admin.users.json'); - Route::get('/new', 'UserController@getNew')->name('admin.users.new'); - Route::get('/view/{id}', 'UserController@getView')->name('admin.users.view'); + Route::get('/', 'UserController@index')->name('admin.users'); + Route::get('/accounts.json', 'UserController@json')->name('admin.users.json'); + Route::get('/new', 'UserController@create')->name('admin.users.new'); + Route::get('/view/{id}', 'UserController@view')->name('admin.users.view'); - Route::post('/new', 'UserController@postNew'); - Route::post('/view/{id}', 'UserController@updateUser'); + Route::post('/new', 'UserController@store'); + Route::post('/view/{id}', 'UserController@update'); - Route::delete('/view/{id}', 'UserController@deleteUser'); + Route::delete('/view/{id}', 'UserController@delete'); }); /* @@ -100,8 +100,8 @@ Route::group(['prefix' => 'users'], function () { */ Route::group(['prefix' => 'servers'], function () { Route::get('/', 'ServersController@index')->name('admin.servers'); - Route::get('/new', 'ServersController@new')->name('admin.servers.new'); - Route::get('/new/nodes', 'ServersController@newServerNodes')->name('admin.servers.new.nodes'); + Route::get('/new', 'ServersController@create')->name('admin.servers.new'); + Route::get('/new/nodes', 'ServersController@nodes')->name('admin.servers.new.nodes'); Route::get('/view/{id}', 'ServersController@viewIndex')->name('admin.servers.view'); Route::get('/view/{id}/details', 'ServersController@viewDetails')->name('admin.servers.view.details'); Route::get('/view/{id}/build', 'ServersController@viewBuild')->name('admin.servers.view.build'); @@ -110,7 +110,7 @@ Route::group(['prefix' => 'servers'], function () { Route::get('/view/{id}/manage', 'ServersController@viewManage')->name('admin.servers.view.manage'); Route::get('/view/{id}/delete', 'ServersController@viewDelete')->name('admin.servers.view.delete'); - Route::post('/new', 'ServersController@create'); + Route::post('/new', 'ServersController@store'); Route::post('/view/{id}/details', 'ServersController@setDetails'); Route::post('/view/{id}/details/container', 'ServersController@setContainer')->name('admin.servers.view.details.container'); Route::post('/view/{id}/build', 'ServersController@updateBuild'); @@ -136,7 +136,7 @@ Route::group(['prefix' => 'servers'], function () { */ Route::group(['prefix' => 'nodes'], function () { Route::get('/', 'NodesController@index')->name('admin.nodes'); - Route::get('/new', 'NodesController@new')->name('admin.nodes.new'); + Route::get('/new', 'NodesController@create')->name('admin.nodes.new'); Route::get('/view/{id}', 'NodesController@viewIndex')->name('admin.nodes.view'); Route::get('/view/{id}/settings', 'NodesController@viewSettings')->name('admin.nodes.view.settings'); Route::get('/view/{id}/configuration', 'NodesController@viewConfiguration')->name('admin.nodes.view.configuration'); @@ -144,7 +144,7 @@ Route::group(['prefix' => 'nodes'], function () { Route::get('/view/{id}/servers', 'NodesController@viewServers')->name('admin.nodes.view.servers'); Route::get('/view/{id}/settings/token', 'NodesController@setToken')->name('admin.nodes.view.configuration.token'); - Route::post('/new', 'NodesController@create'); + Route::post('/new', 'NodesController@store'); Route::post('/view/{id}/settings', 'NodesController@updateSettings'); Route::post('/view/{id}/allocation', 'NodesController@createAllocation'); Route::post('/view/{id}/allocation/remove', 'NodesController@allocationRemoveBlock')->name('admin.nodes.view.allocation.removeBlock'); @@ -164,16 +164,16 @@ Route::group(['prefix' => 'nodes'], function () { */ Route::group(['prefix' => 'services'], function () { Route::get('/', 'ServiceController@index')->name('admin.services'); - Route::get('/new', 'ServiceController@new')->name('admin.services.new'); + Route::get('/new', 'ServiceController@create')->name('admin.services.new'); Route::get('/view/{id}', 'ServiceController@view')->name('admin.services.view'); Route::get('/view/{id}/functions', 'ServiceController@viewFunctions')->name('admin.services.view.functions'); - Route::get('/option/new', 'OptionController@new')->name('admin.services.option.new'); + Route::get('/option/new', 'OptionController@create')->name('admin.services.option.new'); Route::get('/option/{id}', 'OptionController@viewConfiguration')->name('admin.services.option.view'); Route::get('/option/{id}/variables', 'OptionController@viewVariables')->name('admin.services.option.variables'); - Route::post('/new', 'ServiceController@create'); + Route::post('/new', 'ServiceController@store'); Route::post('/view/{id}', 'ServiceController@edit'); - Route::post('/option/new', 'OptionController@new'); + Route::post('/option/new', 'OptionController@store'); Route::post('/option/{id}', 'OptionController@editConfiguration'); Route::post('/option/{id}/variables', 'OptionController@createVariable'); Route::post('/option/{id}/variables/{variable}', 'OptionController@editVariable')->name('admin.services.option.variables.edit'); @@ -191,11 +191,11 @@ Route::group(['prefix' => 'services'], function () { */ Route::group(['prefix' => 'packs'], function () { Route::get('/', 'PackController@index')->name('admin.packs'); - Route::get('/new', 'PackController@new')->name('admin.packs.new'); + Route::get('/new', 'PackController@create')->name('admin.packs.new'); Route::get('/new/template', 'PackController@newTemplate')->name('admin.packs.new.template'); Route::get('/view/{id}', 'PackController@view')->name('admin.packs.view'); - Route::post('/new', 'PackController@create'); + Route::post('/new', 'PackController@store'); Route::post('/view/{id}', 'PackController@update'); Route::post('/view/{id}/export/{files?}', 'PackController@export')->name('admin.packs.view.export'); }); diff --git a/routes/server.php b/routes/server.php index cf46054cb..75fc56c7d 100644 --- a/routes/server.php +++ b/routes/server.php @@ -71,14 +71,14 @@ Route::group(['prefix' => 'files'], function () { | */ Route::group(['prefix' => 'users'], function () { - Route::get('/', 'SubuserController@getIndex')->name('server.subusers'); - Route::get('/new', 'SubuserController@getNew')->name('server.subusers.new'); - Route::get('/view/{id}', 'SubuserController@getView')->name('server.subusers.view'); + Route::get('/', 'SubuserController@index')->name('server.subusers'); + Route::get('/new', 'SubuserController@create')->name('server.subusers.new'); + Route::get('/view/{id}', 'SubuserController@view')->name('server.subusers.view'); - Route::post('/new', 'SubuserController@postNew'); - Route::post('/view/{id}', 'SubuserController@postView'); + Route::post('/new', 'SubuserController@store'); + Route::post('/view/{id}', 'SubuserController@update'); - Route::delete('/delete/{id}', 'SubuserController@deleteSubuser')->name('server.subusers.delete'); + Route::delete('/delete/{id}', 'SubuserController@delete')->name('server.subusers.delete'); }); /* @@ -90,15 +90,13 @@ Route::group(['prefix' => 'users'], function () { | */ Route::group(['prefix' => 'tasks'], function () { - Route::get('/', 'TaskController@getIndex')->name('server.tasks'); - Route::get('/new', 'TaskController@getNew')->name('server.tasks.new'); - Route::get('/view/{id}', 'TaskController@getView')->name('server.tasks.view'); + Route::get('/', 'TaskController@index')->name('server.tasks'); + Route::get('/new', 'TaskController@create')->name('server.tasks.new'); - Route::post('/new', 'TaskController@postNew'); - Route::post('/view/{id}', 'SubuserController@postView'); - Route::post('/toggle/{id}', 'TaskController@toggleTask')->name('server.tasks.toggle'); + Route::post('/new', 'TaskController@store'); + Route::post('/toggle/{id}', 'TaskController@toggle')->name('server.tasks.toggle'); - Route::delete('/delete/{id}', 'TaskController@deleteTask')->name('server.tasks.delete'); + Route::delete('/delete/{id}', 'TaskController@delete')->name('server.tasks.delete'); }); /* From 7bd14db6465ed22e6f8d7aebbcbdbafca82a13f8 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 19:15:20 -0400 Subject: [PATCH 22/23] Update changelog before PR --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4e652519..7d7b219cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ This project follows [Semantic Versioning](http://semver.org) guidelines. * Attempting to reset a password for an account that does not exist no longer returns an error, rather it displays a success message. Failed resets trigger a `Pterodactyl\Events\Auth\FailedPasswordReset` event that can be caught if needed to perform other actions. * Servers are no longer queued for deletion due to the general hassle and extra logic required. * Updated all panel components to run on Laravel v5.4 rather than 5.3 which is EOL. +* Routes are now handled in the `routes/` folder, and use a significantly cleaner syntax. Controller names and methods have been updated as well to be clearer as well as avoid conflicts with PHP reserved keywords. +* API has been completely overhauled to use new permissions system. **Any old API keys will immediately become invalid and fail to operate properly anymore. You will need to generate new keys.** ## v0.6.0-pre.7 (Courageous Carniadactylus) ### Fixed From 93d79994f808e566359d06ab3f5ad9dd3e9f43e2 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 9 Apr 2017 19:16:39 -0400 Subject: [PATCH 23/23] Apply fixes from StyleCI (#372) --- app/Exceptions/Handler.php | 1 - .../Controllers/API/Admin/NodeController.php | 4 +++- .../Controllers/API/Admin/ServerController.php | 17 ++++++++++++++++- .../Controllers/API/Admin/UserController.php | 5 ++++- .../Controllers/API/User/ServerController.php | 3 +-- app/Http/Middleware/CheckServer.php | 4 ++-- app/Http/Middleware/HMACAuthorization.php | 13 +++++++------ app/Models/APIPermission.php | 4 ++-- app/Models/Server.php | 3 ++- app/Providers/MacroServiceProvider.php | 4 ++-- app/Repositories/APIRepository.php | 2 +- app/Repositories/UserRepository.php | 2 +- .../Admin/ServiceVariableTransformer.php | 2 +- config/pterodactyl.php | 2 +- routes/admin.php | 1 - routes/api-admin.php | 2 -- routes/api.php | 1 - routes/auth.php | 1 - routes/base.php | 1 - routes/daemon.php | 1 - routes/remote.php | 1 - routes/server.php | 1 - 22 files changed, 43 insertions(+), 32 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 22d79a952..71d66cdc6 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -4,7 +4,6 @@ namespace Pterodactyl\Exceptions; use Log; use Exception; -use DisplayException; use Illuminate\Auth\AuthenticationException; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; diff --git a/app/Http/Controllers/API/Admin/NodeController.php b/app/Http/Controllers/API/Admin/NodeController.php index 4992638b2..d70e89969 100644 --- a/app/Http/Controllers/API/Admin/NodeController.php +++ b/app/Http/Controllers/API/Admin/NodeController.php @@ -27,8 +27,8 @@ namespace Pterodactyl\Http\Controllers\API\Admin; use Fractal; use Illuminate\Http\Request; use Pterodactyl\Models\Node; -use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Repositories\NodeRepository; use Pterodactyl\Transformers\Admin\NodeTransformer; use Pterodactyl\Exceptions\DisplayValidationException; @@ -135,6 +135,7 @@ class NodeController extends Controller ], 400); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to create this node. Please try again.', ], 500); @@ -163,6 +164,7 @@ class NodeController extends Controller ], 400); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to delete this node. Please try again.', ], 500); diff --git a/app/Http/Controllers/API/Admin/ServerController.php b/app/Http/Controllers/API/Admin/ServerController.php index 8d1962822..89dfd8cd0 100644 --- a/app/Http/Controllers/API/Admin/ServerController.php +++ b/app/Http/Controllers/API/Admin/ServerController.php @@ -113,11 +113,13 @@ class ServerController extends Controller ], 400); } catch (TransferException $ex) { Log::warning($ex); + return response()->json([ 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', ], 504); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to add this server. Please try again.', ], 500); @@ -146,18 +148,20 @@ class ServerController extends Controller ], 400); } catch (TransferException $ex) { Log::warning($ex); + return response()->json([ 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', ], 504); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to add this server. Please try again.', ], 500); } } - /** + /** * Update the details for a server. * * @param \Illuminate\Http\Request $request @@ -190,6 +194,7 @@ class ServerController extends Controller ], 400); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to modify this server. Please try again.', ], 500); @@ -223,11 +228,13 @@ class ServerController extends Controller ], 400); } catch (TransferException $ex) { Log::warning($ex); + return response()->json([ 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', ], 504); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to modify this server container. Please try again.', ], 500); @@ -256,6 +263,7 @@ class ServerController extends Controller ], 400); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to toggle the install status for this server. Please try again.', ], 500); @@ -283,6 +291,7 @@ class ServerController extends Controller return response('', 204); } catch (TransferException $ex) { Log::warning($ex); + return response()->json([ 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', ], 504); @@ -318,11 +327,13 @@ class ServerController extends Controller ], 400); } catch (TransferException $ex) { Log::warning($ex); + return response()->json([ 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', ], 504); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to ' . $action . ' this server. Please try again.', ], 500); @@ -363,11 +374,13 @@ class ServerController extends Controller ], 400); } catch (TransferException $ex) { Log::warning($ex); + return response()->json([ 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', ], 504); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to modify the build settings for this server. Please try again.', ], 500); @@ -400,11 +413,13 @@ class ServerController extends Controller ], 400); } catch (TransferException $ex) { Log::warning($ex); + return response()->json([ 'error' => 'A TransferException was encountered while trying to contact the daemon, please ensure it is online and accessible. This error has been logged.', ], 504); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to modify the startup settings for this server. Please try again.', ], 500); diff --git a/app/Http/Controllers/API/Admin/UserController.php b/app/Http/Controllers/API/Admin/UserController.php index 7268c263c..150ca4f87 100644 --- a/app/Http/Controllers/API/Admin/UserController.php +++ b/app/Http/Controllers/API/Admin/UserController.php @@ -27,8 +27,8 @@ namespace Pterodactyl\Http\Controllers\API\Admin; use Fractal; use Illuminate\Http\Request; use Pterodactyl\Models\User; -use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Http\Controllers\Controller; use Pterodactyl\Repositories\UserRepository; use Pterodactyl\Transformers\Admin\UserTransformer; use Pterodactyl\Exceptions\DisplayValidationException; @@ -109,6 +109,7 @@ class UserController extends Controller ], 400); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to create this user. Please try again.', ], 500); @@ -145,6 +146,7 @@ class UserController extends Controller ], 400); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to update this user. Please try again.', ], 500); @@ -173,6 +175,7 @@ class UserController extends Controller ], 400); } catch (\Exception $ex) { Log::error($ex); + return response()->json([ 'error' => 'An unhandled exception occured while attemping to delete this user. Please try again.', ], 500); diff --git a/app/Http/Controllers/API/User/ServerController.php b/app/Http/Controllers/API/User/ServerController.php index 4064ad8c1..1c5399cf9 100644 --- a/app/Http/Controllers/API/User/ServerController.php +++ b/app/Http/Controllers/API/User/ServerController.php @@ -27,10 +27,9 @@ namespace Pterodactyl\Http\Controllers\API\User; use Fractal; use Illuminate\Http\Request; use Pterodactyl\Models\Server; -use GuzzleHttp\Exception\ConnectException; use Pterodactyl\Http\Controllers\Controller; -use Pterodactyl\Transformers\User\ServerTransformer; use Pterodactyl\Repositories\Daemon\PowerRepository; +use Pterodactyl\Transformers\User\ServerTransformer; class ServerController extends Controller { diff --git a/app/Http/Middleware/CheckServer.php b/app/Http/Middleware/CheckServer.php index a913b87ea..4cfe08191 100644 --- a/app/Http/Middleware/CheckServer.php +++ b/app/Http/Middleware/CheckServer.php @@ -64,7 +64,7 @@ class CheckServer $this->request = $request; $this->server = Server::byUuid($request->route()->server); - if(! $this->exists()) { + if (! $this->exists()) { return response()->view('errors.404', [], 404); } @@ -124,6 +124,6 @@ class CheckServer } } - return ($this->server->installed === 1); + return $this->server->installed === 1; } } diff --git a/app/Http/Middleware/HMACAuthorization.php b/app/Http/Middleware/HMACAuthorization.php index 7b4e84b7f..2c08c1449 100644 --- a/app/Http/Middleware/HMACAuthorization.php +++ b/app/Http/Middleware/HMACAuthorization.php @@ -28,13 +28,11 @@ use Auth; use Crypt; use Config; use Closure; -use Response; use Debugbar; use IPTools\IP; use IPTools\Range; use Illuminate\Http\Request; use Pterodactyl\Models\APIKey; -use Pterodactyl\Models\APIPermission; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; // 400 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; // 403 @@ -150,7 +148,7 @@ class HMACAuthorization protected function validateIPAccess() { if (! is_null($this->key()->allowed_ips)) { - foreach($this->key()->allowed_ips as $ip) { + foreach ($this->key()->allowed_ips as $ip) { if (Range::parse($ip)->contains(new IP($this->request()->ip()))) { return true; } @@ -194,7 +192,8 @@ class HMACAuthorization * * @return string */ - protected function public() { + protected function public() + { return $this->token['public']; } @@ -203,7 +202,8 @@ class HMACAuthorization * * @return string */ - protected function hash() { + protected function hash() + { return $this->token['hash']; } @@ -212,7 +212,8 @@ class HMACAuthorization * * @return \Pterodactyl\Models\APIKey */ - protected function key() { + protected function key() + { return $this->key; } diff --git a/app/Models/APIPermission.php b/app/Models/APIPermission.php index 67eec35be..bfe2fc908 100644 --- a/app/Models/APIPermission.php +++ b/app/Models/APIPermission.php @@ -71,7 +71,7 @@ class APIPermission extends Model 'view', 'power', 'command', - ] + ], ], // All other pemissions below are administrative actions. @@ -120,7 +120,7 @@ class APIPermission extends Model ]; /** - * Return permissions for API + * Return permissions for API. * * @return array */ diff --git a/app/Models/Server.php b/app/Models/Server.php index 18c86c157..8a3725ed6 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -209,7 +209,8 @@ class Server extends Model * * @return array */ - public function getTableColumns() { + public function getTableColumns() + { return Schema::getColumnListing($this->getTable()); } diff --git a/app/Providers/MacroServiceProvider.php b/app/Providers/MacroServiceProvider.php index 980634dd6..8dd08f73b 100644 --- a/app/Providers/MacroServiceProvider.php +++ b/app/Providers/MacroServiceProvider.php @@ -66,7 +66,7 @@ class MacroServiceProvider extends ServiceProvider return Cache::tags([ 'ApiKeyMacro', 'ApiKeyMacro:Key:' . $parts[0], - ])->remember('ApiKeyMacro.' . $parts[0], Carbon::now()->addMinutes(15), function() use ($parts) { + ])->remember('ApiKeyMacro.' . $parts[0], Carbon::now()->addMinutes(15), function () use ($parts) { return APIKey::where('public', $parts[0])->first(); }); } @@ -74,7 +74,7 @@ class MacroServiceProvider extends ServiceProvider return false; }); - Request::macro('apiKeyHasPermission', function($permission) { + Request::macro('apiKeyHasPermission', function ($permission) { $key = Request::apiKey(); if (! $key) { return false; diff --git a/app/Repositories/APIRepository.php b/app/Repositories/APIRepository.php index 561266c3f..db9b9d6b7 100644 --- a/app/Repositories/APIRepository.php +++ b/app/Repositories/APIRepository.php @@ -31,8 +31,8 @@ use Validator; use IPTools\Network; use Pterodactyl\Models\User; use Pterodactyl\Models\APIKey as Key; -use Pterodactyl\Models\APIPermission as Permission; use Pterodactyl\Exceptions\DisplayException; +use Pterodactyl\Models\APIPermission as Permission; use Pterodactyl\Exceptions\DisplayValidationException; class APIRepository diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php index 902cebf15..b2ddaeadd 100644 --- a/app/Repositories/UserRepository.php +++ b/app/Repositories/UserRepository.php @@ -147,7 +147,7 @@ class UserRepository unset($data['password']); } - $user->fill($data)->save();; + $user->fill($data)->save(); return $user; } diff --git a/app/Transformers/Admin/ServiceVariableTransformer.php b/app/Transformers/Admin/ServiceVariableTransformer.php index 7f41a1079..aa10428d9 100644 --- a/app/Transformers/Admin/ServiceVariableTransformer.php +++ b/app/Transformers/Admin/ServiceVariableTransformer.php @@ -25,8 +25,8 @@ namespace Pterodactyl\Transformers\Admin; use Illuminate\Http\Request; -use Pterodactyl\Models\ServiceVariable; use League\Fractal\TransformerAbstract; +use Pterodactyl\Models\ServiceVariable; class ServiceVariableTransformer extends TransformerAbstract { diff --git a/config/pterodactyl.php b/config/pterodactyl.php index f217e4c05..dc3f3072c 100644 --- a/config/pterodactyl.php +++ b/config/pterodactyl.php @@ -32,7 +32,7 @@ return [ 'nodes' => env('APP_PAGINATE_API_NODES', 25), 'servers' => env('APP_PAGINATE_API_SERVERS', 25), 'users' => env('APP_PAGINATE_API_USERS', 25), - ] + ], ], /* diff --git a/routes/admin.php b/routes/admin.php index 96fa47256..36b8e6239 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - Route::get('/', 'BaseController@getIndex')->name('admin.index'); /* diff --git a/routes/api-admin.php b/routes/api-admin.php index fcd0a0a70..d5ca5b0b3 100644 --- a/routes/api-admin.php +++ b/routes/api-admin.php @@ -21,10 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - Route::get('/', 'CoreController@index'); - /* |-------------------------------------------------------------------------- | Server Controller Routes diff --git a/routes/api.php b/routes/api.php index 88a9d5ee7..9b2e01dfa 100644 --- a/routes/api.php +++ b/routes/api.php @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - Route::get('/', 'CoreController@index')->name('api.user'); /* diff --git a/routes/auth.php b/routes/auth.php index 2d0ae392b..46de5a1b5 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - Route::get('/logout', 'LoginController@logout')->name('auth.logout')->middleware('auth'); Route::get('/login', 'LoginController@showLoginForm')->name('auth.login'); Route::get('/login/totp', 'LoginController@totp')->name('auth.totp'); diff --git a/routes/base.php b/routes/base.php index e63f5b43b..e13e1284a 100644 --- a/routes/base.php +++ b/routes/base.php @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - Route::get('/', 'IndexController@getIndex')->name('index'); Route::get('/index', function () { redirect()->route('index'); diff --git a/routes/daemon.php b/routes/daemon.php index 5a1fc35c9..78edf308f 100644 --- a/routes/daemon.php +++ b/routes/daemon.php @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - Route::get('/services', 'ServiceController@list')->name('daemon.services'); Route::get('/services/pull/{service}/{file}', 'ServiceController@pull')->name('daemon.pull'); Route::get('/packs/pull/{uuid}', 'PackController@pull')->name('daemon.pack.pull'); diff --git a/routes/remote.php b/routes/remote.php index c592ad325..d7fe471c5 100644 --- a/routes/remote.php +++ b/routes/remote.php @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - Route::get('/configuration/{token}', 'RemoteController@getConfiguration')->name('remote.configuration'); Route::post('/download', 'RemoteController@postDownload')->name('remote.download'); diff --git a/routes/server.php b/routes/server.php index 75fc56c7d..953eab2b2 100644 --- a/routes/server.php +++ b/routes/server.php @@ -21,7 +21,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - Route::get('/', 'ServerController@getIndex')->name('server.index'); /*