Skip to content

Commit 45a1534

Browse files
committed
Add new API middleware
1 parent 47e14cc commit 45a1534

File tree

5 files changed

+144
-19
lines changed

5 files changed

+144
-19
lines changed

app/Http/Kernel.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@
1111
use Pterodactyl\Http\Middleware\VerifyCsrfToken;
1212
use Pterodactyl\Http\Middleware\VerifyReCaptcha;
1313
use Pterodactyl\Http\Middleware\AdminAuthenticate;
14-
use Pterodactyl\Http\Middleware\HMACAuthorization;
1514
use Illuminate\Routing\Middleware\ThrottleRequests;
1615
use Pterodactyl\Http\Middleware\LanguageMiddleware;
1716
use Illuminate\Foundation\Http\Kernel as HttpKernel;
17+
use Pterodactyl\Http\Middleware\API\AuthenticateKey;
1818
use Illuminate\Routing\Middleware\SubstituteBindings;
1919
use Pterodactyl\Http\Middleware\AccessingValidServer;
20+
use Pterodactyl\Http\Middleware\API\SetSessionDriver;
2021
use Illuminate\View\Middleware\ShareErrorsFromSession;
2122
use Pterodactyl\Http\Middleware\RedirectIfAuthenticated;
2223
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
24+
use Pterodactyl\Http\Middleware\API\AuthenticateIPAccess;
2325
use Pterodactyl\Http\Middleware\Daemon\DaemonAuthenticate;
2426
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
2527
use Pterodactyl\Http\Middleware\Server\AuthenticateAsSubuser;
@@ -42,10 +44,6 @@ class Kernel extends HttpKernel
4244
EncryptCookies::class,
4345
AddQueuedCookiesToResponse::class,
4446
TrimStrings::class,
45-
46-
/*
47-
* Custom middleware applied to all routes.
48-
*/
4947
TrustProxies::class,
5048
];
5149

