Skip to content

Commit e30a765

Browse files
committed
Simplify logic when a server is in an unsupported state
1 parent be26921 commit e30a765

File tree

10 files changed

+76
-294
lines changed

10 files changed

+76
-294
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Pterodactyl\Exceptions\Http\Server;
4+
5+
use Throwable;
6+
use Pterodactyl\Models\Server;
7+
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
8+
9+
class ServerStateConflictException extends ConflictHttpException
10+
{
11+
/**
12+
* Exception thrown when the server is in an unsupported state for API access or
13+
* certain operations within the codebase.
14+
*/
15+
public function __construct(Server $server, Throwable $previous = null)
16+
{
17+
$message = 'This server is currently in an unsupported state, please try again later.';
18+
if ($server->isSuspended()) {
19+
$message = 'This server is currently suspended and the functionality requested is unavailable.';
20+
} elseif (!$server->isInstalled()) {
21+
$message = 'This server has not yet completed its installation process, please try again later.';
22+
} elseif ($server->status === Server::STATUS_RESTORING_BACKUP) {
23+
$message = 'This server is currently restoring from a backup, please try again later.';
24+
} elseif (!is_null($server->transfer)) {
25+
$message = 'This server is currently being transferred to a new machine, please try again later.';
26+
}
27+
28+
parent::__construct($message, $previous);
29+
}
30+
}

app/Exceptions/Http/Server/ServerTransferringException.php

Lines changed: 0 additions & 17 deletions
This file was deleted.

app/Http/Controllers/Api/Remote/SftpAuthenticationController.php

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
use Pterodactyl\Repositories\Eloquent\ServerRepository;
1313
use Pterodactyl\Services\Servers\GetUserPermissionsService;
1414
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
15-
use Pterodactyl\Exceptions\Http\Server\ServerTransferringException;
16-
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
1715
use Pterodactyl\Http\Requests\Api\Remote\SftpAuthenticationFormRequest;
1816
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
1917

@@ -98,16 +96,7 @@ public function __invoke(SftpAuthenticationFormRequest $request): JsonResponse
9896
}
9997
}
10098

101-
// Prevent SFTP access to servers that are being transferred.
102-
if (!is_null($server->transfer)) {
103-
throw new ServerTransferringException();
104-
}
105-
106-
// Remember, for security purposes, only reveal the existence of the server to people that
107-
// have provided valid credentials, and have permissions to know about it.
108-
if ($server->isSuspended() || !$server->isInstalled()) {
109-
throw new BadRequestHttpException('Server is not installed or is currently suspended.');
110-
}
99+
$server->validateCurrentState();
111100

