Skip to content

Commit e969344

Browse files
committed
Fix display of navbar links to admins, closes pterodactyl#1920
1 parent 4193c5f commit e969344

File tree

8 files changed

+67
-39
lines changed

8 files changed

+67
-39
lines changed

app/Http/Controllers/Api/Client/Servers/ServerController.php

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use Pterodactyl\Models\Server;
66
use Pterodactyl\Repositories\Eloquent\SubuserRepository;
77
use Pterodactyl\Transformers\Api\Client\ServerTransformer;
8-
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
8+
use Pterodactyl\Services\Servers\GetUserPermissionsService;
99
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
1010
use Pterodactyl\Http\Requests\Api\Client\Servers\GetServerRequest;
1111

@@ -16,16 +16,23 @@ class ServerController extends ClientApiController
1616
*/
1717
private $repository;
1818

19+
/**
20+
* @var \Pterodactyl\Services\Servers\GetUserPermissionsService
21+
*/
22+
private $permissionsService;
23+
1924
/**
2025
* ServerController constructor.
2126
*
27+
* @param \Pterodactyl\Services\Servers\GetUserPermissionsService $permissionsService
2228
* @param \Pterodactyl\Repositories\Eloquent\SubuserRepository $repository
2329
*/
24-
public function __construct(SubuserRepository $repository)
30+
public function __construct(GetUserPermissionsService $permissionsService, SubuserRepository $repository)
2531
{
2632
parent::__construct();
2733

2834
$this->repository = $repository;
35+
$this->permissionsService = $permissionsService;
2936
}
3037

3138
/**
@@ -38,20 +45,11 @@ public function __construct(SubuserRepository $repository)
3845
*/
3946
public function index(GetServerRequest $request, Server $server): array
4047
{
41-
try {
42-
$permissions = $this->repository->findFirstWhere([
43-
'server_id' => $server->id,
44-
'user_id' => $request->user()->id,
45-
])->permissions;
46-
} catch (RecordNotFoundException $exception) {
47-
$permissions = [];
48-
}
49-
5048
return $this->fractal->item($server)
5149
->transformWith($this->getTransformer(ServerTransformer::class))
5250
->addMeta([
5351
'is_server_owner' => $request->user()->id === $server->owner_id,
54-
'user_permissions' => $permissions,
52+
'user_permissions' => $this->permissionsService->handle($server, $request->user()),
5553
])
5654
->toArray();
5755
}

app/Http/Controllers/Api/Client/Servers/SubuserController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,6 @@ public function delete(DeleteSubuserRequest $request, Server $server)
123123
*/
124124
protected function getDefaultPermissions(Request $request): array
125125
{
126-
return array_unique(array_merge($request->input('permissions') ?? [], ['websocket.*']));
126+
return array_unique(array_merge($request->input('permissions') ?? [], ['websocket.connect']));
127127
}
128128
}

app/Http/Controllers/Api/Client/Servers/WebsocketController.php

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
use Carbon\CarbonImmutable;
66
use Illuminate\Http\Response;
77
use Pterodactyl\Models\Server;
8-
use Pterodactyl\Models\Subuser;
98
use Illuminate\Http\JsonResponse;
109
use Pterodactyl\Models\Permission;
1110
use Illuminate\Contracts\Cache\Repository;
1211
use Pterodactyl\Services\Nodes\NodeJWTService;
1312
use Symfony\Component\HttpKernel\Exception\HttpException;
1413
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
14+
use Pterodactyl\Services\Servers\GetUserPermissionsService;
1515
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
1616

1717
class WebsocketController extends ClientApiController
@@ -26,18 +26,28 @@ class WebsocketController extends ClientApiController
2626
*/
2727
private $jwtService;
2828

