Add backend validation to subuser permissions (#1014)

* add backend validation to subuser permissions

* always allow websocket.connect

* use collection to clean permissions
This commit is contained in:
Boy132 2025-02-21 11:02:08 +01:00 committed by GitHub
parent 324fc4b7d5
commit f0f04fd86a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 21 additions and 7 deletions

View File

@ -11,6 +11,7 @@ use Illuminate\Database\ConnectionInterface;
use App\Services\Users\UserCreationService; use App\Services\Users\UserCreationService;
use App\Exceptions\Service\Subuser\UserIsServerOwnerException; use App\Exceptions\Service\Subuser\UserIsServerOwnerException;
use App\Exceptions\Service\Subuser\ServerSubuserExistsException; use App\Exceptions\Service\Subuser\ServerSubuserExistsException;
use App\Models\Permission;
class SubuserCreationService class SubuserCreationService
{ {
@ -57,10 +58,17 @@ class SubuserCreationService
throw new ServerSubuserExistsException(trans('exceptions.subusers.subuser_exists')); throw new ServerSubuserExistsException(trans('exceptions.subusers.subuser_exists'));
} }
$cleanedPermissions = collect($permissions)
->unique()
->filter(fn ($permission) => $permission === Permission::ACTION_WEBSOCKET_CONNECT || auth()->user()->can($permission, $server))
->sort()
->values()
->all();
$subuser = Subuser::query()->create([ $subuser = Subuser::query()->create([
'user_id' => $user->id, 'user_id' => $user->id,
'server_id' => $server->id, 'server_id' => $server->id,
'permissions' => array_unique($permissions), 'permissions' => $cleanedPermissions,
]); ]);
event(new SubUserAdded($subuser)); event(new SubUserAdded($subuser));

View File

@ -3,6 +3,7 @@
namespace App\Services\Subusers; namespace App\Services\Subusers;
use App\Facades\Activity; use App\Facades\Activity;
use App\Models\Permission;
use App\Models\Server; use App\Models\Server;
use App\Models\Subuser; use App\Models\Subuser;
use App\Repositories\Daemon\DaemonServerRepository; use App\Repositories\Daemon\DaemonServerRepository;
@ -16,9 +17,14 @@ class SubuserUpdateService
public function handle(Subuser $subuser, Server $server, array $permissions): void public function handle(Subuser $subuser, Server $server, array $permissions): void
{ {
$current = $subuser->permissions; $cleanedPermissions = collect($permissions)
->unique()
->filter(fn ($permission) => $permission === Permission::ACTION_WEBSOCKET_CONNECT || auth()->user()->can($permission, $server))
->sort()
->values()
->all();
sort($permissions); $current = $subuser->permissions;
sort($current); sort($current);
$log = Activity::event('server:subuser.update') $log = Activity::event('server:subuser.update')
@ -26,15 +32,15 @@ class SubuserUpdateService
->property([ ->property([
'email' => $subuser->user->email, 'email' => $subuser->user->email,
'old' => $current, 'old' => $current,
'new' => $permissions, 'new' => $cleanedPermissions,
'revoked' => true, 'revoked' => true,
]); ]);
// Only update the database and hit up the daemon instance to invalidate JTI's if the permissions // Only update the database and hit up the daemon instance to invalidate JTI's if the permissions
// have actually changed for the user. // have actually changed for the user.
if ($permissions !== $current) { if ($cleanedPermissions !== $current) {
$log->transaction(function ($instance) use ($subuser, $permissions, $server) { $log->transaction(function ($instance) use ($subuser, $cleanedPermissions, $server) {
$subuser->update(['permissions' => $permissions]); $subuser->update(['permissions' => $cleanedPermissions]);
try { try {
$this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id); $this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id);