Update all the middlewares
This commit is contained in:
parent
e0d03513e4
commit
79decafdc8
16 changed files with 161 additions and 100 deletions
|
@ -28,6 +28,7 @@ This project follows [Semantic Versioning](http://semver.org) guidelines.
|
|||
* Server creation page now only asks for a node to deploy to, rather than requiring a location and then a node.
|
||||
* Database passwords are now hidden by default and will only show if clicked on. In addition, database view in ACP now indicates that passwords must be viewed on the front-end.
|
||||
* Localhost cannot be used as a connection address in the environment configuration script. `127.0.0.1` is allowed.
|
||||
* Application locale can now be quickly set using an environment variable `APP_LOCALE` rather than having to edit core files.
|
||||
|
||||
### Fixed
|
||||
* Unable to change the daemon secret for a server via the Admin CP.
|
||||
|
|
|
@ -6,6 +6,7 @@ use Pterodactyl\Http\Middleware\DaemonAuthenticate;
|
|||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||
use Pterodactyl\Http\Middleware\AccessingValidServer;
|
||||
use Pterodactyl\Http\Middleware\Server\AuthenticateAsSubuser;
|
||||
use Pterodactyl\Http\Middleware\Server\SubuserBelongsToServer;
|
||||
use Pterodactyl\Http\Middleware\Server\DatabaseBelongsToServer;
|
||||
use Pterodactyl\Http\Middleware\Server\ScheduleBelongsToServer;
|
||||
|
@ -66,7 +67,7 @@ class Kernel extends HttpKernel
|
|||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'guest' => \Pterodactyl\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'server' => AccessingValidServer::class,
|
||||
'subuser.auth' => \Pterodactyl\Http\Middleware\SubuserAccessAuthenticate::class,
|
||||
'subuser.auth' => AuthenticateAsSubuser::class,
|
||||
'admin' => \Pterodactyl\Http\Middleware\AdminAuthenticate::class,
|
||||
'daemon-old' => DaemonAuthenticate::class,
|
||||
'csrf' => \Pterodactyl\Http\Middleware\VerifyCsrfToken::class,
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
namespace Pterodactyl\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class AdminAuthenticate
|
||||
{
|
||||
|
@ -20,18 +22,10 @@ class AdminAuthenticate
|
|||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (! $request->user()) {
|
||||
if ($request->expectsJson() || $request->json()) {
|
||||
return response('Unauthorized.', 401);
|
||||
} else {
|
||||
return redirect()->guest('auth/login');
|
||||
}
|
||||
}
|
||||
|
||||
if (! $request->user()->root_admin) {
|
||||
return abort(403);
|
||||
if (! $request->user() || ! $request->user()->root_admin) {
|
||||
throw new HttpException(403, 'Access Denied');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Pterodactyl\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
|
||||
class Authenticate
|
||||
|
@ -31,7 +32,7 @@ class Authenticate
|
|||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($this->auth->guest()) {
|
||||
if ($request->ajax()) {
|
||||
|
|
|
@ -33,9 +33,12 @@ use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
|||
class DaemonAuthenticate
|
||||
{
|
||||
/**
|
||||
* Daemon routes that this middleware should be skipped on.
|
||||
* @var array
|
||||
*/
|
||||
protected $except = ['daemon.configuration'];
|
||||
protected $except = [
|
||||
'daemon.configuration',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface
|
||||
|
@ -63,6 +66,10 @@ class DaemonAuthenticate
|
|||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (in_array($request->route()->getName(), $this->except)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
$token = $request->bearerToken();
|
||||
|
||||
if (is_null($token)) {
|
||||
|
|
|
@ -10,35 +10,36 @@
|
|||
namespace Pterodactyl\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
|
||||
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||
|
||||
class DaemonAuthenticate
|
||||
{
|
||||
/**
|
||||
* The Guard implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Auth\Guard
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* An array of route names to not apply this middleware to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
private $except = [
|
||||
'daemon.configuration',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\NodeRepositoryInterface
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* Create a new filter instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Auth\Guard $auth
|
||||
* @param \Pterodactyl\Contracts\Repository\NodeRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(Guard $auth)
|
||||
public function __construct(NodeRepositoryInterface $repository)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,21 +49,24 @@ class DaemonAuthenticate
|
|||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (in_array($request->route()->getName(), $this->except)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if (! $request->header('X-Access-Node')) {
|
||||
return abort(403);
|
||||
throw new HttpException(403);
|
||||
}
|
||||
|
||||
$node = Node::where('daemonSecret', $request->header('X-Access-Node'))->first();
|
||||
if (! $node) {
|
||||
return abort(401);
|
||||
try {
|
||||
$node = $this->repository->findWhere(['daemonSecret' => $request->header('X-Access-Node')]);
|
||||
} catch (RecordNotFoundException $exception) {
|
||||
throw new HttpException(401);
|
||||
}
|
||||
|
||||
$request->attributes->set('node', $node);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,5 @@ class EncryptCookies extends BaseEncrypter
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
];
|
||||
protected $except = [];
|
||||
}
|
||||
|
|
|
@ -9,14 +9,28 @@
|
|||
|
||||
namespace Pterodactyl\Http\Middleware;
|
||||
|
||||
use Auth;
|
||||
use Closure;
|
||||
use Session;
|
||||
use Settings;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
|
||||
class LanguageMiddleware
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* LanguageMiddleware constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
*/
|
||||
public function __construct(Repository $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
|
@ -24,17 +38,9 @@ class LanguageMiddleware
|
|||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
// if (Session::has('applocale')) {
|
||||
// App::setLocale(Session::get('applocale'));
|
||||
// } elseif (Auth::check() && isset(Auth::user()->language)) {
|
||||
// Session::put('applocale', Auth::user()->language);
|
||||
// App::setLocale(Auth::user()->language);
|
||||
// } else {
|
||||
// App::setLocale(Settings::get('default_language', 'en'));
|
||||
// }
|
||||
App::setLocale('en');
|
||||
App::setLocale($this->config->get('app.locale', 'en'));
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,26 @@
|
|||
namespace Pterodactyl\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Auth\AuthManager;
|
||||
|
||||
class RedirectIfAuthenticated
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Auth\Guard
|
||||
*/
|
||||
private $authManager;
|
||||
|
||||
/**
|
||||
* RedirectIfAuthenticated constructor.
|
||||
*
|
||||
* @param \Illuminate\Auth\AuthManager $authManager
|
||||
*/
|
||||
public function __construct(AuthManager $authManager)
|
||||
{
|
||||
$this->authManager = $authManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
|
@ -15,9 +31,9 @@ class RedirectIfAuthenticated
|
|||
* @param string|null $guard
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $guard = null)
|
||||
public function handle(Request $request, Closure $next, string $guard = null)
|
||||
{
|
||||
if (Auth::guard($guard)->check()) {
|
||||
if ($this->authManager->guard($guard)->check()) {
|
||||
return redirect(route('index'));
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
namespace Pterodactyl\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Krucas\Settings\Settings;
|
||||
use Prologue\Alerts\AlertsMessageBag;
|
||||
|
||||
|
@ -22,28 +23,35 @@ class RequireTwoFactorAuthentication
|
|||
/**
|
||||
* @var \Prologue\Alerts\AlertsMessageBag
|
||||
*/
|
||||
protected $alert;
|
||||
private $alert;
|
||||
|
||||
/**
|
||||
* @var \Krucas\Settings\Settings
|
||||
*/
|
||||
protected $settings;
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* All TOTP related routes.
|
||||
* The names of routes that should be accessable without 2FA enabled.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $ignoreRoutes = [
|
||||
'account.security',
|
||||
'account.security.revoke',
|
||||
'account.security.totp',
|
||||
'account.security.totp.set',
|
||||
'account.security.totp.disable',
|
||||
'auth.totp',
|
||||
'auth.logout',
|
||||
protected $except = [
|
||||
'account.security',
|
||||
'account.security.revoke',
|
||||
'account.security.totp',
|
||||
'account.security.totp.set',
|
||||
'account.security.totp.disable',
|
||||
'auth.totp',
|
||||
'auth.logout',
|
||||
];
|
||||
|
||||
/**
|
||||
* The route to redirect a user to to enable 2FA.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectRoute = 'account.security';
|
||||
|
||||
/**
|
||||
* RequireTwoFactorAuthentication constructor.
|
||||
*
|
||||
|
@ -63,7 +71,7 @@ class RequireTwoFactorAuthentication
|
|||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
// Ignore non-users
|
||||
if (! $request->user()) {
|
||||
|
@ -71,7 +79,7 @@ class RequireTwoFactorAuthentication
|
|||
}
|
||||
|
||||
// Skip the 2FA pages
|
||||
if (in_array($request->route()->getName(), $this->ignoreRoutes)) {
|
||||
if (in_array($request->route()->getName(), $this->except)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
|
@ -93,8 +101,8 @@ class RequireTwoFactorAuthentication
|
|||
break;
|
||||
}
|
||||
|
||||
$this->alert->danger('The administrator has required 2FA to be enabled. You must enable it before you can do any other action.')->flash();
|
||||
$this->alert->danger(trans('auth.2fa_must_be_enabled'))->flash();
|
||||
|
||||
return redirect()->route('account.security');
|
||||
return redirect()->route($this->redirectRoute);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Http\Middleware;
|
||||
namespace Pterodactyl\Http\Middleware\Server;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
@ -16,17 +16,17 @@ use Illuminate\Auth\AuthenticationException;
|
|||
use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService;
|
||||
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
|
||||
|
||||
class SubuserAccessAuthenticate
|
||||
class AuthenticateAsSubuser
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService
|
||||
*/
|
||||
protected $keyProviderService;
|
||||
private $keyProviderService;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Session\Session
|
||||
*/
|
||||
protected $session;
|
||||
private $session;
|
||||
|
||||
/**
|
||||
* SubuserAccessAuthenticate constructor.
|
||||
|
@ -34,10 +34,8 @@ class SubuserAccessAuthenticate
|
|||
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService $keyProviderService
|
||||
* @param \Illuminate\Contracts\Session\Session $session
|
||||
*/
|
||||
public function __construct(
|
||||
DaemonKeyProviderService $keyProviderService,
|
||||
Session $session
|
||||
) {
|
||||
public function __construct(DaemonKeyProviderService $keyProviderService, Session $session)
|
||||
{
|
||||
$this->keyProviderService = $keyProviderService;
|
||||
$this->session = $session;
|
||||
}
|
||||
|
@ -55,16 +53,17 @@ class SubuserAccessAuthenticate
|
|||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$server = $this->session->get('server_data.model');
|
||||
$server = $request->attributes->get('server');
|
||||
|
||||
try {
|
||||
$token = $this->keyProviderService->handle($server->id, $request->user()->id);
|
||||
$this->session->now('server_data.token', $token);
|
||||
$request->attributes->set('server_token', $token);
|
||||
} catch (RecordNotFoundException $exception) {
|
||||
throw new AuthenticationException('This account does not have permission to access this server.');
|
||||
}
|
||||
|
||||
$this->session->now('server_data.token', $token);
|
||||
$request->attributes->set('server_token', $token);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace Pterodactyl\Http\Middleware\Server;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Contracts\Extensions\HashidsInterface;
|
||||
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
@ -41,7 +42,7 @@ class ScheduleBelongsToServer
|
|||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$server = $request->attributes->get('server');
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Pterodactyl\Http\Middleware\Server;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Exceptions\DisplayException;
|
||||
use Pterodactyl\Contracts\Extensions\HashidsInterface;
|
||||
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
|
||||
|
@ -43,7 +44,7 @@ class SubuserBelongsToServer
|
|||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$server = $request->attributes->get('server');
|
||||
|
||||
|
|
|
@ -3,28 +3,46 @@
|
|||
namespace Pterodactyl\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use Pterodactyl\Events\Auth\FailedCaptcha;
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
|
||||
class VerifyReCaptcha
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* VerifyReCaptcha constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
*/
|
||||
public function __construct(Repository $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return \Illuminate\Http\RediectResponse
|
||||
* @return \Illuminate\Http\RedirectResponse|mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if (! config('recaptcha.enabled')) {
|
||||
if (! $this->config->get('recaptcha.enabled')) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
if ($request->has('g-recaptcha-response')) {
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$res = $client->post(config('recaptcha.domain'), [
|
||||
$client = new Client();
|
||||
$res = $client->post($this->config->get('recaptcha.domain'), [
|
||||
'form_params' => [
|
||||
'secret' => config('recaptcha.secret_key'),
|
||||
'secret' => $this->config->get('recaptcha.secret_key'),
|
||||
'response' => $request->input('g-recaptcha-response'),
|
||||
],
|
||||
]);
|
||||
|
@ -32,29 +50,33 @@ class VerifyReCaptcha
|
|||
if ($res->getStatusCode() === 200) {
|
||||
$result = json_decode($res->getBody());
|
||||
|
||||
$verified = function ($result, $request) {
|
||||
if (! config('recaptcha.verify_domain')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$url = parse_url($request->url());
|
||||
|
||||
if (! array_key_exists('host', $url)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result->hostname === $url['host'];
|
||||
};
|
||||
|
||||
if ($result->success && (! config('recaptcha.verify_domain') || $verified($result, $request))) {
|
||||
if ($result->success && (! $this->config->get('recaptcha.verify_domain') || $this->isResponseVerified($result, $request))) {
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit an event and return to the previous view with an error (only the captcha error will be shown!)
|
||||
event(new FailedCaptcha($request->ip(), (! isset($result->hostname) ?: $result->hostname)));
|
||||
event(new FailedCaptcha($request->ip(), (! isset($result) ?: object_get($result, 'hostname'))));
|
||||
|
||||
return back()->withErrors(['g-recaptcha-response' => trans('strings.captcha_invalid')])->withInput();
|
||||
return redirect()->back()->withErrors(['g-recaptcha-response' => trans('strings.captcha_invalid')])->withInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the response from the recaptcha servers was valid.
|
||||
*
|
||||
* @param object $result
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return bool
|
||||
*/
|
||||
private function isResponseVerified(object $result, Request $request): bool
|
||||
{
|
||||
if (! $this->config->get('recaptcha.verify_domain')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$url = parse_url($request->url());
|
||||
|
||||
return $result->hostname === array_get($url, 'host');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ return [
|
|||
|
|
||||
*/
|
||||
|
||||
'locale' => 'en',
|
||||
'locale' => env('APP_LOCALE', 'en'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
@ -18,4 +18,5 @@ return [
|
|||
'2fa_required' => '2-Factor Authentication',
|
||||
'2fa_failed' => 'The 2FA token provided was invalid.',
|
||||
'totp_failed' => 'There was an error while attempting to validate TOTP.',
|
||||
'2fa_must_be_enabled' => 'The administrator has required that 2-Factor Authentication be enabled for your account in order to use the Panel.',
|
||||
];
|
||||
|
|
Loading…
Reference in a new issue