112101
return new JsonResponse([
113102
'server' => $server->uuid,

app/Http/Kernel.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
use Pterodactyl\Http\Middleware\Api\ApiSubstituteBindings;
2929
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
3030
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
31-
use Pterodactyl\Http\Middleware\Server\AccessingValidServer;
3231
use Pterodactyl\Http\Middleware\Api\Daemon\DaemonAuthenticate;
3332
use Pterodactyl\Http\Middleware\RequireTwoFactorAuthentication;
3433
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode;
@@ -106,7 +105,6 @@ class Kernel extends HttpKernel
106105
'auth' => Authenticate::class,
107106
'auth.basic' => AuthenticateWithBasicAuth::class,
108107
'guest' => RedirectIfAuthenticated::class,
109-
'server' => AccessingValidServer::class,
110108
'admin' => AdminAuthenticate::class,
111109
'csrf' => VerifyCsrfToken::class,
112110
'throttle' => ThrottleRequests::class,

app/Http/Middleware/Api/Client/Server/AuthenticateServerAccess.php

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
use Illuminate\Http\Request;
77
use Pterodactyl\Models\Server;
88
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
9-
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
109
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
11-
use Pterodactyl\Exceptions\Http\Server\ServerTransferringException;
12-
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
10+
use Pterodactyl\Exceptions\Http\Server\ServerStateConflictException;
1311

1412
class AuthenticateServerAccess
1513
{
@@ -60,23 +58,17 @@ public function handle(Request $request, Closure $next)
6058
}
6159
}
6260

63-
if ($server->suspended && !$request->routeIs('api:client:server.resources')) {
64-
throw new BadRequestHttpException('This server is currently suspended and the functionality requested is unavailable.');
65-
}
66-
67-
// Still allow users to get information about their server if it is installing or being transferred.
68-
if (!$request->routeIs('api:client:server.view')) {
69-
if (!$server->isInstalled()) {
70-
// Throw an exception for all server routes; however if the user is an admin and requesting the
71-
// server details, don't throw the exception for them.
72-
if (!$user->root_admin || ($user->root_admin && !$request->routeIs($this->except))) {
73-
throw new ConflictHttpException('Server has not completed the installation process.');
61+
try {
62+
$server->validateCurrentState();
63+
} catch (ServerStateConflictException $exception) {
64+
// Still allow users to get information about their server if it is installing or
65+
// being transferred.
66+
if (!$request->routeIs('api:client:server.view')) {
67+
if ($server->isSuspended() && !$request->routeIs('api:client:server.resources')) {
68+
throw $exception;
7469
}
75-
}
76-
77-
if (!is_null($server->transfer)) {
78-
if (!$user->root_admin || ($user->root_admin && !$request->routeIs($this->except))) {
79-
throw new ServerTransferringException();
70+
if (!$user->root_admin || !$request->routeIs($this->except)) {
71+
throw $exception;
8072
}
8173
}
8274
}

app/Http/Middleware/Server/AccessingValidServer.php

Lines changed: 0 additions & 92 deletions
This file was deleted.

app/Models/Server.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Notifications\Notifiable;
77
use Illuminate\Database\Query\JoinClause;
88
use Znck\Eloquent\Traits\BelongsToThrough;
9+
use Pterodactyl\Exceptions\Http\Server\ServerStateConflictException;
910

1011
/**
1112
* @property int $id
@@ -371,4 +372,23 @@ public function audits()
371372
{
372373
return $this->hasMany(AuditLog::class);
373374
}
375+
376+
/**
377+
* Checks if the server is currently in a user-accessible state. If not, an
378+
* exception is raised. This should be called whenever something needs to make
379+
* sure the server is not in a weird state that should block user access.
380+
*
381+
* @throws \Pterodactyl\Exceptions\Http\Server\ServerStateConflictException
382+
*/
383+
public function validateCurrentState()
384+
{
385+
if (
386+
$this->isSuspended() ||
387+
!$this->isInstalled() ||
388+
$this->status === self::STATUS_RESTORING_BACKUP ||
389+
!is_null($this->transfer)
390+
) {
391+
throw new ServerStateConflictException($this);
392+
}
393+
}
374394
}

app/Services/Servers/SuspensionService.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use Pterodactyl\Models\Server;
77
use Illuminate\Database\ConnectionInterface;
88
use Pterodactyl\Repositories\Wings\DaemonServerRepository;
9-
use Pterodactyl\Exceptions\Http\Server\ServerTransferringException;
9+
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
1010

1111
class SuspensionService
1212
{
@@ -55,7 +55,7 @@ public function toggle(Server $server, $action = self::ACTION_SUSPEND)
5555

5656
// Check if the server is currently being transferred.
5757
if (!is_null($server->transfer)) {
58-
throw new ServerTransferringException();
58+
throw new ConflictHttpException('Cannot toggle suspension status on a server that is currently being transferred.');
5959
}
6060

6161
$this->connection->transaction(function () use ($action, $server, $isSuspending) {

resources/scripts/components/dashboard/ServerRow.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,21 +111,23 @@ export default ({ server, className }: { server: Server; className?: string }) =
111111
</span>
112112
</div>
113113
:
114-
server.isInstalling ?
114+
(server.isTransferring || server.status) ?
115115
<div css={tw`flex-1 text-center`}>
116116
<span css={tw`bg-neutral-500 rounded px-2 py-1 text-neutral-100 text-xs`}>
117-
Installing
117+
{server.isTransferring ?
118+
'Transferring'
119+
:
120+
server.status === 'installing' ? 'Installing' : (
121+
server.status === 'restoring_backup' ?
122+
'Restoring Backup'
123+
:
124+
'Unavailable'
125+
)
126+
}
118127
</span>
119128
</div>
120129
:
121-
server.isTransferring ?
122-
<div css={tw`flex-1 text-center`}>
123-
<span css={tw`bg-neutral-500 rounded px-2 py-1 text-neutral-100 text-xs`}>
124-
Transferring
125-
</span>
126-
</div>
127-
:
128-
<Spinner size={'small'}/>
130+
<Spinner size={'small'}/>
129131
:
130132
<React.Fragment>
131133
<div css={tw`flex-1 flex md:ml-4 sm:flex hidden justify-center`}>

0 commit comments

Comments
 (0)