diff --git a/app/Enums/ResourceLimit.php b/app/Enums/ResourceLimit.php new file mode 100644 index 0000000000..59707601a4 --- /dev/null +++ b/app/Enums/ResourceLimit.php @@ -0,0 +1,65 @@ +name}"; + } + + /** + * Returns a middleware that will throttle the specific resource by server. This + * throttle applies to any user making changes to that resource on the specific + * server, it is NOT per-user. + */ + public function middleware(): string + { + return ThrottleRequests::using($this->throttleKey()); + } + + public function limit(): Limit + { + return match ($this) { + self::Websocket => Limit::perMinute(5), + self::BackupRestore => Limit::perMinutes(15, 3), + self::DatabaseCreate => Limit::perMinute(2), + self::SubuserCreate => Limit::perMinutes(15, 10), + self::FilePull => Limit::perMinutes(10, 5), + default => Limit::perMinute(2), + }; + } + + public static function boot(): void + { + foreach (self::cases() as $case) { + RateLimiter::for($case->throttleKey(), function (Request $request) use ($case) { + Assert::isInstanceOf($server = $request->route()->parameter('server'), Server::class); + + return $case->limit()->by($server->uuid); + }); + } + } +} diff --git a/app/Extensions/OAuth/Schemas/GithubSchema.php b/app/Extensions/OAuth/Schemas/GithubSchema.php index c3dfc4894f..b7258ab4b0 100644 --- a/app/Extensions/OAuth/Schemas/GithubSchema.php +++ b/app/Extensions/OAuth/Schemas/GithubSchema.php @@ -18,11 +18,11 @@ public function getId(): string public function getSetupSteps(): array { return array_merge([ - Step::make('Register new Github OAuth App') + Step::make('Register new GitHub OAuth App') ->schema([ TextEntry::make('create_application') ->hiddenLabel() - ->state(new HtmlString(Blade::render('

Visit the Github Developer Dashboard, go to OAuth Apps and click on New OAuth App.

Enter an Application name (e.g. your panel name), set Homepage URL to your panel url and enter the below url as Authorization callback URL.

'))), + ->state(new HtmlString(Blade::render('

Visit the GitHub Developer Dashboard, go to OAuth Apps and click on New OAuth App.

Enter an Application name (e.g. your panel name), set Homepage URL to your panel url and enter the below url as Authorization callback URL.