29+
/**
30+
* @var \Pterodactyl\Services\Servers\GetUserPermissionsService
31+
*/
32+
private $permissionsService;
33+
2934
/**
3035
* WebsocketController constructor.
3136
*
3237
* @param \Pterodactyl\Services\Nodes\NodeJWTService $jwtService
38+
* @param \Pterodactyl\Services\Servers\GetUserPermissionsService $permissionsService
3339
* @param \Illuminate\Contracts\Cache\Repository $cache
3440
*/
35-
public function __construct(NodeJWTService $jwtService, Repository $cache)
36-
{
41+
public function __construct(
42+
NodeJWTService $jwtService,
43+
GetUserPermissionsService $permissionsService,
44+
Repository $cache
45+
) {
3746
parent::__construct();
3847

3948
$this->cache = $cache;
4049
$this->jwtService = $jwtService;
50+
$this->permissionsService = $permissionsService;
4151
}
4252

4353
/**
@@ -53,32 +63,16 @@ public function __construct(NodeJWTService $jwtService, Repository $cache)
5363
public function __invoke(ClientApiRequest $request, Server $server)
5464
{
5565
$user = $request->user();
56-
if ($user->cannot(Permission::ACTION_WEBSOCKET, $server)) {
66+
if ($user->cannot(Permission::ACTION_WEBSOCKET_CONNECT, $server)) {
5767
throw new HttpException(Response::HTTP_FORBIDDEN, 'You do not have permission to connect to this server\'s websocket.');
5868
}
5969

60-
if ($user->root_admin || $user->id === $server->owner_id) {
61-
$permissions = ['*'];
62-
63-
if ($user->root_admin) {
64-
$permissions[] = 'admin.errors';
65-
$permissions[] = 'admin.install';
66-
}
67-
} else {
68-
/** @var \Pterodactyl\Models\Subuser|null $subuserPermissions */
69-
$subuserPermissions = $server->subusers->first(function (Subuser $subuser) use ($user) {
70-
return $subuser->user_id === $user->id;
71-
});
72-
73-
$permissions = $subuserPermissions ? $subuserPermissions->permissions : [];
74-
}
75-
7670
$token = $this->jwtService
7771
->setExpiresAt(CarbonImmutable::now()->addMinutes(15))
7872
->setClaims([
7973
'user_id' => $request->user()->id,
8074
'server_uuid' => $server->uuid,
81-
'permissions' => $permissions ?? [],
75+
'permissions' => $this->permissionsService->handle($server, $user),
8276
])
8377
->handle($server->node, $user->id . $server->uuid);
8478

app/Models/Permission.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Permission extends Model
1515
/**
1616
* Constants defining different permissions available.
1717
*/
18-
const ACTION_WEBSOCKET = 'websocket.*';
18+
const ACTION_WEBSOCKET_CONNECT = 'websocket.connect';
1919
const ACTION_CONTROL_CONSOLE = 'control.console';
2020
const ACTION_CONTROL_START = 'control.start';
2121
const ACTION_CONTROL_STOP = 'control.stop';
@@ -105,7 +105,7 @@ class Permission extends Model
105105
'websocket' => [
106106
'description' => 'Allows the user to connect to the server websocket, giving them access to view console output and realtime server stats.',
107107
'keys' => [
108-
'*' => 'Gives user full read access to the websocket.',
108+
'connect' => 'Allows a user to connect to the websocket instance for a server to stream the console.',
109109
],
110110
],
111111

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Pterodactyl\Services\Servers;
4+
5+
use Pterodactyl\Models\User;
6+
use Pterodactyl\Models\Server;
7+
8+
class GetUserPermissionsService
9+
{
10+
/**
11+
* Returns the server specific permissions that a user has. This checks
12+
* if they are an admin or a subuser for the server. If no permissions are
13+
* found, an empty array is returned.
14+
*
15+
* @param \Pterodactyl\Models\Server $server
16+
* @param \Pterodactyl\Models\User $user
17+
* @return string[]
18+
*/
19+
public function handle(Server $server, User $user)
20+
{
21+
if ($user->root_admin || $user->id === $server->owner_id) {
22+
$permissions = ['*'];
23+
24+
if ($user->root_admin) {
25+
$permissions[] = 'admin.websocket.errors';
26+
$permissions[] = 'admin.websocket.install';
27+
}
28+
29+
return $permissions;
30+
}
31+
32+
/** @var \Pterodactyl\Models\Subuser|null $subuserPermissions */
33+
$subuserPermissions = $server->subusers->where('user_id', $user->id)->first();
34+
35+
return $subuserPermissions ? $subuserPermissions->permissions : [];
36+
}
37+
}

resources/scripts/components/server/users/UserRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export default ({ subuser }: Props) => {
4747
</div>
4848
<div className={'ml-4'}>
4949
<p className={'font-medium text-center'}>
50-
{subuser.permissions.filter(permission => permission !== 'websocket.*').length}
50+
{subuser.permissions.filter(permission => permission !== 'websocket.connect').length}
5151
</p>
5252
<p className={'text-2xs text-neutral-500 uppercase'}>Permissions</p>
5353
</div>

resources/scripts/plugins/usePermissions.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ export const usePermissions = (action: string | string[]): boolean[] => {
1515
// will return if the user has any permission under the file.XYZ namespace.
1616
(
1717
permission.endsWith('.*') &&
18-
permission !== 'websocket.*' &&
1918
userPermissions.filter(p => p.startsWith(permission.split('.')[0])).length > 0
2019
) ||
2120
// Otherwise just check if the entire permission exists in the array or not.

resources/scripts/state/server/subusers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { action, Action } from 'easy-peasy';
22

33
export type SubuserPermission =
4-
'websocket.*' |
4+
'websocket.connect' |
55
'control.console' | 'control.start' | 'control.stop' | 'control.restart' |
66
'user.create' | 'user.read' | 'user.update' | 'user.delete' |
77
'file.create' | 'file.read' | 'file.update' | 'file.delete' | 'file.archive' | 'file.sftp' |

0 commit comments

Comments
 (0)