@@ -66,9 +64,11 @@ class Kernel extends HttpKernel
6664
RequireTwoFactorAuthentication::class,
6765
],
6866
'api' => [
69-
HMACAuthorization::class,
7067
'throttle:60,1',
71-
'bindings',
68+
SubstituteBindings::class,
69+
SetSessionDriver::class,
70+
AuthenticateKey::class,
71+
AuthenticateIPAccess::class,
7272
],
7373
'daemon' => [
7474
SubstituteBindings::class,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Middleware\API;
4+
5+
use Closure;
6+
use IPTools\IP;
7+
use IPTools\Range;
8+
use Illuminate\Http\Request;
9+
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
10+
11+
class AuthenticateIPAccess
12+
{
13+
/**
14+
* Determine if a request IP has permission to access the API.
15+
*
16+
* @param \Illuminate\Http\Request $request
17+
* @param \Closure $next
18+
* @return mixed
19+
*
20+
* @throws \Exception
21+
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
22+
*/
23+
public function handle(Request $request, Closure $next)
24+
{
25+
$model = $request->attributes->get('api_key');
26+
27+
if (is_null($model->allowed_ips) || empty($model->allowed_ips)) {
28+
return $next($request);
29+
}
30+
31+
foreach ($model->allowed_ips as $ip) {
32+
if (Range::parse($ip)->contains(new IP($request->ip()))) {
33+
return $next($request);
34+
}
35+
}
36+
37+
throw new AccessDeniedHttpException('This IP address does not have permission to access the API using these credentials.');
38+
}
39+
}

app/Http/Middleware/API/AuthenticateKey.php

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,25 @@
44

55
use Closure;
66
use Illuminate\Http\Request;
7+
use Illuminate\Auth\AuthManager;
8+
use Symfony\Component\HttpKernel\Exception\HttpException;
9+
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
10+
use Illuminate\Contracts\Config\Repository as ConfigRepository;
711
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
12+
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
813

914
class AuthenticateKey
1015
{
16+
/**
17+
* @var \Illuminate\Auth\AuthManager
18+
*/
19+
private $auth;
20+
21+
/**
22+
* @var \Illuminate\Contracts\Config\Repository
23+
*/
24+
private $config;
25+
1126
/**
1227
* @var \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface
1328
*/
@@ -17,9 +32,16 @@ class AuthenticateKey
1732
* AuthenticateKey constructor.
1833
*
1934
* @param \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface $repository
35+
* @param \Illuminate\Auth\AuthManager $auth
36+
* @param \Illuminate\Contracts\Config\Repository $config
2037
*/
21-
public function __construct(ApiKeyRepositoryInterface $repository)
22-
{
38+
public function __construct(
39+
ApiKeyRepositoryInterface $repository,
40+
AuthManager $auth,
41+
ConfigRepository $config
42+
) {
43+
$this->auth = $auth;
44+
$this->config = $config;
2345
$this->repository = $repository;
2446
}
2547

@@ -30,11 +52,23 @@ public function __construct(ApiKeyRepositoryInterface $repository)
3052
*
3153
* @param \Illuminate\Http\Request $request
3254
* @param \Closure $next
55+
* @return mixed
3356
*/
3457
public function handle(Request $request, Closure $next)
3558
{
36-
$this->repository->findFirstWhere([
37-
'',
38-
]);
59+
if (is_null($request->bearerToken())) {
60+
throw new HttpException(401, null, null, ['WWW-Authenticate' => 'Bearer']);
61+
}
62+
63+
try {
64+
$model = $this->repository->findFirstWhere([['token', '=', $request->bearerToken()]]);
65+
} catch (RecordNotFoundException $exception) {
66+
throw new AccessDeniedHttpException;
67+
}
68+
69+
$this->auth->guard()->loginUsingId($model->user_id);
70+
$request->attributes->set('api_key', $model);
71+
72+
return $next($request);
3973
}
4074
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Middleware\API;
4+
5+
use Closure;
6+
use Illuminate\Http\Request;
7+
use Barryvdh\Debugbar\LaravelDebugbar;
8+
use Illuminate\Contracts\Foundation\Application;
9+
use Illuminate\Contracts\Config\Repository as ConfigRepository;
10+
11+
class SetSessionDriver
12+
{
13+
/**
14+
* @var \Illuminate\Contracts\Foundation\Application
15+
*/
16+
private $app;
17+
18+
/**
19+
* @var \Illuminate\Contracts\Config\Repository
20+
*/
21+
private $config;
22+
23+
/**
24+
* SetSessionDriver constructor.
25+
*
26+
* @param \Illuminate\Contracts\Foundation\Application $app
27+
* @param \Illuminate\Contracts\Config\Repository $config
28+
*/
29+
public function __construct(Application $app, ConfigRepository $config)
30+
{
31+
$this->app = $app;
32+
$this->config = $config;
33+
}
34+
35+
/**
36+
* Set the session for API calls to only last for the one request.
37+
*
38+
* @param \Illuminate\Http\Request $request
39+
* @param \Closure $next
40+
* @return mixed
41+
*/
42+
public function handle(Request $request, Closure $next)
43+
{
44+
if ($this->app->environment() !== 'production') {
45+
$this->app->make(LaravelDebugbar::class)->disable();
46+
}
47+
48+
$this->config->set('session.driver', 'array');
49+
50+
return $next($request);
51+
}
52+
}

app/Providers/RouteServiceProvider.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,9 @@ public function boot()
2929
*/
3030
public function map()
3131
{
32-
Route::middleware(['api'])->prefix('/api/user')
33-
->namespace($this->namespace . '\API\User')
34-
->group(base_path('routes/api.php'));
35-
36-
Route::middleware(['api'])->prefix('/api/admin')
37-
->namespace($this->namespace . '\API\Admin')
38-
->group(base_path('routes/api-admin.php'));
32+
// Route::middleware(['api'])->prefix('/api/user')
33+
// ->namespace($this->namespace . '\API\User')
34+
// ->group(base_path('routes/api.php'));
3935

4036
Route::middleware(['web', 'auth', 'csrf'])
4137
->namespace($this->namespace . '\Base')
@@ -53,6 +49,10 @@ public function map()
5349
->namespace($this->namespace . '\Server')
5450
->group(base_path('routes/server.php'));
5551

52+
Route::middleware(['api'])->prefix('/api/admin')
53+
->namespace($this->namespace . '\API\Admin')
54+
->group(base_path('routes/api-admin.php'));
55+
5656
Route::middleware(['daemon'])->prefix('/api/remote')
5757
->namespace($this->namespace . '\API\Remote')
5858
->group(base_path('routes/api-remote.php'));

0 commit comments

Comments
 (0)