'))), TextInput::make('_noenv_callback') ->label('Authorization callback URL') ->dehydrated() diff --git a/app/Filament/Admin/Resources/Nodes/Pages/CreateNode.php b/app/Filament/Admin/Resources/Nodes/Pages/CreateNode.php index 5850bc8b8e..b5de18d5d9 100644 --- a/app/Filament/Admin/Resources/Nodes/Pages/CreateNode.php +++ b/app/Filament/Admin/Resources/Nodes/Pages/CreateNode.php @@ -253,13 +253,11 @@ public function form(Schema $schema): Schema ->columnSpan(2), TextInput::make('upload_size') ->label(trans('admin/node.upload_limit')) - ->helperText(trans('admin/node.upload_limit_help.0')) - ->hintIcon('tabler-question-mark', trans('admin/node.upload_limit_help.1')) + ->hintIcon('tabler-question-mark', trans('admin/node.upload_limit_help')) ->columnSpan(1) ->numeric()->required() ->default(256) ->minValue(1) - ->maxValue(1024) ->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB'), TextInput::make('daemon_sftp') ->columnSpan(1) diff --git a/app/Filament/Admin/Resources/Nodes/Pages/EditNode.php b/app/Filament/Admin/Resources/Nodes/Pages/EditNode.php index 20cd7036c6..0497beae22 100644 --- a/app/Filament/Admin/Resources/Nodes/Pages/EditNode.php +++ b/app/Filament/Admin/Resources/Nodes/Pages/EditNode.php @@ -319,10 +319,10 @@ public function form(Schema $schema): Schema 'lg' => 1, ]) ->label(trans('admin/node.upload_limit')) - ->hintIcon('tabler-question-mark', trans('admin/node.upload_limit_help.0') . trans('admin/node.upload_limit_help.1')) - ->numeric()->required() + ->hintIcon('tabler-question-mark', trans('admin/node.upload_limit_help')) + ->numeric() + ->required() ->minValue(1) - ->maxValue(1024) ->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB'), TextInput::make('daemon_sftp') ->columnSpan([ diff --git a/app/Http/Controllers/Api/Client/Servers/BackupController.php b/app/Http/Controllers/Api/Client/Servers/BackupController.php index fd6217ad60..d5492cbcd8 100644 --- a/app/Http/Controllers/Api/Client/Servers/BackupController.php +++ b/app/Http/Controllers/Api/Client/Servers/BackupController.php @@ -83,15 +83,21 @@ public function store(StoreBackupRequest $request, Server $server): array // how best to allow a user to create a backup that is locked without also preventing // them from just filling up a server with backups that can never be deleted? if ($request->user()->can(SubuserPermission::BackupDelete, $server)) { - $action->setIsLocked((bool) $request->input('is_locked')); + $action->setIsLocked($request->boolean('is_locked')); } - $backup = $action->handle($server, $request->input('name')); + $backup = Activity::event('server:backup.start')->transaction(function ($log) use ($action, $server, $request) { + $server->backups()->lockForUpdate(); - Activity::event('server:backup.start') - ->subject($backup) - ->property(['name' => $backup->name, 'locked' => (bool) $request->input('is_locked')]) - ->log(); + $backup = $action->handle($server, $request->input('name')); + + $log->subject($backup)->property([ + 'name' => $backup->name, + 'locked' => $request->boolean('is_locked'), + ]); + + return $backup; + }); return $this->fractal->item($backup) ->transformWith($this->getTransformer(BackupTransformer::class)) diff --git a/app/Http/Controllers/Api/Client/Servers/DatabaseController.php b/app/Http/Controllers/Api/Client/Servers/DatabaseController.php index 2ce65f0173..445c8b2bcc 100644 --- a/app/Http/Controllers/Api/Client/Servers/DatabaseController.php +++ b/app/Http/Controllers/Api/Client/Servers/DatabaseController.php @@ -59,12 +59,15 @@ public function index(GetDatabasesRequest $request, Server $server): array */ public function store(StoreDatabaseRequest $request, Server $server): array { - $database = $this->deployDatabaseService->handle($server, $request->validated()); + $database = Activity::event('server:database.create')->transaction(function ($log) use ($request, $server) { + $server->databases()->lockForUpdate(); - Activity::event('server:database.create') - ->subject($database) - ->property('name', $database->database) - ->log(); + $database = $this->deployDatabaseService->handle($server, $request->validated()); + + $log->subject($database)->property('name', $database->database); + + return $database; + }); return $this->fractal->item($database) ->parseIncludes(['password']) diff --git a/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php b/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php index 08bfb54f20..fc8ae338d9 100644 --- a/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php +++ b/app/Http/Controllers/Api/Client/Servers/NetworkAllocationController.php @@ -107,16 +107,19 @@ public function setPrimary(SetPrimaryAllocationRequest $request, Server $server, */ public function store(NewAllocationRequest $request, Server $server): array { - if ($server->allocations()->count() >= $server->allocation_limit) { - throw new DisplayException('Cannot assign additional allocations to this server: limit has been reached.'); - } + $allocation = Activity::event('server:allocation.create')->transaction(function ($log) use ($server) { + $server->allocations()->lockForUpdate(); - $allocation = $this->assignableAllocationService->handle($server); + if ($server->allocations->count() >= $server->allocation_limit) { + throw new DisplayException('Cannot assign additional allocations to this server: limit has been reached.'); + } - Activity::event('server:allocation.create') - ->subject($allocation) - ->property('allocation', $allocation->address) - ->log(); + $allocation = $this->assignableAllocationService->handle($server); + + $log->subject($allocation)->property('allocation', $allocation->address); + + return $allocation; + }); return $this->fractal->item($allocation) ->transformWith($this->getTransformer(AllocationTransformer::class)) diff --git a/app/Http/Controllers/Api/Remote/Backups/BackupRemoteUploadController.php b/app/Http/Controllers/Api/Remote/Backups/BackupRemoteUploadController.php index 77d869949f..fa149c31e6 100644 --- a/app/Http/Controllers/Api/Remote/Backups/BackupRemoteUploadController.php +++ b/app/Http/Controllers/Api/Remote/Backups/BackupRemoteUploadController.php @@ -131,7 +131,7 @@ public function __invoke(Request $request, string $backup): JsonResponse */ private function getConfiguredMaxPartSize(): int { - $maxPartSize = (int) config('backups.max_part_size', self::DEFAULT_MAX_PART_SIZE); + $maxPartSize = config('backups.max_part_size', self::DEFAULT_MAX_PART_SIZE); if ($maxPartSize <= 0) { $maxPartSize = self::DEFAULT_MAX_PART_SIZE; } diff --git a/app/Models/Node.php b/app/Models/Node.php index 69b1072d51..4c5479dc3f 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -110,7 +110,7 @@ class Node extends Model implements Validatable 'daemon_listen' => ['required', 'numeric', 'between:1,65535'], 'daemon_connect' => ['required', 'numeric', 'between:1,65535'], 'maintenance_mode' => ['boolean'], - 'upload_size' => ['int', 'between:1,1024'], + 'upload_size' => ['int', 'min:1'], 'tags' => ['array'], ]; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 311e3d0fc0..36c42d07cd 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Enums\ResourceLimit; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Foundation\Http\Middleware\TrimStrings; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; @@ -98,5 +99,7 @@ protected function configureRateLimiting(): void config('http.rate_limit.application') )->by($key); }); + + ResourceLimit::boot(); } } diff --git a/app/Repositories/Daemon/DaemonServerRepository.php b/app/Repositories/Daemon/DaemonServerRepository.php index e4abe7408e..6088acf130 100644 --- a/app/Repositories/Daemon/DaemonServerRepository.php +++ b/app/Repositories/Daemon/DaemonServerRepository.php @@ -133,6 +133,9 @@ public function cancelTransfer(): void * make it easier to revoke tokens on the fly. This ensures that the JTI key is formatted * correctly and avoids any costly mistakes in the codebase. * + * @deprecated + * @see self::deauthorize() + * * @throws ConnectionException */ public function revokeUserJTI(int $id): void @@ -143,6 +146,21 @@ public function revokeUserJTI(int $id): void ]); } + /** + * Deauthorizes a user (disconnects websockets and SFTP) on the Wings instance for the server. + * + * @throws ConnectionException + */ + public function deauthorize(string $user): void + { + $this->getHttpClient()->post('/api/deauthorize-user', [ + 'json' => [ + 'user' => $user, + 'servers' => [$this->server->uuid], + ], + ]); + } + public function getInstallLogs(): string { return $this->getHttpClient() diff --git a/app/Services/Servers/DetailsModificationService.php b/app/Services/Servers/DetailsModificationService.php index b3b789d604..e8c40e3c56 100644 --- a/app/Services/Servers/DetailsModificationService.php +++ b/app/Services/Servers/DetailsModificationService.php @@ -48,7 +48,7 @@ public function handle(Server $server, array $data): Server // websockets. if ($server->owner_id !== $owner) { try { - $this->serverRepository->setServer($server)->revokeUserJTI($owner); + $this->serverRepository->setServer($server)->deauthorize($server->user->uuid); } catch (ConnectionException) { // Do nothing. A failure here is not ideal, but it is likely to be caused by daemon // being offline, or in an entirely broken state. Remember, these tokens reset every diff --git a/app/Services/Servers/ServerDeletionService.php b/app/Services/Servers/ServerDeletionService.php index 925694f271..7f59d017c5 100644 --- a/app/Services/Servers/ServerDeletionService.php +++ b/app/Services/Servers/ServerDeletionService.php @@ -78,7 +78,10 @@ public function handle(Server $server): void } } - $server->allocations()->update(['server_id' => null]); + $server->allocations()->update([ + 'server_id' => null, + 'notes' => null, + ]); $server->delete(); }); diff --git a/app/Services/Subusers/SubuserDeletionService.php b/app/Services/Subusers/SubuserDeletionService.php index b68b948f86..bbf232995d 100644 --- a/app/Services/Subusers/SubuserDeletionService.php +++ b/app/Services/Subusers/SubuserDeletionService.php @@ -28,7 +28,7 @@ public function handle(Subuser $subuser, Server $server): void event(new SubUserRemoved($subuser->server, $subuser->user)); try { - $this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id); + $this->serverRepository->setServer($server)->deauthorize($subuser->user->uuid); } catch (ConnectionException $exception) { // Don't block this request if we can't connect to the daemon instance. logger()->warning($exception, ['user_id' => $subuser->user_id, 'server_id' => $server->id]); diff --git a/app/Services/Subusers/SubuserUpdateService.php b/app/Services/Subusers/SubuserUpdateService.php index 14fd9decd2..1ce9c0ac53 100644 --- a/app/Services/Subusers/SubuserUpdateService.php +++ b/app/Services/Subusers/SubuserUpdateService.php @@ -46,7 +46,7 @@ public function handle(Subuser $subuser, Server $server, array $permissions): vo $subuser->update(['permissions' => $cleanedPermissions]); try { - $this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id); + $this->serverRepository->setServer($server)->deauthorize($subuser->user->uuid); } catch (ConnectionException $exception) { // Don't block this request if we can't connect to the daemon instance. Chances are it is // offline and the token will be invalid once daemon boots back. diff --git a/bootstrap/app.php b/bootstrap/app.php index d40ab8cc38..cd5ca70057 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -44,6 +44,10 @@ 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'node.maintenance' => \App\Http\Middleware\MaintenanceMiddleware::class, ]); + + $middleware->priority([ + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ]); }) ->withSingletons([ \Illuminate\Contracts\Console\Kernel::class => \App\Console\Kernel::class, diff --git a/config/backups.php b/config/backups.php index 0074bf8d7a..c3bf16cf71 100644 --- a/config/backups.php +++ b/config/backups.php @@ -1,5 +1,6 @@ env('BACKUP_PRESIGNED_URL_LIFESPAN', 60), + 'presigned_url_lifespan' => (int) env('BACKUP_PRESIGNED_URL_LIFESPAN', 60), // This value defines the maximal size of a single part for the S3 multipart upload during backups // The maximal part size must be given in bytes. The default value is 5GB. // Note that 5GB is the maximum for a single part when using AWS S3. - 'max_part_size' => env('BACKUP_MAX_PART_SIZE', 5 * 1024 * 1024 * 1024), + 'max_part_size' => (int) env('BACKUP_MAX_PART_SIZE', BackupRemoteUploadController::DEFAULT_MAX_PART_SIZE), // The time to wait before automatically failing a backup, time is in minutes and defaults // to 6 hours. To disable this feature, set the value to `0`. - 'prune_age' => env('BACKUP_PRUNE_AGE', 360), + 'prune_age' => (int) env('BACKUP_PRUNE_AGE', 360), // Defines the backup creation throttle limits for users. In this default example, we allow // a user to create two (successful or pending) backups per 10 minutes. Even if they delete @@ -27,8 +28,8 @@ // // Set the period to "0" to disable this throttle. The period is defined in seconds. 'throttles' => [ - 'limit' => env('BACKUP_THROTTLE_LIMIT', 2), - 'period' => env('BACKUP_THROTTLE_PERIOD', 600), + 'limit' => (int) env('BACKUP_THROTTLE_LIMIT', 2), + 'period' => (int) env('BACKUP_THROTTLE_PERIOD', 600), ], 'disks' => [ diff --git a/config/http.php b/config/http.php index ed54e475b1..69bf4b5305 100644 --- a/config/http.php +++ b/config/http.php @@ -13,7 +13,7 @@ */ 'rate_limit' => [ 'client_period' => 1, - 'client' => env('APP_API_CLIENT_RATELIMIT', 720), + 'client' => env('APP_API_CLIENT_RATELIMIT', 120), 'application_period' => 1, 'application' => env('APP_API_APPLICATION_RATELIMIT', 240), diff --git a/contributing.md b/contributing.md index 70cc654c71..627c04e4c4 100644 --- a/contributing.md +++ b/contributing.md @@ -8,7 +8,7 @@ To start contributing to Pelican Panel, you need to have a basic understanding o * [PHP](https://php.net) & [Laravel](https://laravel.com) * [Livewire](https://laravel-livewire.com) & [Filament](https://filamentphp.com) -* [Git](https://git-scm.com) & [Github](https://github.com) +* [Git](https://git-scm.com) & [GitHub](https://github.com) ## Dev Environment Setup diff --git a/database/migrations/2026_01_09_134116_clear_unused_allocation_notes.php b/database/migrations/2026_01_09_134116_clear_unused_allocation_notes.php new file mode 100644 index 0000000000..6eb6e5c2d1 --- /dev/null +++ b/database/migrations/2026_01_09_134116_clear_unused_allocation_notes.php @@ -0,0 +1,25 @@ +whereNull('server_id') + ->update(['notes' => null]); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Not needed + } +}; diff --git a/lang/en/admin/node.php b/lang/en/admin/node.php index 40b514673c..32b3fdd322 100644 --- a/lang/en/admin/node.php +++ b/lang/en/admin/node.php @@ -61,10 +61,7 @@ 'tags' => 'Tags', 'upload_limit' => 'Upload Limit', - 'upload_limit_help' => [ - 'Enter the maximum size of files that can be uploaded through the web-based file manager.', - 'Make sure your webserver supports file uploads of this size!', - ], + 'upload_limit_help' => 'Enter the maximum size of files that can be uploaded through the web-based file manager.', 'sftp_port' => 'SFTP Port', 'sftp_alias' => 'SFTP Alias', 'sftp_alias_help' => 'Display alias for the SFTP address. Leave empty to use the Node FQDN.', diff --git a/routes/api-client.php b/routes/api-client.php index 12ab28af7d..4365cfeb22 100644 --- a/routes/api-client.php +++ b/routes/api-client.php @@ -1,5 +1,6 @@ middleware([ServerSubject::class, AuthenticateServerAccess::class, ResourceBelongsToServer::class])->group(function () { Route::get('/', [Client\Servers\ServerController::class, 'index'])->name('api:client:server.view'); - Route::get('/websocket', Client\Servers\WebsocketController::class)->name('api:client:server.ws'); + Route::middleware([ResourceLimit::Websocket->middleware()]) + ->get('/websocket', Client\Servers\WebsocketController::class) + ->name('api:client:server.ws'); Route::get('/resources', Client\Servers\ResourceUtilizationController::class)->name('api:client:server.resources'); Route::get('/activity', Client\Servers\ActivityLogController::class)->name('api:client:server.activity'); @@ -59,7 +62,8 @@ Route::prefix('/databases')->group(function () { Route::get('/', [Client\Servers\DatabaseController::class, 'index']); - Route::post('/', [Client\Servers\DatabaseController::class, 'store']); + Route::middleware([ResourceLimit::DatabaseCreate->middleware()]) + ->post('/', [Client\Servers\DatabaseController::class, 'store']); Route::post('/{database}/rotate-password', [Client\Servers\DatabaseController::class, 'rotatePassword']); Route::delete('/{database}', [Client\Servers\DatabaseController::class, 'delete']); }); @@ -76,13 +80,15 @@ Route::post('/delete', [Client\Servers\FileController::class, 'delete']); Route::post('/create-folder', [Client\Servers\FileController::class, 'create']); Route::post('/chmod', [Client\Servers\FileController::class, 'chmod']); - Route::post('/pull', [Client\Servers\FileController::class, 'pull'])->middleware(['throttle:10,5']); + Route::middleware([ResourceLimit::FilePull->middleware()]) + ->post('/pull', [Client\Servers\FileController::class, 'pull']); Route::get('/upload', Client\Servers\FileUploadController::class); }); Route::prefix('/schedules')->group(function () { Route::get('/', [Client\Servers\ScheduleController::class, 'index']); - Route::post('/', [Client\Servers\ScheduleController::class, 'store']); + Route::middleware([ResourceLimit::ScheduleCreate->middleware()]) + ->post('/', [Client\Servers\ScheduleController::class, 'store']); Route::get('/{schedule}', [Client\Servers\ScheduleController::class, 'view']); Route::post('/{schedule}', [Client\Servers\ScheduleController::class, 'update']); Route::post('/{schedule}/execute', [Client\Servers\ScheduleController::class, 'execute']); @@ -95,7 +101,8 @@ Route::prefix('/network/allocations')->group(function () { Route::get('/', [Client\Servers\NetworkAllocationController::class, 'index']); - Route::post('/', [Client\Servers\NetworkAllocationController::class, 'store']); + Route::middleware([ResourceLimit::AllocationCreate->middleware()]) + ->post('/', [Client\Servers\NetworkAllocationController::class, 'store']); Route::post('/{allocation}', [Client\Servers\NetworkAllocationController::class, 'update']); Route::post('/{allocation}/primary', [Client\Servers\NetworkAllocationController::class, 'setPrimary']); Route::delete('/{allocation}', [Client\Servers\NetworkAllocationController::class, 'delete']); @@ -103,7 +110,8 @@ Route::prefix('/users')->group(function () { Route::get('/', [Client\Servers\SubuserController::class, 'index']); - Route::post('/', [Client\Servers\SubuserController::class, 'store']); + Route::middleware([ResourceLimit::SubuserCreate->middleware()]) + ->post('/', [Client\Servers\SubuserController::class, 'store']); Route::get('/{user:uuid}', [Client\Servers\SubuserController::class, 'view']); Route::post('/{user:uuid}', [Client\Servers\SubuserController::class, 'update']); Route::delete('/{user:uuid}', [Client\Servers\SubuserController::class, 'delete']); @@ -116,7 +124,8 @@ Route::get('/{backup:uuid}/download', [Client\Servers\BackupController::class, 'download']); Route::put('/{backup:uuid}/rename', [Client\Servers\BackupController::class, 'rename']); Route::post('/{backup:uuid}/lock', [Client\Servers\BackupController::class, 'toggleLock']); - Route::post('/{backup:uuid}/restore', [Client\Servers\BackupController::class, 'restore']); + Route::middleware([ResourceLimit::BackupRestore->middleware()]) + ->post('/{backup:uuid}/restore', [Client\Servers\BackupController::class, 'restore']); Route::delete('/{backup:uuid}', [Client\Servers\BackupController::class, 'delete']); }); diff --git a/security.md b/security.md index 093456c581..520e6e2d6a 100644 --- a/security.md +++ b/security.md @@ -8,8 +8,9 @@ While Pelican is in beta, we only provide security fixes for the most recent bet ## Reporting a Vulnerability Please report any vulnerabilities via _one_ of the following methods: -- [Create a security advisory on Github](https://github.com/pelican-dev/panel/security/advisories/new) -- Send an e-mail to team@pelican.dev + +- [Create a security advisory on GitHub](https://github.com/pelican-dev/panel/security/advisories/new) +- Send an e-mail to Include steps to reproduce, affected versions, impact, and a proof of concept if available. diff --git a/tests/Integration/Api/Client/Server/Subuser/DeleteSubuserTest.php b/tests/Integration/Api/Client/Server/Subuser/DeleteSubuserTest.php index 63440a0845..f0a368c25f 100644 --- a/tests/Integration/Api/Client/Server/Subuser/DeleteSubuserTest.php +++ b/tests/Integration/Api/Client/Server/Subuser/DeleteSubuserTest.php @@ -42,7 +42,7 @@ public function test_correct_subuser_is_deleted_from_server(): void 'permissions' => [SubuserPermission::WebsocketConnect], ]); - $mock->expects('setServer->revokeUserJTI')->with($subuser->id)->andReturnUndefined(); + $mock->expects('setServer->deauthorize')->with($subuser->uuid)->andReturnUndefined(); $this->actingAs($user)->deleteJson($this->link($server) . "/users/$subuser->uuid")->assertNoContent(); @@ -58,7 +58,7 @@ public function test_correct_subuser_is_deleted_from_server(): void 'permissions' => [SubuserPermission::WebsocketConnect], ]); - $mock->expects('setServer->revokeUserJTI')->with($subuser->id)->andReturnUndefined(); + $mock->expects('setServer->deauthorize')->with($subuser->uuid)->andReturnUndefined(); $this->actingAs($user)->deleteJson($this->link($server) . "/users/$subuser->uuid")->assertNoContent(); } diff --git a/tests/Integration/Api/Client/Server/Subuser/SubuserAuthorizationTest.php b/tests/Integration/Api/Client/Server/Subuser/SubuserAuthorizationTest.php index 31370dcc70..b838c97783 100644 --- a/tests/Integration/Api/Client/Server/Subuser/SubuserAuthorizationTest.php +++ b/tests/Integration/Api/Client/Server/Subuser/SubuserAuthorizationTest.php @@ -37,7 +37,7 @@ public function test_user_cannot_access_resource_belonging_to_other_servers(stri $this->instance(DaemonServerRepository::class, $mock = \Mockery::mock(DaemonServerRepository::class)); if ($method === 'DELETE') { - $mock->expects('setServer->revokeUserJTI')->with($internal->id)->andReturnUndefined(); + $mock->expects('setServer->deauthorize')->with($internal->uuid)->andReturnUndefined(); } // This route is acceptable since they're accessing a subuser on their own server.