diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 3b6966064..1d33e210d 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -19,6 +19,7 @@ use Pterodactyl\Http\Middleware\AccessingValidServer; use Illuminate\View\Middleware\ShareErrorsFromSession; use Pterodactyl\Http\Middleware\RedirectIfAuthenticated; use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth; +use Pterodactyl\Http\Middleware\Api\ApiSubstituteBindings; use Illuminate\Foundation\Http\Middleware\ValidatePostSize; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Pterodactyl\Http\Middleware\Server\AuthenticateAsSubuser; @@ -68,7 +69,7 @@ class Kernel extends HttpKernel ], 'api' => [ 'throttle:120,1', - SubstituteBindings::class, + ApiSubstituteBindings::class, SetSessionDriver::class, AuthenticateKey::class, AuthenticateUser::class, diff --git a/app/Http/Middleware/Api/ApiSubstituteBindings.php b/app/Http/Middleware/Api/ApiSubstituteBindings.php new file mode 100644 index 000000000..430d4597b --- /dev/null +++ b/app/Http/Middleware/Api/ApiSubstituteBindings.php @@ -0,0 +1,70 @@ +route(); + + $this->router->substituteBindings($route); + $this->resolveForRoute($route); + + return $next($request); + } + + /** + * Resolve the implicit route bindings for the given route. This function + * overrides Laravel's default inn \Illuminate\Routing\ImplictRouteBinding + * to not throw a 404 error when a model is not found. + * + * If a model is not found using the provided information, the binding is + * replaced with null which is then checked in the form requests on API + * routes. This avoids a potential imformation leak on API routes for + * unauthenticated users. + * + * @param \Illuminate\Routing\Route $route + */ + protected function resolveForRoute($route) + { + $parameters = $route->parameters(); + + // Avoid having to copy and paste the entirety of that class into this middleware + // by using reflection to access a protected method. + $reflection = new ReflectionMethod(ImplicitRouteBinding::class, 'getParameterName'); + $reflection->setAccessible(true); + + foreach ($route->signatureParameters(UrlRoutable::class) as $parameter) { + if (! $parameterName = $reflection->invokeArgs(null, [$parameter->name, $parameters])) { + continue; + } + + $parameterValue = $parameters[$parameterName]; + + if ($parameterValue instanceof UrlRoutable) { + continue; + } + + // Try to find an existing model, if one is not found simply bind the + // parameter as null. + $instance = Container::getInstance()->make($parameter->getClass()->name); + $route->setParameter($parameterName, $instance->resolveRouteBinding($parameterValue)); + } + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 130b7ba72..f9f6ac31d 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -16,14 +16,6 @@ class RouteServiceProvider extends ServiceProvider */ protected $namespace = 'Pterodactyl\Http\Controllers'; - /** - * Define your route model bindings, pattern filters, etc. - */ - public function boot() - { - parent::boot(); - } - /** * Define the routes for the application. */ diff --git a/routes/api-application.php b/routes/api-application.php index f6d2577c0..83ea5a2a0 100644 --- a/routes/api-application.php +++ b/routes/api-application.php @@ -1,11 +1,5 @@ '/users'], function () { - Route::bind('user', function ($value) { - return User::find($value) ?? new User; - }); - Route::get('/', 'Users\UserController@index')->name('api.application.users'); Route::get('/{user}', 'Users\UserController@view')->name('api.applications.users.view'); @@ -37,10 +27,6 @@ Route::group(['prefix' => '/users'], function () { | */ Route::group(['prefix' => '/nodes'], function () { - Route::bind('node', function ($value) { - return Node::find($value) ?? new Node; - }); - Route::get('/', 'Nodes\NodeController@index')->name('api.application.nodes'); Route::get('/{node}', 'Nodes\NodeController@view')->name('api.application.nodes.view'); @@ -50,10 +36,6 @@ Route::group(['prefix' => '/nodes'], function () { Route::delete('/{node}', 'Nodes\NodeController@delete'); Route::group(['prefix' => '/{node}/allocations'], function () { - Route::bind('allocation', function ($value) { - return Allocation::find($value) ?? new Allocation; - }); - Route::get('/', 'Nodes\AllocationController@index')->name('api.application.allocations'); Route::delete('/{allocation}', 'Nodes\AllocationController@delete')->name('api.application.allocations.view'); @@ -69,10 +51,6 @@ Route::group(['prefix' => '/nodes'], function () { | */ Route::group(['prefix' => '/locations'], function () { - Route::bind('location', function ($value) { - return Location::find($value) ?? new Location; - }); - Route::get('/', 'Locations\LocationController@index')->name('api.applications.locations'); Route::get('/{location}', 'Locations\LocationController@view')->name('api.application.locations.view'); @@ -91,10 +69,6 @@ Route::group(['prefix' => '/locations'], function () { | */ Route::group(['prefix' => '/servers'], function () { - Route::bind('server', function ($value) { - return Server::find($value) ?? new Server; - }); - Route::get('/', 'Servers\ServerController@index')->name('api.application.servers'); Route::get('/{server}', 'Servers\ServerController@view')->name('api.application.servers.view');