diff --git a/app/Http/Controllers/api/v1/RoleController.php b/app/Http/Controllers/api/v1/RoleController.php index e44a74c67..124f0b824 100644 --- a/app/Http/Controllers/api/v1/RoleController.php +++ b/app/Http/Controllers/api/v1/RoleController.php @@ -6,7 +6,6 @@ use App\Http\Controllers\Controller; use App\Http\Requests\RoleRequest; use App\Http\Resources\Role as RoleResource; -use App\Models\Permission; use App\Models\Role; use App\Settings\GeneralSettings; use Exception; @@ -74,11 +73,7 @@ public function store(RoleRequest $request) $role->save(); - $new_permissions = collect($request->permissions)->filter(function ($permissionId) { - $permission = Permission::find($permissionId); - - return ! in_array($permission->name, config('permissions.restrictions')); - }); + $new_permissions = $role->filterRestrictedPermissions(collect($request->permissions)); $role->permissions()->sync($new_permissions); @@ -106,11 +101,7 @@ public function update(RoleRequest $request, Role $role) if (! $role->superuser) { $old_role_permissions = $role->permissions()->pluck('permissions.id')->toArray(); - $new_permissions = collect($request->permissions)->filter(function ($permissionId) { - $permission = Permission::find($permissionId); - - return ! in_array($permission->name, config('permissions.restrictions')); - }); + $new_permissions = $role->filterRestrictedPermissions(collect($request->permissions)); $role->permissions()->sync($new_permissions); diff --git a/app/Models/Role.php b/app/Models/Role.php index 7ec85ae33..214c3d0f8 100644 --- a/app/Models/Role.php +++ b/app/Models/Role.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Support\Collection; /** * Class Role @@ -46,6 +47,42 @@ public function permissions() return $this->belongsToMany(Permission::class)->using(PermissionRole::class); } + /** + * Filters out restricted permissions from the given collection of permission IDs. + * + * @param Collection $permissionIDs Collection of permission IDs to be filtered. + * @return Collection Filtered collection of permission IDs that are not restricted. + */ + public function filterRestrictedPermissions(Collection $permissionIDs): Collection + { + return $permissionIDs->filter(function ($permissionID) { + // Find the permission by its ID + $permission = Permission::find($permissionID); + if ($permission === null) { + return false; + } + + // Get the list of restricted permissions from the configuration + $restrictions = collect(config('permissions.restrictions')); + + // Check if the permission is not in the list of restricted permissions + return $restrictions->doesntContain(function (string $restriction) use ($permission) { + // If the restriction matches the permission name, it is restricted + if ($restriction === $permission->name) { + return true; + } + + // Split the restriction and permission names into groups and permissions + $restrictionGroup = explode('.', $restriction, 2)[0]; + $restrictionPermission = explode('.', $restriction, 2)[1] ?? null; + $permissionGroup = explode('.', $permission->name, 2)[0]; + + // If the restriction applies to all permissions in the group, it is restricted + return $restrictionPermission === '*' && $restrictionGroup === $permissionGroup; + }); + }); + } + /** * Types of rooms that can be used by the user of this role. * diff --git a/docs/docs/administration/08-advanced/02-roles-and-permissions.md b/docs/docs/administration/08-advanced/02-roles-and-permissions.md index d6547946d..284e9fb92 100644 --- a/docs/docs/administration/08-advanced/02-roles-and-permissions.md +++ b/docs/docs/administration/08-advanced/02-roles-and-permissions.md @@ -96,7 +96,9 @@ To prevent regular admins from managing certain permissions: Example (regular admins cannot manage servers or server pools): ```bash -PERMISSION_RESTRICTIONS=servers.viewAny,servers.view,servers.create,servers.update,servers.delete,serverPools.viewAny,serverPools.view,serverPools.create,serverPools.update,serverPools.delete +PERMISSION_RESTRICTIONS=servers.*,serverPools.viewAny,serverPools.view,serverPools.create,serverPools.update,serverPools.delete ``` +The permissions can either be a specific permission or a wildcard `*` to restrict all permissions of a group. + Permissions in this list cannot be assigned to roles by anyone except superusers. diff --git a/resources/js/views/AdminRolesView.vue b/resources/js/views/AdminRolesView.vue index 39054725c..86581a8ad 100644 --- a/resources/js/views/AdminRolesView.vue +++ b/resources/js/views/AdminRolesView.vue @@ -459,8 +459,24 @@ function loadPermissions() { response.data.data.forEach((permission) => { permission.rawName = permission.name; - permission.restricted = permissionRestrictions.value.includes( - permission.name, + + permission.restricted = permissionRestrictions.value.some( + (restriction) => { + if (restriction === permission.name) { + return true; + } + + return false; + + const restrictionPermission = restriction.split(".", 2)[1]; + const restrictionGroup = restriction.split(".", 2)[0]; + const permissionGroup = permission.name.split(".", 2)[0]; + + return ( + restrictionPermission === "*" && + permissionGroup === restrictionGroup + ); + }, ); permission.name = permission.name diff --git a/tests/Backend/Feature/api/v1/RoleTest.php b/tests/Backend/Feature/api/v1/RoleTest.php index 5e5474962..f13a05451 100644 --- a/tests/Backend/Feature/api/v1/RoleTest.php +++ b/tests/Backend/Feature/api/v1/RoleTest.php @@ -124,7 +124,7 @@ public function test_create() public function test_create_restricted_permissions() { - config(['permissions.restrictions' => ['servers.create']]); + config(['permissions.restrictions' => ['servers.create', 'serverPools.*']]); $user = User::factory()->create(); $roleA = Role::factory()->create(); @@ -132,6 +132,7 @@ public function test_create_restricted_permissions() $createRolesPermission = Permission::firstOrCreate(['name' => 'roles.create']); $createServersPermission = Permission::firstOrCreate(['name' => 'servers.create']); + $createServerPoolPermission = Permission::firstOrCreate(['name' => 'serverPools.create']); $roleA->permissions()->attach([$createRolesPermission, $createServersPermission]); $role = [ @@ -274,7 +275,7 @@ public function test_update_restricted_permissions() $roleA = Role::factory()->create(); $user->roles()->attach([$roleA->id]); - config(['permissions.restrictions' => ['servers.create']]); + config(['permissions.restrictions' => ['servers.create', 'serverPools.*']]); $permission_ids = [ Permission::firstOrCreate(['name' => 'admin.view'])->id, @@ -294,7 +295,7 @@ public function test_update_restricted_permissions() $role = [ 'name' => 'Test', 'superuser' => false, - 'permissions' => [...$permission_ids, $createServersPermission->id], + 'permissions' => [...$permission_ids, $createServerPoolsPermission->id, $createServersPermission->id], 'room_limit' => 1, 'updated_at' => now(), ];