Files
pterodactyl_addon/app/Addons/AdvancedAdmin/Http/Controllers/Client/ServerRoleController.php

186 lines
6.4 KiB
PHP

<?php
/**
* @author Ball Studios <https://git.balls.studio>
* @license MIT
*/
namespace Pterodactyl\Addons\AdvancedAdmin\Http\Controllers\Client;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Pterodactyl\Addons\AdvancedAdmin\Http\Resources\RoleResource;
use Pterodactyl\Addons\AdvancedAdmin\Http\Resources\EffectivePermissionResource;
use Pterodactyl\Addons\AdvancedAdmin\Models\ServerRoleAssignment;
use Pterodactyl\Addons\AdvancedAdmin\Services\Roles\PermissionResolver;
use Pterodactyl\Addons\AdvancedAdmin\Services\Roles\RoleService;
use Pterodactyl\Models\Server;
class ServerRoleController extends Controller
{
public function __construct(
private readonly RoleService $roleService,
private readonly PermissionResolver $resolver,
) {}
/** GET /api/client/servers/{server}/addons/roles/users */
public function listUsers(Request $request, Server $server): JsonResponse
{
$this->authorizeServerAdmin($request, $server);
$assignments = ServerRoleAssignment::query()
->where('server_id', $server->id)
->with(['user', 'role.permissions'])
->get()
->groupBy('user_id')
->map(function ($items) {
$user = $items->first()->user;
$roles = $items->pluck('role');
return ['user' => $user, 'roles' => $roles];
})
->values();
return response()->json(['data' => $assignments]);
}
/** POST /api/client/servers/{server}/addons/roles/assign */
public function assign(Request $request, Server $server): JsonResponse
{
$this->authorizeServerAdmin($request, $server);
$data = $request->validate([
'user_id' => 'required|integer|exists:users,id',
'role_id' => 'required|integer|exists:addon_roles,id',
]);
$assignment = $this->roleService->assignToUser(
$server->id,
$data['user_id'],
$data['role_id'],
$request->user()->id,
);
return response()->json(['data' => $assignment], 201);
}
/** DELETE /api/client/servers/{server}/addons/roles/assign */
public function unassign(Request $request, Server $server): JsonResponse
{
$this->authorizeServerAdmin($request, $server);
$data = $request->validate([
'user_id' => 'required|integer|exists:users,id',
'role_id' => 'required|integer|exists:addon_roles,id',
]);
$this->roleService->unassignFromUser(
$server->id,
$data['user_id'],
$data['role_id'],
$request->user()->id,
);
return response()->json(['deleted' => true]);
}
/** GET /api/client/servers/{server}/addons/permissions/effective/{userId} */
public function effectivePermissions(Request $request, Server $server, string $targetUserId): JsonResponse
{
// Allow callers to pass "me" to resolve to their own user ID
if ($targetUserId === 'me') {
$targetUserId = (string) $request->user()?->id;
}
// Non-admins can only query their own permissions
$user = $request->user();
$isAdmin = $user && ($user->root_admin || $server->owner_id === $user->id);
if (!$isAdmin && (string) $user?->id !== $targetUserId) {
abort(403, 'You may only query your own permissions.');
}
// If target user is the owner, return an Owner role item
if ((int) $targetUserId === $server->owner_id) {
$ownerRole = [
'role' => [
'id' => 0,
'name' => 'Owner',
'color' => '#f59e0b',
'description' => 'Full server access — assigned to the server owner',
'permissions' => array_keys(RoleService::KNOWN_PERMISSIONS),
'created_at' => now()->toIso8601String(),
],
'source' => 'Server Owner',
];
return response()->json(['data' => [$ownerRole]]);
}
// Get user's assigned roles on this server
$roles = $this->resolver->getUserRolesForServer((int) $targetUserId, $server->id);
$data = [];
foreach ($roles as $role) {
$allowedPermissions = [];
foreach ($role->permissions as $p) {
if ($p->value === 'allow') {
$allowedPermissions[] = $p->permission;
}
}
$data[] = [
'role' => [
'id' => $role->id,
'name' => $role->name,
'color' => $role->color,
'description' => $role->description,
'permissions' => $allowedPermissions,
'created_at' => $role->created_at?->toIso8601String(),
],
'source' => 'Role Assignment',
];
}
return response()->json(['data' => $data]);
}
/** PUT /api/client/servers/{server}/addons/permissions/override */
public function setOverride(Request $request, Server $server): JsonResponse
{
$this->authorizeServerAdmin($request, $server);
$data = $request->validate([
'user_id' => 'required|integer|exists:users,id',
'permission' => 'required|string|max:100',
'value' => 'required|in:allow,deny,unset',
]);
$override = $this->roleService->setOverride(
$server->id,
$data['user_id'],
$data['permission'],
$data['value'],
$request->user()->id,
);
return response()->json(['data' => $override]);
}
private function authorizeServerAdmin(Request $request, Server $server): void
{
$user = $request->user();
abort_unless($user, 401);
$isOwner = $server->owner_id === $user->id;
$isAdmin = $user->root_admin;
// Subusers with user.update can also manage roles on their server
$isSubuserAdmin = false;
if (!$isOwner && !$isAdmin) {
$subuser = $server->subusers()->where('user_id', $user->id)->first();
$isSubuserAdmin = $subuser && in_array('user.update', $subuser->permissions ?? [], true);
}
abort_unless($isOwner || $isAdmin || $isSubuserAdmin, 403, 'Insufficient privileges.');
}
}