From 49e9440e0f9c055dd44d36a9e93ac22fab6f95d5 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Thu, 7 Aug 2025 11:16:32 +0200 Subject: [PATCH 1/7] Fix server creation without deployment (#1569) --- app/Services/Servers/ServerCreationService.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index 6fd76e55c..276311ebe 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -39,15 +39,7 @@ class ServerCreationService * as possible given the input data. For example, if an allocation_id is passed with * no node_id the node_is will be picked from the allocation. * - * @param array{ - * node_id?: int, - * oom_killer?: bool, - * oom_disabled?: bool, - * egg_id?: int, - * image?: ?string, - * startup?: ?string, - * start_on_completion?: ?bool, - * } $data + * @param array $data * * @throws \Throwable * @throws \App\Exceptions\DisplayException @@ -94,6 +86,8 @@ class ServerCreationService if (empty($data['node_id'])) { $data['node_id'] = $nodes->first(); } + } else { + $data['node_id'] = Allocation::find($data['allocation_id'])?->node_id; } Assert::false(empty($data['node_id']), 'Expected a non-empty node_id in server creation data.'); From 7c315ac99570490eea1a5e33444f3b5e40efea4e Mon Sep 17 00:00:00 2001 From: Boy132 Date: Thu, 7 Aug 2025 11:22:30 +0200 Subject: [PATCH 2/7] Auto create missing users when using oauth (#1573) --- app/Extensions/OAuth/OAuthSchemaInterface.php | 2 + app/Extensions/OAuth/Schemas/OAuthSchema.php | 20 ++++++ app/Http/Controllers/Auth/OAuthController.php | 61 +++++++++++++------ .../Subusers/SubuserCreationService.php | 7 --- app/Services/Users/UserCreationService.php | 11 ++++ lang/en/admin/setting.php | 1 + 6 files changed, 78 insertions(+), 24 deletions(-) diff --git a/app/Extensions/OAuth/OAuthSchemaInterface.php b/app/Extensions/OAuth/OAuthSchemaInterface.php index 837705888..6d7610677 100644 --- a/app/Extensions/OAuth/OAuthSchemaInterface.php +++ b/app/Extensions/OAuth/OAuthSchemaInterface.php @@ -32,4 +32,6 @@ interface OAuthSchemaInterface public function getHexColor(): ?string; public function isEnabled(): bool; + + public function shouldCreateMissingUsers(): bool; } diff --git a/app/Extensions/OAuth/Schemas/OAuthSchema.php b/app/Extensions/OAuth/Schemas/OAuthSchema.php index 0f5873d41..250dba5da 100644 --- a/app/Extensions/OAuth/Schemas/OAuthSchema.php +++ b/app/Extensions/OAuth/Schemas/OAuthSchema.php @@ -5,7 +5,9 @@ namespace App\Extensions\OAuth\Schemas; use App\Extensions\OAuth\OAuthSchemaInterface; use Filament\Forms\Components\Component; use Filament\Forms\Components\TextInput; +use Filament\Forms\Components\Toggle; use Filament\Forms\Components\Wizard\Step; +use Filament\Forms\Set; use Illuminate\Support\Str; abstract class OAuthSchema implements OAuthSchemaInterface @@ -53,6 +55,17 @@ abstract class OAuthSchema implements OAuthSchemaInterface ->revealable() ->autocomplete(false) ->default(env("OAUTH_{$id}_CLIENT_SECRET")), + Toggle::make("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS") + ->label(trans('admin/setting.oauth.create_missing_users')) + ->columnSpanFull() + ->inline(false) + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS", (bool) $state)) + ->default(env("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS")), ]; } @@ -96,4 +109,11 @@ abstract class OAuthSchema implements OAuthSchemaInterface return env("OAUTH_{$id}_ENABLED", false); } + + public function shouldCreateMissingUsers(): bool + { + $id = Str::upper($this->getId()); + + return env("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS", false); + } } diff --git a/app/Http/Controllers/Auth/OAuthController.php b/app/Http/Controllers/Auth/OAuthController.php index 97e6a4f15..31de3cb9d 100644 --- a/app/Http/Controllers/Auth/OAuthController.php +++ b/app/Http/Controllers/Auth/OAuthController.php @@ -6,8 +6,8 @@ use App\Extensions\OAuth\OAuthService; use App\Filament\Pages\Auth\EditProfile; use App\Http\Controllers\Controller; use App\Models\User; +use App\Services\Users\UserCreationService; use App\Services\Users\UserUpdateService; -use Exception; use Filament\Notifications\Notification; use Illuminate\Auth\AuthManager; use Illuminate\Http\RedirectResponse; @@ -18,8 +18,9 @@ class OAuthController extends Controller { public function __construct( private readonly AuthManager $auth, + private UserCreationService $userCreation, private readonly UserUpdateService $updateService, - private readonly OAuthService $oauthService + private readonly OAuthService $oauthService, ) {} /** @@ -40,8 +41,10 @@ class OAuthController extends Controller */ public function callback(Request $request, string $driver): RedirectResponse { - // Driver is disabled - redirect to normal login - if (!$this->oauthService->get($driver)?->isEnabled()) { + $driver = $this->oauthService->get($driver); + + // Unknown driver or driver is disabled - redirect to normal login + if (!$driver || !$driver->isEnabled()) { return redirect()->route('auth.login'); } @@ -59,33 +62,57 @@ class OAuthController extends Controller return redirect()->route('auth.login'); } - $oauthUser = Socialite::driver($driver)->user(); + $oauthUser = Socialite::driver($driver->getId())->user(); // User is already logged in and wants to link a new OAuth Provider if ($request->user()) { $oauth = $request->user()->oauth; - $oauth[$driver] = $oauthUser->getId(); + $oauth[$driver->getId()] = $oauthUser->getId(); $this->updateService->handle($request->user(), ['oauth' => $oauth]); return redirect(EditProfile::getUrl(['tab' => '-oauth-tab'], panel: 'app')); } - try { - $user = User::query()->whereJsonContains('oauth->'. $driver, $oauthUser->getId())->firstOrFail(); + $user = User::whereJsonContains('oauth->'. $driver->getId(), $oauthUser->getId())->first(); - $this->auth->guard()->login($user, true); - } catch (Exception) { - // No user found - redirect to normal login - Notification::make() - ->title('No linked User found') - ->danger() - ->persistent() - ->send(); + if (!$user) { + // No user found and auto creation is disabled - redirect to normal login + if (!$driver->shouldCreateMissingUsers()) { + Notification::make() + ->title('No linked User found') + ->danger() + ->persistent() + ->send(); - return redirect()->route('auth.login'); + return redirect()->route('auth.login'); + } + + $username = $oauthUser->getNickname(); + $email = $oauthUser->getEmail(); + + // Incomplete data, can't create user - redirect to normal login + if (!$email) { + Notification::make() + ->title('No linked User found') + ->danger() + ->persistent() + ->send(); + + return redirect()->route('auth.login'); + } + + $user = $this->userCreation->handle([ + 'username' => $username, + 'email' => $email, + 'oauth' => [ + $driver->getId() => $oauthUser->getId(), + ], + ]); } + $this->auth->guard()->login($user, true); + return redirect('/'); } } diff --git a/app/Services/Subusers/SubuserCreationService.php b/app/Services/Subusers/SubuserCreationService.php index 4fe6e5093..cafb22873 100644 --- a/app/Services/Subusers/SubuserCreationService.php +++ b/app/Services/Subusers/SubuserCreationService.php @@ -4,7 +4,6 @@ namespace App\Services\Subusers; use App\Events\Server\SubUserAdded; use App\Models\User; -use Illuminate\Support\Str; use App\Models\Server; use App\Models\Subuser; use Illuminate\Database\ConnectionInterface; @@ -40,14 +39,8 @@ class SubuserCreationService return $this->connection->transaction(function () use ($server, $email, $permissions) { $user = User::query()->where('email', $email)->first(); if (!$user) { - // Just cap the username generated at 64 characters at most and then append a random string - // to the end to make it "unique"... - [$beforeDomain] = explode('@', $email, 1); - $username = substr(preg_replace('/([^\w.-]+)/', '', $beforeDomain), 0, 64) . Str::random(3); - $user = $this->userCreationService->handle([ 'email' => $email, - 'username' => $username, 'root_admin' => false, ]); } diff --git a/app/Services/Users/UserCreationService.php b/app/Services/Users/UserCreationService.php index 589b7e45e..644dac7f5 100644 --- a/app/Services/Users/UserCreationService.php +++ b/app/Services/Users/UserCreationService.php @@ -3,6 +3,7 @@ namespace App\Services\Users; use App\Models\Role; +use Illuminate\Support\Str; use Ramsey\Uuid\Uuid; use App\Models\User; use Illuminate\Contracts\Hashing\Hasher; @@ -42,6 +43,16 @@ class UserCreationService $isRootAdmin = array_key_exists('root_admin', $data) && $data['root_admin']; unset($data['root_admin']); + if (empty($data['username'])) { + $data['username'] = str($data['email'])->before('@')->toString() . Str::random(3); + } + + $data['username'] = str($data['username']) + ->replace(['.', '-'], '') + ->ascii() + ->substr(0, 64) + ->toString(); + /** @var User $user */ $user = User::query()->forceCreate(array_merge($data, [ 'uuid' => Uuid::uuid4()->toString(), diff --git a/lang/en/admin/setting.php b/lang/en/admin/setting.php index 9f0ee01be..718e9511f 100644 --- a/lang/en/admin/setting.php +++ b/lang/en/admin/setting.php @@ -97,6 +97,7 @@ return [ 'base_url' => 'Base URL', 'display_name' => 'Display Name', 'auth_url' => 'Authorization callback URL', + 'create_missing_users' => 'Auto Create Missing Users?', ], 'misc' => [ 'auto_allocation' => [ From 6a4ac515a7187a76ae76708ebaa053514781c5e1 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 9 Aug 2025 17:53:29 -0400 Subject: [PATCH 3/7] Laravel 12.22.1 Shift (#1580) Co-authored-by: Shift --- composer.json | 2 +- composer.lock | 483 ++++++++++++++++++++++++++++---------------------- 2 files changed, 271 insertions(+), 214 deletions(-) diff --git a/composer.json b/composer.json index e14dc4fca..bc86b449c 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "doctrine/dbal": "~3.6.0", "filament/filament": "^3.3", "guzzlehttp/guzzle": "^7.9", - "laravel/framework": "^12.21", + "laravel/framework": "^12.22", "laravel/helpers": "^1.7", "laravel/sanctum": "^4.1", "laravel/socialite": "^5.21", diff --git a/composer.lock b/composer.lock index 2f1dc9f2c..22b374ce3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c1c3e31cb57271e9ce2edcc715d16d4c", + "content-hash": "7138d3f3e583251a87fcbf5157c43315", "packages": [ { "name": "abdelhamiderrahmouni/filament-monaco-editor", @@ -900,16 +900,16 @@ }, { "name": "anourvalar/eloquent-serialize", - "version": "1.3.3", + "version": "1.3.4", "source": { "type": "git", "url": "https://github.com/AnourValar/eloquent-serialize.git", - "reference": "2f05023f1e465a91dc4f08483e6710325641a444" + "reference": "0934a98866e02b73e38696961a9d7984b834c9d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/AnourValar/eloquent-serialize/zipball/2f05023f1e465a91dc4f08483e6710325641a444", - "reference": "2f05023f1e465a91dc4f08483e6710325641a444", + "url": "https://api.github.com/repos/AnourValar/eloquent-serialize/zipball/0934a98866e02b73e38696961a9d7984b834c9d9", + "reference": "0934a98866e02b73e38696961a9d7984b834c9d9", "shasum": "" }, "require": { @@ -960,9 +960,9 @@ ], "support": { "issues": "https://github.com/AnourValar/eloquent-serialize/issues", - "source": "https://github.com/AnourValar/eloquent-serialize/tree/1.3.3" + "source": "https://github.com/AnourValar/eloquent-serialize/tree/1.3.4" }, - "time": "2025-05-28T17:07:28+00:00" + "time": "2025-07-30T15:45:57+00:00" }, { "name": "aws/aws-crt-php", @@ -1020,16 +1020,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.351.3", + "version": "3.352.4", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "7c58f4a8acd2230daad1ef23bceb9972e62bdf94" + "reference": "d3ce2a85687d55cd67d52682306227bc6aa836d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7c58f4a8acd2230daad1ef23bceb9972e62bdf94", - "reference": "7c58f4a8acd2230daad1ef23bceb9972e62bdf94", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d3ce2a85687d55cd67d52682306227bc6aa836d6", + "reference": "d3ce2a85687d55cd67d52682306227bc6aa836d6", "shasum": "" }, "require": { @@ -1111,9 +1111,9 @@ "support": { "forum": "https://github.com/aws/aws-sdk-php/discussions", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.351.3" + "source": "https://github.com/aws/aws-sdk-php/tree/3.352.4" }, - "time": "2025-07-21T18:04:02+00:00" + "time": "2025-08-07T18:15:55+00:00" }, { "name": "blade-ui-kit/blade-heroicons", @@ -1758,16 +1758,16 @@ }, { "name": "dedoc/scramble", - "version": "v0.12.23", + "version": "v0.12.28", "source": { "type": "git", "url": "https://github.com/dedoc/scramble.git", - "reference": "5b650167c81c59138e844c2ae550c14dc1a249d0" + "reference": "f06a98d1fd6678544428df7077d73194e2d28de3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dedoc/scramble/zipball/5b650167c81c59138e844c2ae550c14dc1a249d0", - "reference": "5b650167c81c59138e844c2ae550c14dc1a249d0", + "url": "https://api.github.com/repos/dedoc/scramble/zipball/f06a98d1fd6678544428df7077d73194e2d28de3", + "reference": "f06a98d1fd6678544428df7077d73194e2d28de3", "shasum": "" }, "require": { @@ -1826,7 +1826,7 @@ ], "support": { "issues": "https://github.com/dedoc/scramble/issues", - "source": "https://github.com/dedoc/scramble/tree/v0.12.23" + "source": "https://github.com/dedoc/scramble/tree/v0.12.28" }, "funding": [ { @@ -1834,7 +1834,7 @@ "type": "github" } ], - "time": "2025-06-15T09:04:49+00:00" + "time": "2025-08-04T12:20:10+00:00" }, { "name": "dflydev/dot-access-data", @@ -2558,7 +2558,7 @@ }, { "name": "filament/actions", - "version": "v3.3.33", + "version": "v3.3.35", "source": { "type": "git", "url": "https://github.com/filamentphp/actions.git", @@ -2611,16 +2611,16 @@ }, { "name": "filament/filament", - "version": "v3.3.33", + "version": "v3.3.35", "source": { "type": "git", "url": "https://github.com/filamentphp/panels.git", - "reference": "8e6618036c9235d968740d43bb8afb58fe705e5b" + "reference": "d9d2367c910956e1e7a4c2903600f37bd740dd11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/panels/zipball/8e6618036c9235d968740d43bb8afb58fe705e5b", - "reference": "8e6618036c9235d968740d43bb8afb58fe705e5b", + "url": "https://api.github.com/repos/filamentphp/panels/zipball/d9d2367c910956e1e7a4c2903600f37bd740dd11", + "reference": "d9d2367c910956e1e7a4c2903600f37bd740dd11", "shasum": "" }, "require": { @@ -2672,20 +2672,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-07-21T10:08:08+00:00" + "time": "2025-08-04T10:34:25+00:00" }, { "name": "filament/forms", - "version": "v3.3.33", + "version": "v3.3.35", "source": { "type": "git", "url": "https://github.com/filamentphp/forms.git", - "reference": "72ec2ede65d8e9fa979a066bce78812458793dde" + "reference": "158177c4a551c8aba5be3f45bc423195ab28e5bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/forms/zipball/72ec2ede65d8e9fa979a066bce78812458793dde", - "reference": "72ec2ede65d8e9fa979a066bce78812458793dde", + "url": "https://api.github.com/repos/filamentphp/forms/zipball/158177c4a551c8aba5be3f45bc423195ab28e5bc", + "reference": "158177c4a551c8aba5be3f45bc423195ab28e5bc", "shasum": "" }, "require": { @@ -2728,11 +2728,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-07-21T10:07:59+00:00" + "time": "2025-08-04T10:34:20+00:00" }, { "name": "filament/infolists", - "version": "v3.3.33", + "version": "v3.3.35", "source": { "type": "git", "url": "https://github.com/filamentphp/infolists.git", @@ -2783,7 +2783,7 @@ }, { "name": "filament/notifications", - "version": "v3.3.33", + "version": "v3.3.35", "source": { "type": "git", "url": "https://github.com/filamentphp/notifications.git", @@ -2835,16 +2835,16 @@ }, { "name": "filament/support", - "version": "v3.3.33", + "version": "v3.3.35", "source": { "type": "git", "url": "https://github.com/filamentphp/support.git", - "reference": "0bf4856840e160624ba79f43aaaa3ec396140f1d" + "reference": "89d8e729025c195a06f2e510af4517fc9a8fd07f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/support/zipball/0bf4856840e160624ba79f43aaaa3ec396140f1d", - "reference": "0bf4856840e160624ba79f43aaaa3ec396140f1d", + "url": "https://api.github.com/repos/filamentphp/support/zipball/89d8e729025c195a06f2e510af4517fc9a8fd07f", + "reference": "89d8e729025c195a06f2e510af4517fc9a8fd07f", "shasum": "" }, "require": { @@ -2890,20 +2890,20 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-07-16T08:51:22+00:00" + "time": "2025-07-28T09:02:43+00:00" }, { "name": "filament/tables", - "version": "v3.3.33", + "version": "v3.3.35", "source": { "type": "git", "url": "https://github.com/filamentphp/tables.git", - "reference": "3f0d827c960f1ee4a67ab71c416ad67e24747dc4" + "reference": "22bc439ec6f2b5fd5703ef499381d7beb0a6b369" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filamentphp/tables/zipball/3f0d827c960f1ee4a67ab71c416ad67e24747dc4", - "reference": "3f0d827c960f1ee4a67ab71c416ad67e24747dc4", + "url": "https://api.github.com/repos/filamentphp/tables/zipball/22bc439ec6f2b5fd5703ef499381d7beb0a6b369", + "reference": "22bc439ec6f2b5fd5703ef499381d7beb0a6b369", "shasum": "" }, "require": { @@ -2942,11 +2942,11 @@ "issues": "https://github.com/filamentphp/filament/issues", "source": "https://github.com/filamentphp/filament" }, - "time": "2025-07-08T20:42:18+00:00" + "time": "2025-07-28T09:02:34+00:00" }, { "name": "filament/widgets", - "version": "v3.3.33", + "version": "v3.3.35", "source": { "type": "git", "url": "https://github.com/filamentphp/widgets.git", @@ -3655,16 +3655,16 @@ }, { "name": "kirschbaum-development/eloquent-power-joins", - "version": "4.2.6", + "version": "4.2.7", "source": { "type": "git", "url": "https://github.com/kirschbaum-development/eloquent-power-joins.git", - "reference": "72cff1e838bb3f826dc09a5566219ad7fa56237f" + "reference": "f2f8d3575a54d91b3e5058d65ac1fccb3ea7dd94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kirschbaum-development/eloquent-power-joins/zipball/72cff1e838bb3f826dc09a5566219ad7fa56237f", - "reference": "72cff1e838bb3f826dc09a5566219ad7fa56237f", + "url": "https://api.github.com/repos/kirschbaum-development/eloquent-power-joins/zipball/f2f8d3575a54d91b3e5058d65ac1fccb3ea7dd94", + "reference": "f2f8d3575a54d91b3e5058d65ac1fccb3ea7dd94", "shasum": "" }, "require": { @@ -3712,22 +3712,22 @@ ], "support": { "issues": "https://github.com/kirschbaum-development/eloquent-power-joins/issues", - "source": "https://github.com/kirschbaum-development/eloquent-power-joins/tree/4.2.6" + "source": "https://github.com/kirschbaum-development/eloquent-power-joins/tree/4.2.7" }, - "time": "2025-07-10T16:55:34+00:00" + "time": "2025-08-06T10:46:13+00:00" }, { "name": "laravel/framework", - "version": "v12.21.0", + "version": "v12.22.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "ac8c4e73bf1b5387b709f7736d41427e6af1c93b" + "reference": "d33ee45184126f32f593d4b809a846ed88a1dc43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/ac8c4e73bf1b5387b709f7736d41427e6af1c93b", - "reference": "ac8c4e73bf1b5387b709f7736d41427e6af1c93b", + "url": "https://api.github.com/repos/laravel/framework/zipball/d33ee45184126f32f593d4b809a846ed88a1dc43", + "reference": "d33ee45184126f32f593d4b809a846ed88a1dc43", "shasum": "" }, "require": { @@ -3929,7 +3929,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-07-22T15:41:55+00:00" + "time": "2025-08-08T13:58:03+00:00" }, { "name": "laravel/helpers", @@ -4174,16 +4174,16 @@ }, { "name": "laravel/socialite", - "version": "v5.22.0", + "version": "v5.23.0", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "99d0fe750a7c68e5b60d8b1850de2554f3ea4072" + "reference": "e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/99d0fe750a7c68e5b60d8b1850de2554f3ea4072", - "reference": "99d0fe750a7c68e5b60d8b1850de2554f3ea4072", + "url": "https://api.github.com/repos/laravel/socialite/zipball/e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5", + "reference": "e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5", "shasum": "" }, "require": { @@ -4242,7 +4242,7 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2025-07-08T22:07:57+00:00" + "time": "2025-07-23T14:16:08+00:00" }, { "name": "laravel/tinker", @@ -5480,16 +5480,16 @@ }, { "name": "masterminds/html5", - "version": "2.9.0", + "version": "2.10.0", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" + "reference": "fcf91eb64359852f00d921887b219479b4f21251" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", "shasum": "" }, "require": { @@ -5541,9 +5541,9 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" }, - "time": "2024-03-31T07:05:07+00:00" + "time": "2025-07-25T09:04:22+00:00" }, { "name": "monolog/monolog", @@ -5716,16 +5716,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.13.3", + "version": "1.13.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "faed855a7b5f4d4637717c2b3863e277116beb36" + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36", - "reference": "faed855a7b5f4d4637717c2b3863e277116beb36", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { @@ -5764,7 +5764,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { @@ -5772,20 +5772,20 @@ "type": "tidelift" } ], - "time": "2025-07-05T12:25:42+00:00" + "time": "2025-08-01T08:46:24+00:00" }, { "name": "nesbot/carbon", - "version": "3.10.1", + "version": "3.10.2", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00" + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/1fd1935b2d90aef2f093c5e35f7ae1257c448d00", - "reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", + "reference": "76b5c07b8a9d2025ed1610e14cef1f3fd6ad2c24", "shasum": "" }, "require": { @@ -5877,7 +5877,7 @@ "type": "tidelift" } ], - "time": "2025-06-21T15:19:35+00:00" + "time": "2025-08-02T09:36:06+00:00" }, { "name": "nette/schema", @@ -5943,29 +5943,29 @@ }, { "name": "nette/utils", - "version": "v4.0.7", + "version": "v4.0.8", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" + "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede", + "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede", "shasum": "" }, "require": { - "php": "8.0 - 8.4" + "php": "8.0 - 8.5" }, "conflict": { "nette/finder": "<3", "nette/schema": "<1.2.2" }, "require-dev": { - "jetbrains/phpstorm-attributes": "dev-master", + "jetbrains/phpstorm-attributes": "^1.2", "nette/tester": "^2.5", - "phpstan/phpstan": "^1.0", + "phpstan/phpstan-nette": "^2.0@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -5983,6 +5983,9 @@ } }, "autoload": { + "psr-4": { + "Nette\\": "src" + }, "classmap": [ "src/" ] @@ -6023,22 +6026,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.7" + "source": "https://github.com/nette/utils/tree/v4.0.8" }, - "time": "2025-06-03T04:55:08+00:00" + "time": "2025-08-06T21:43:34+00:00" }, { "name": "nikic/php-parser", - "version": "v5.5.0", + "version": "v5.6.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", - "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56", + "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56", "shasum": "" }, "require": { @@ -6081,9 +6084,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0" }, - "time": "2025-05-31T08:24:38+00:00" + "time": "2025-07-27T20:03:57+00:00" }, { "name": "nunomaduro/termwind", @@ -7438,16 +7441,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.9", + "version": "v0.12.10", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "1b801844becfe648985372cb4b12ad6840245ace" + "reference": "6e80abe6f2257121f1eb9a4c55bf29d921025b22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/1b801844becfe648985372cb4b12ad6840245ace", - "reference": "1b801844becfe648985372cb4b12ad6840245ace", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/6e80abe6f2257121f1eb9a4c55bf29d921025b22", + "reference": "6e80abe6f2257121f1eb9a4c55bf29d921025b22", "shasum": "" }, "require": { @@ -7497,12 +7500,11 @@ "authors": [ { "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" + "email": "justin@justinhileman.info" } ], "description": "An interactive shell for modern PHP.", - "homepage": "http://psysh.org", + "homepage": "https://psysh.org", "keywords": [ "REPL", "console", @@ -7511,9 +7513,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.9" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.10" }, - "time": "2025-06-23T02:35:06+00:00" + "time": "2025-08-04T12:39:37+00:00" }, { "name": "ralouphie/getallheaders", @@ -8623,16 +8625,16 @@ }, { "name": "spatie/laravel-health", - "version": "1.34.4", + "version": "1.34.5", "source": { "type": "git", "url": "https://github.com/spatie/laravel-health.git", - "reference": "ac04fb0b82b4c89ab88c18897f9eda4e559d624b" + "reference": "8487a3a43551f3d24e73546362f93da2684a0a3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-health/zipball/ac04fb0b82b4c89ab88c18897f9eda4e559d624b", - "reference": "ac04fb0b82b4c89ab88c18897f9eda4e559d624b", + "url": "https://api.github.com/repos/spatie/laravel-health/zipball/8487a3a43551f3d24e73546362f93da2684a0a3a", + "reference": "8487a3a43551f3d24e73546362f93da2684a0a3a", "shasum": "" }, "require": { @@ -8704,7 +8706,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/laravel-health/tree/1.34.4" + "source": "https://github.com/spatie/laravel-health/tree/1.34.5" }, "funding": [ { @@ -8712,7 +8714,7 @@ "type": "github" } ], - "time": "2025-07-22T08:06:42+00:00" + "time": "2025-07-25T07:00:21+00:00" }, { "name": "spatie/laravel-package-tools", @@ -8777,16 +8779,16 @@ }, { "name": "spatie/laravel-permission", - "version": "6.20.0", + "version": "6.21.0", "source": { "type": "git", "url": "https://github.com/spatie/laravel-permission.git", - "reference": "31c05679102c73f3b0d05790d2400182745a5615" + "reference": "6a118e8855dfffcd90403aab77bbf35a03db51b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/31c05679102c73f3b0d05790d2400182745a5615", - "reference": "31c05679102c73f3b0d05790d2400182745a5615", + "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/6a118e8855dfffcd90403aab77bbf35a03db51b3", + "reference": "6a118e8855dfffcd90403aab77bbf35a03db51b3", "shasum": "" }, "require": { @@ -8848,7 +8850,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-permission/issues", - "source": "https://github.com/spatie/laravel-permission/tree/6.20.0" + "source": "https://github.com/spatie/laravel-permission/tree/6.21.0" }, "funding": [ { @@ -8856,20 +8858,20 @@ "type": "github" } ], - "time": "2025-06-05T07:33:07+00:00" + "time": "2025-07-23T16:08:05+00:00" }, { "name": "spatie/laravel-query-builder", - "version": "6.3.3", + "version": "6.3.5", "source": { "type": "git", "url": "https://github.com/spatie/laravel-query-builder.git", - "reference": "0d80323d2b2ffc410f06bf73c2e3a6ad763e4b8d" + "reference": "ee3c98235616f88c11e75d3df5ea48dc7b20dd93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-query-builder/zipball/0d80323d2b2ffc410f06bf73c2e3a6ad763e4b8d", - "reference": "0d80323d2b2ffc410f06bf73c2e3a6ad763e4b8d", + "url": "https://api.github.com/repos/spatie/laravel-query-builder/zipball/ee3c98235616f88c11e75d3df5ea48dc7b20dd93", + "reference": "ee3c98235616f88c11e75d3df5ea48dc7b20dd93", "shasum": "" }, "require": { @@ -8930,7 +8932,7 @@ "type": "custom" } ], - "time": "2025-07-14T08:31:42+00:00" + "time": "2025-08-04T07:36:33+00:00" }, { "name": "spatie/php-structure-discoverer", @@ -9211,16 +9213,16 @@ }, { "name": "symfony/console", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101" + "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/9e27aecde8f506ba0fd1d9989620c04a87697101", - "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101", + "url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1", + "reference": "5f360ebc65c55265a74d23d7fe27f957870158a1", "shasum": "" }, "require": { @@ -9285,7 +9287,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.1" + "source": "https://github.com/symfony/console/tree/v7.3.2" }, "funding": [ { @@ -9296,12 +9298,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-07-30T17:13:41+00:00" }, { "name": "symfony/css-selector", @@ -9437,16 +9443,16 @@ }, { "name": "symfony/error-handler", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "35b55b166f6752d6aaf21aa042fc5ed280fce235" + "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/35b55b166f6752d6aaf21aa042fc5ed280fce235", - "reference": "35b55b166f6752d6aaf21aa042fc5ed280fce235", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/0b31a944fcd8759ae294da4d2808cbc53aebd0c3", + "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3", "shasum": "" }, "require": { @@ -9494,7 +9500,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.3.1" + "source": "https://github.com/symfony/error-handler/tree/v7.3.2" }, "funding": [ { @@ -9505,12 +9511,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-13T07:48:40+00:00" + "time": "2025-07-07T08:17:57+00:00" }, { "name": "symfony/event-dispatcher", @@ -9670,16 +9680,16 @@ }, { "name": "symfony/finder", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d" + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d", - "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d", + "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", "shasum": "" }, "require": { @@ -9714,7 +9724,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.0" + "source": "https://github.com/symfony/finder/tree/v7.3.2" }, "funding": [ { @@ -9725,25 +9735,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-30T19:00:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/html-sanitizer", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/html-sanitizer.git", - "reference": "cf21254e982b12276329940ca4af5e623ee06c58" + "reference": "3388e208450fcac57d24aef4d5ae41037b663630" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/cf21254e982b12276329940ca4af5e623ee06c58", - "reference": "cf21254e982b12276329940ca4af5e623ee06c58", + "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/3388e208450fcac57d24aef4d5ae41037b663630", + "reference": "3388e208450fcac57d24aef4d5ae41037b663630", "shasum": "" }, "require": { @@ -9783,7 +9797,7 @@ "sanitizer" ], "support": { - "source": "https://github.com/symfony/html-sanitizer/tree/v7.3.0" + "source": "https://github.com/symfony/html-sanitizer/tree/v7.3.2" }, "funding": [ { @@ -9794,25 +9808,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-03-31T08:49:55+00:00" + "time": "2025-07-10T08:29:33+00:00" }, { "name": "symfony/http-client", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "4403d87a2c16f33345dca93407a8714ee8c05a64" + "reference": "1c064a0c67749923483216b081066642751cc2c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/4403d87a2c16f33345dca93407a8714ee8c05a64", - "reference": "4403d87a2c16f33345dca93407a8714ee8c05a64", + "url": "https://api.github.com/repos/symfony/http-client/zipball/1c064a0c67749923483216b081066642751cc2c7", + "reference": "1c064a0c67749923483216b081066642751cc2c7", "shasum": "" }, "require": { @@ -9878,7 +9896,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.1" + "source": "https://github.com/symfony/http-client/tree/v7.3.2" }, "funding": [ { @@ -9889,12 +9907,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-28T07:58:39+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { "name": "symfony/http-client-contracts", @@ -9976,16 +9998,16 @@ }, { "name": "symfony/http-foundation", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "23dd60256610c86a3414575b70c596e5deff6ed9" + "reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/23dd60256610c86a3414575b70c596e5deff6ed9", - "reference": "23dd60256610c86a3414575b70c596e5deff6ed9", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6877c122b3a6cc3695849622720054f6e6fa5fa6", + "reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6", "shasum": "" }, "require": { @@ -10035,7 +10057,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.3.1" + "source": "https://github.com/symfony/http-foundation/tree/v7.3.2" }, "funding": [ { @@ -10046,25 +10068,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-23T15:07:14+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "1644879a66e4aa29c36fe33dfa6c54b450ce1831" + "reference": "6ecc895559ec0097e221ed2fd5eb44d5fede083c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1644879a66e4aa29c36fe33dfa6c54b450ce1831", - "reference": "1644879a66e4aa29c36fe33dfa6c54b450ce1831", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6ecc895559ec0097e221ed2fd5eb44d5fede083c", + "reference": "6ecc895559ec0097e221ed2fd5eb44d5fede083c", "shasum": "" }, "require": { @@ -10149,7 +10175,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.3.1" + "source": "https://github.com/symfony/http-kernel/tree/v7.3.2" }, "funding": [ { @@ -10160,25 +10186,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-28T08:24:55+00:00" + "time": "2025-07-31T10:45:04+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "b5db5105b290bdbea5ab27b89c69effcf1cb3368" + "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/b5db5105b290bdbea5ab27b89c69effcf1cb3368", - "reference": "b5db5105b290bdbea5ab27b89c69effcf1cb3368", + "url": "https://api.github.com/repos/symfony/mailer/zipball/d43e84d9522345f96ad6283d5dfccc8c1cfc299b", + "reference": "d43e84d9522345f96ad6283d5dfccc8c1cfc299b", "shasum": "" }, "require": { @@ -10229,7 +10259,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.1" + "source": "https://github.com/symfony/mailer/tree/v7.3.2" }, "funding": [ { @@ -10240,12 +10270,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { "name": "symfony/mailgun-mailer", @@ -10318,16 +10352,16 @@ }, { "name": "symfony/mime", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9" + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", - "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", + "url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1", + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1", "shasum": "" }, "require": { @@ -10382,7 +10416,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.0" + "source": "https://github.com/symfony/mime/tree/v7.3.2" }, "funding": [ { @@ -10393,12 +10427,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-19T08:51:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/polyfill-ctype", @@ -11170,16 +11208,16 @@ }, { "name": "symfony/routing", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "8e213820c5fea844ecea29203d2a308019007c15" + "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/8e213820c5fea844ecea29203d2a308019007c15", - "reference": "8e213820c5fea844ecea29203d2a308019007c15", + "url": "https://api.github.com/repos/symfony/routing/zipball/7614b8ca5fa89b9cd233e21b627bfc5774f586e4", + "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4", "shasum": "" }, "require": { @@ -11231,7 +11269,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.3.0" + "source": "https://github.com/symfony/routing/tree/v7.3.2" }, "funding": [ { @@ -11242,12 +11280,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-24T20:43:28+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { "name": "symfony/service-contracts", @@ -11334,16 +11376,16 @@ }, { "name": "symfony/string", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125" + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125", + "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca", + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca", "shasum": "" }, "require": { @@ -11401,7 +11443,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.0" + "source": "https://github.com/symfony/string/tree/v7.3.2" }, "funding": [ { @@ -11412,25 +11454,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-20T20:19:01+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { "name": "symfony/translation", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "241d5ac4910d256660238a7ecf250deba4c73063" + "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/241d5ac4910d256660238a7ecf250deba4c73063", - "reference": "241d5ac4910d256660238a7ecf250deba4c73063", + "url": "https://api.github.com/repos/symfony/translation/zipball/81b48f4daa96272efcce9c7a6c4b58e629df3c90", + "reference": "81b48f4daa96272efcce9c7a6c4b58e629df3c90", "shasum": "" }, "require": { @@ -11497,7 +11543,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.1" + "source": "https://github.com/symfony/translation/tree/v7.3.2" }, "funding": [ { @@ -11508,12 +11554,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-07-30T17:31:46+00:00" }, { "name": "symfony/translation-contracts", @@ -11669,16 +11719,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42" + "reference": "53205bea27450dc5c65377518b3275e126d45e75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6e209fbe5f5a7b6043baba46fe5735a4b85d0d42", - "reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/53205bea27450dc5c65377518b3275e126d45e75", + "reference": "53205bea27450dc5c65377518b3275e126d45e75", "shasum": "" }, "require": { @@ -11690,7 +11740,6 @@ "symfony/console": "<6.4" }, "require-dev": { - "ext-iconv": "*", "symfony/console": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", "symfony/process": "^6.4|^7.0", @@ -11733,7 +11782,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.1" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.2" }, "funding": [ { @@ -11744,25 +11793,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-07-29T20:02:46+00:00" }, { "name": "symfony/yaml", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "0c3555045a46ab3cd4cc5a69d161225195230edb" + "reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/0c3555045a46ab3cd4cc5a69d161225195230edb", - "reference": "0c3555045a46ab3cd4cc5a69d161225195230edb", + "url": "https://api.github.com/repos/symfony/yaml/zipball/b8d7d868da9eb0919e99c8830431ea087d6aae30", + "reference": "b8d7d868da9eb0919e99c8830431ea087d6aae30", "shasum": "" }, "require": { @@ -11805,7 +11858,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.1" + "source": "https://github.com/symfony/yaml/tree/v7.3.2" }, "funding": [ { @@ -11816,12 +11869,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-03T06:57:57+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -12667,16 +12724,16 @@ }, { "name": "filp/whoops", - "version": "2.18.3", + "version": "2.18.4", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "59a123a3d459c5a23055802237cb317f609867e5" + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", - "reference": "59a123a3d459c5a23055802237cb317f609867e5", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", "shasum": "" }, "require": { @@ -12726,7 +12783,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.3" + "source": "https://github.com/filp/whoops/tree/2.18.4" }, "funding": [ { @@ -12734,7 +12791,7 @@ "type": "github" } ], - "time": "2025-06-16T00:02:10+00:00" + "time": "2025-08-08T12:00:00+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -13945,16 +14002,16 @@ }, { "name": "phpstan/phpstan", - "version": "2.1.19", + "version": "2.1.22", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "473a8c30e450d87099f76313edcbb90852f9afdf" + "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/473a8c30e450d87099f76313edcbb90852f9afdf", - "reference": "473a8c30e450d87099f76313edcbb90852f9afdf", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/41600c8379eb5aee63e9413fe9e97273e25d57e4", + "reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4", "shasum": "" }, "require": { @@ -13999,7 +14056,7 @@ "type": "github" } ], - "time": "2025-07-21T19:58:24+00:00" + "time": "2025-08-04T19:17:37+00:00" }, { "name": "phpunit/php-code-coverage", From 900f8d0fe1c6d9960b7721c778136b2372681f36 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Sat, 9 Aug 2025 23:53:45 +0200 Subject: [PATCH 4/7] Cleanup remote api requests (#1579) --- .../Remote/ActivityProcessingController.php | 5 ++- .../Servers/ServerContainersController.php | 6 +-- .../Servers/ServerDetailsController.php | 11 +++-- .../Servers/ServerInstallController.php | 11 +++-- .../Servers/ServerTransferController.php | 45 ++++++++----------- .../Api/Remote/InstallationDataRequest.php | 9 +--- .../Requests/Api/Remote/ServerRequest.php | 21 +++++++++ 7 files changed, 58 insertions(+), 50 deletions(-) create mode 100644 app/Http/Requests/Api/Remote/ServerRequest.php diff --git a/app/Http/Controllers/Api/Remote/ActivityProcessingController.php b/app/Http/Controllers/Api/Remote/ActivityProcessingController.php index ab84eb626..1dae9407a 100644 --- a/app/Http/Controllers/Api/Remote/ActivityProcessingController.php +++ b/app/Http/Controllers/Api/Remote/ActivityProcessingController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Remote; +use App\Models\Node; use Carbon\Carbon; use Illuminate\Support\Str; use App\Models\User; @@ -14,7 +15,7 @@ class ActivityProcessingController extends Controller { public function __invoke(ActivityEventRequest $request): void { - /** @var \App\Models\Node $node */ + /** @var Node $node */ $node = $request->attributes->get('node'); $servers = $node->servers()->whereIn('uuid', $request->servers())->get()->keyBy('uuid'); @@ -22,7 +23,7 @@ class ActivityProcessingController extends Controller $logs = []; foreach ($request->input('data') as $datum) { - /** @var \App\Models\Server|null $server */ + /** @var Server|null $server */ $server = $servers->get($datum['server']); if (is_null($server) || !Str::startsWith($datum['event'], 'server:')) { continue; diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerContainersController.php b/app/Http/Controllers/Api/Remote/Servers/ServerContainersController.php index 84b6b5473..bd500536b 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerContainersController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerContainersController.php @@ -2,7 +2,7 @@ namespace App\Http\Controllers\Api\Remote\Servers; -use Illuminate\Http\Request; +use App\Http\Requests\Api\Remote\ServerRequest; use App\Models\Server; use Illuminate\Http\JsonResponse; use App\Http\Controllers\Controller; @@ -12,11 +12,11 @@ class ServerContainersController extends Controller /** * Updates the server container's status on the Panel */ - public function status(Server $server, Request $request): JsonResponse + public function status(ServerRequest $request, Server $server): JsonResponse { $status = fluent($request->json()->all())->get('data.new_state'); - cache()->put("servers.$server->uuid.container.status", $status, now()->addHour()); + cache()->put("servers.$server->uuid.status", $status, now()->addHour()); return new JsonResponse([]); } diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php b/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php index ba32d5553..52828487c 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerDetailsController.php @@ -3,7 +3,10 @@ namespace App\Http\Controllers\Api\Remote\Servers; use App\Enums\ServerState; +use App\Http\Requests\Api\Remote\ServerRequest; +use App\Models\ActivityLog; use App\Models\Backup; +use App\Models\Node; use Illuminate\Http\Request; use App\Models\Server; use Illuminate\Http\JsonResponse; @@ -29,7 +32,7 @@ class ServerDetailsController extends Controller * Returns details about the server that allows daemon to self-recover and ensure * that the state of the server matches the Panel at all times. */ - public function __invoke(Server $server): JsonResponse + public function __invoke(ServerRequest $request, Server $server): JsonResponse { return new JsonResponse([ 'settings' => $this->configurationStructureService->handle($server), @@ -42,7 +45,7 @@ class ServerDetailsController extends Controller */ public function list(Request $request): ServerConfigurationCollection { - /** @var \App\Models\Node $node */ + /** @var Node $node */ $node = $request->attributes->get('node'); // Avoid run-away N+1 SQL queries by preloading the relationships that are used @@ -85,9 +88,9 @@ class ServerDetailsController extends Controller ->get(); $this->connection->transaction(function () use ($node, $servers) { - /** @var \App\Models\Server $server */ + /** @var Server $server */ foreach ($servers as $server) { - /** @var \App\Models\ActivityLog|null $activity */ + /** @var ActivityLog|null $activity */ $activity = $server->activity->first(); if (!$activity) { continue; diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerInstallController.php b/app/Http/Controllers/Api/Remote/Servers/ServerInstallController.php index 513d26ef3..eec5744ea 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerInstallController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerInstallController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Api\Remote\Servers; use App\Enums\ServerState; +use App\Http\Requests\Api\Remote\ServerRequest; use Illuminate\Http\Response; use App\Models\Server; use Illuminate\Http\JsonResponse; @@ -15,14 +16,12 @@ class ServerInstallController extends Controller /** * Returns installation information for a server. */ - public function index(Server $server): JsonResponse + public function index(ServerRequest $request, Server $server): JsonResponse { - $egg = $server->egg; - return new JsonResponse([ - 'container_image' => $egg->copy_script_container, - 'entrypoint' => $egg->copy_script_entry, - 'script' => $egg->copy_script_install, + 'container_image' => $server->egg->copy_script_container, + 'entrypoint' => $server->egg->copy_script_entry, + 'script' => $server->egg->copy_script_install, ]); } diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php index 514f7f60f..c49b9e534 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerTransferController.php @@ -2,12 +2,12 @@ namespace App\Http\Controllers\Api\Remote\Servers; +use App\Http\Requests\Api\Remote\ServerRequest; use App\Models\Server; use App\Repositories\Daemon\DaemonServerRepository; use Illuminate\Http\Response; use Illuminate\Http\JsonResponse; use App\Models\Allocation; -use App\Models\ServerTransfer; use Illuminate\Database\ConnectionInterface; use App\Http\Controllers\Controller; use Symfony\Component\HttpKernel\Exception\ConflictHttpException; @@ -28,14 +28,23 @@ class ServerTransferController extends Controller * * @throws \Throwable */ - public function failure(Server $server): JsonResponse + public function failure(ServerRequest $request, Server $server): JsonResponse { $transfer = $server->transfer; if (is_null($transfer)) { throw new ConflictHttpException('Server is not being transferred.'); } - return $this->processFailedTransfer($transfer); + $this->connection->transaction(function () use ($transfer) { + $transfer->forceFill(['successful' => false])->saveOrFail(); + + if ($transfer->new_allocation || $transfer->new_additional_allocations) { + $allocations = array_merge([$transfer->new_allocation], $transfer->new_additional_allocations); + Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]); + } + }); + + return new JsonResponse([], Response::HTTP_NO_CONTENT); } /** @@ -43,16 +52,17 @@ class ServerTransferController extends Controller * * @throws \Throwable */ - public function success(Server $server): JsonResponse + public function success(ServerRequest $request, Server $server): JsonResponse { $transfer = $server->transfer; if (is_null($transfer)) { throw new ConflictHttpException('Server is not being transferred.'); } - $data = []; - /** @var \App\Models\Server $server */ - $server = $this->connection->transaction(function () use ($server, $transfer, $data) { + /** @var Server $server */ + $server = $this->connection->transaction(function () use ($server, $transfer) { + $data = []; + if ($transfer->old_allocation || $transfer->old_additional_allocations) { $allocations = array_merge([$transfer->old_allocation], $transfer->old_additional_allocations); // Remove the old allocations for the server and re-assign the server to the new @@ -60,6 +70,7 @@ class ServerTransferController extends Controller Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]); $data['allocation_id'] = $transfer->new_allocation; } + $data['node_id'] = $transfer->new_node; $server->update($data); @@ -82,24 +93,4 @@ class ServerTransferController extends Controller return new JsonResponse([], Response::HTTP_NO_CONTENT); } - - /** - * Release all the reserved allocations for this transfer and mark it as failed in - * the database. - * - * @throws \Throwable - */ - protected function processFailedTransfer(ServerTransfer $transfer): JsonResponse - { - $this->connection->transaction(function () use (&$transfer) { - $transfer->forceFill(['successful' => false])->saveOrFail(); - - if ($transfer->new_allocation || $transfer->new_additional_allocations) { - $allocations = array_merge([$transfer->new_allocation], $transfer->new_additional_allocations); - Allocation::query()->whereIn('id', $allocations)->update(['server_id' => null]); - } - }); - - return new JsonResponse([], Response::HTTP_NO_CONTENT); - } } diff --git a/app/Http/Requests/Api/Remote/InstallationDataRequest.php b/app/Http/Requests/Api/Remote/InstallationDataRequest.php index 99adcef5f..59d52c978 100644 --- a/app/Http/Requests/Api/Remote/InstallationDataRequest.php +++ b/app/Http/Requests/Api/Remote/InstallationDataRequest.php @@ -2,15 +2,8 @@ namespace App\Http\Requests\Api\Remote; -use Illuminate\Foundation\Http\FormRequest; - -class InstallationDataRequest extends FormRequest +class InstallationDataRequest extends ServerRequest { - public function authorize(): bool - { - return true; - } - /** * @return array */ diff --git a/app/Http/Requests/Api/Remote/ServerRequest.php b/app/Http/Requests/Api/Remote/ServerRequest.php new file mode 100644 index 000000000..32e1d2b1e --- /dev/null +++ b/app/Http/Requests/Api/Remote/ServerRequest.php @@ -0,0 +1,21 @@ +attributes->get('node'); + + /** @var ?Server $server */ + $server = $this->route()->parameter('server'); + + return $server && $server->node_id === $node->id; + } +} From ad709344308ff7a51f015e99ad83e17e69d162d3 Mon Sep 17 00:00:00 2001 From: "Michael (Parker) Parker" Date: Sun, 10 Aug 2025 14:30:58 -0500 Subject: [PATCH 5/7] Update healthcheck (#1571) --- Dockerfile | 9 +++++---- Dockerfile.dev | 11 ++++++----- compose.yml | 1 + docker/Caddyfile | 17 +++++++++++------ docker/entrypoint.sh | 11 ++++++++++- docker/healthcheck.sh | 9 +++++++++ 6 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 docker/healthcheck.sh diff --git a/Dockerfile b/Dockerfile index ccc06a934..436d04882 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,7 +63,7 @@ FROM --platform=$TARGETOS/$TARGETARCH localhost:5000/base-php:$TARGETARCH AS fin WORKDIR /var/www/html # Install additional required libraries -RUN apk update && apk add --no-cache \ +RUN apk add --no-cache \ caddy ca-certificates supervisor supercronic COPY --chown=root:www-data --chmod=640 --from=composerbuild /build . @@ -93,10 +93,11 @@ COPY docker/Caddyfile /etc/caddy/Caddyfile # Add Laravel scheduler to crontab COPY docker/crontab /etc/supercronic/crontab -COPY docker/entrypoint.sh ./docker/entrypoint.sh +COPY docker/entrypoint.sh /entrypoint.sh +COPY docker/healthcheck.sh /healthcheck.sh HEALTHCHECK --interval=5m --timeout=10s --start-period=5s --retries=3 \ - CMD curl -f http://localhost/up || exit 1 + CMD /bin/ash /healthcheck.sh EXPOSE 80 443 @@ -104,5 +105,5 @@ VOLUME /pelican-data USER www-data -ENTRYPOINT [ "/bin/ash", "docker/entrypoint.sh" ] +ENTRYPOINT [ "/bin/ash", "/entrypoint.sh" ] CMD [ "supervisord", "-n", "-c", "/etc/supervisord.conf" ] diff --git a/Dockerfile.dev b/Dockerfile.dev index 797576e25..0872e7ab4 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -67,8 +67,8 @@ FROM --platform=$TARGETOS/$TARGETARCH base AS final WORKDIR /var/www/html # Install additional required libraries -RUN apk update && apk add --no-cache \ - caddy ca-certificates supervisor supercronic +RUN apk add --no-cache \ + caddy ca-certificates supervisor supercronic coreutils COPY --chown=root:www-data --chmod=640 --from=composerbuild /build . COPY --chown=root:www-data --chmod=640 --from=yarnbuild /build/public ./public @@ -97,10 +97,11 @@ COPY docker/Caddyfile /etc/caddy/Caddyfile # Add Laravel scheduler to crontab COPY docker/crontab /etc/supercronic/crontab -COPY docker/entrypoint.sh ./docker/entrypoint.sh +COPY docker/entrypoint.sh /entrypoint.sh +COPY docker/healthcheck.sh /healthcheck.sh HEALTHCHECK --interval=5m --timeout=10s --start-period=5s --retries=3 \ - CMD curl -f http://localhost/up || exit 1 + CMD /bin/ash /healthcheck.sh EXPOSE 80 443 @@ -108,5 +109,5 @@ VOLUME /pelican-data USER www-data -ENTRYPOINT [ "/bin/ash", "docker/entrypoint.sh" ] +ENTRYPOINT [ "/bin/ash", "/entrypoint.sh" ] CMD [ "supervisord", "-n", "-c", "/etc/supervisord.conf" ] diff --git a/compose.yml b/compose.yml index becbab503..24aea6832 100644 --- a/compose.yml +++ b/compose.yml @@ -45,6 +45,7 @@ services: <<: [*panel-environment, *mail-environment] XDG_DATA_HOME: /pelican-data # SKIP_CADDY: true # enable when not using caddy. + TRUSTED_PROXIES: volumes: pelican-data: diff --git a/docker/Caddyfile b/docker/Caddyfile index e30760959..96559e477 100644 --- a/docker/Caddyfile +++ b/docker/Caddyfile @@ -1,12 +1,17 @@ { - admin off - email {$ADMIN_EMAIL} + servers { + ## docs https://caddyserver.com/docs/caddyfile/options#trusted-proxies + {$CADDY_TRUSTED_PROXIES} + {$CADDY_STRICT_PROXIES} + } + admin off + auto_https off + email {$ADMIN_EMAIL} } {$APP_URL} { - root * /var/www/html/public - encode gzip + root * /var/www/html/public + encode gzip - php_fastcgi 127.0.0.1:9000 - file_server + php_fastcgi 127.0.0.1:9000 } diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 1089ea539..9734223c4 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -1,5 +1,4 @@ #!/bin/ash -e - ## check for .env file or symlink and generate app keys if missing if [ -f /var/www/html/.env ]; then echo "external vars exist." @@ -23,6 +22,8 @@ else echo -e "APP_INSTALLED=false" >> /pelican-data/.env fi +sed -i "s/upload_max_filesize = 2M/upload_max_filesize = ${UPLOAD_LIMIT}M/" /usr/local/etc/php/php.ini-production + mkdir -p /pelican-data/database /pelican-data/storage/avatars /pelican-data/storage/fonts /var/www/html/storage/logs/supervisord 2>/dev/null if ! grep -q "APP_KEY=" .env || grep -q "APP_KEY=$" .env; then @@ -39,6 +40,7 @@ php artisan migrate --force echo -e "Optimizing Filament" php artisan filament:optimize +# default to caddy not starting export SUPERVISORD_CADDY=false ## disable caddy if SKIP_CADDY is set @@ -46,7 +48,14 @@ if [[ "${SKIP_CADDY:-}" == "true" ]]; then echo "Starting PHP-FPM only" else echo "Starting PHP-FPM and Caddy" + # enable caddy export SUPERVISORD_CADDY=true + + # handle trusted proxies for caddy + if [[ ! -z ${TRUSTED_PROXIES} ]]; then + export CADDY_TRUSTED_PROXIES=$(echo "trusted_proxies static ${TRUSTED_PROXIES}" | sed 's/,/ /g') + export CADDY_STRICT_PROXIES="trusted_proxies_strict" + fi fi echo "Starting Supervisord" diff --git a/docker/healthcheck.sh b/docker/healthcheck.sh new file mode 100644 index 000000000..8eef81989 --- /dev/null +++ b/docker/healthcheck.sh @@ -0,0 +1,9 @@ +#!/bin/ash -e + +if [ ${SKIP_CADDY} ! "true" ]; then + curl -f http://localhost/up || exit 1 +fi + +cgi-fcgi -bind -connect 127.0.0.1:9000 || exit 2 + +exit 0 \ No newline at end of file From 27a8423f55016856ad641cf37d8348c06acf4751 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Mon, 11 Aug 2025 22:21:52 +0200 Subject: [PATCH 6/7] Fix container status caching (#1588) --- .../Api/Remote/Servers/ServerContainersController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/Remote/Servers/ServerContainersController.php b/app/Http/Controllers/Api/Remote/Servers/ServerContainersController.php index bd500536b..196e18394 100644 --- a/app/Http/Controllers/Api/Remote/Servers/ServerContainersController.php +++ b/app/Http/Controllers/Api/Remote/Servers/ServerContainersController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\Api\Remote\Servers; +use App\Enums\ContainerStatus; use App\Http\Requests\Api\Remote\ServerRequest; use App\Models\Server; use Illuminate\Http\JsonResponse; @@ -14,7 +15,7 @@ class ServerContainersController extends Controller */ public function status(ServerRequest $request, Server $server): JsonResponse { - $status = fluent($request->json()->all())->get('data.new_state'); + $status = ContainerStatus::tryFrom($request->json('data.new_state')) ?? ContainerStatus::Missing; cache()->put("servers.$server->uuid.status", $status, now()->addHour()); From b03d2cf9194cb112140f06d827813007af2e2766 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 11 Aug 2025 16:57:59 -0400 Subject: [PATCH 7/7] composer update + update jwt (#1587) --- app/Services/Nodes/NodeJWTService.php | 19 +- .../Servers/TransferServerService.php | 4 +- composer.json | 2 +- composer.lock | 192 +++++++----------- .../Client/Server/WebsocketControllerTest.php | 61 +++--- 5 files changed, 111 insertions(+), 167 deletions(-) diff --git a/app/Services/Nodes/NodeJWTService.php b/app/Services/Nodes/NodeJWTService.php index 7d9765fa9..53d355a18 100644 --- a/app/Services/Nodes/NodeJWTService.php +++ b/app/Services/Nodes/NodeJWTService.php @@ -2,16 +2,16 @@ namespace App\Services\Nodes; +use App\Extensions\Lcobucci\JWT\Encoding\TimestampDates; use Carbon\CarbonImmutable; use DateTimeImmutable; use Illuminate\Support\Str; use App\Models\Node; use App\Models\User; -use Lcobucci\JWT\Token\Plain; use Lcobucci\JWT\Configuration; use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Key\InMemory; -use App\Extensions\Lcobucci\JWT\Encoding\TimestampDates; +use Lcobucci\JWT\UnencryptedToken; class NodeJWTService { @@ -64,7 +64,7 @@ class NodeJWTService /** * Generate a new JWT for a given node. */ - public function handle(Node $node, ?string $identifiedBy, string $algo = 'md5'): Plain + public function handle(Node $node, ?string $identifiedBy, string $algo = 'sha256'): UnencryptedToken { $identifier = hash($algo, $identifiedBy); $config = Configuration::forSymmetricSigner(new Sha256(), InMemory::plainText($node->daemon_token)); @@ -80,7 +80,9 @@ class NodeJWTService $builder = $builder->expiresAt($this->expiresAt); if (!empty($this->subject)) { - $builder = $builder->relatedTo($this->subject)->withHeader('sub', $this->subject); + $builder = $builder + ->relatedTo($this->subject) + ->withHeader('sub', $this->subject); } foreach ($this->claims as $key => $value) { @@ -88,14 +90,7 @@ class NodeJWTService } if (!is_null($this->user)) { - $builder = $builder - ->withClaim('user_uuid', $this->user->uuid) - // The "user_id" claim is deprecated and should not be referenced — it remains - // here solely to ensure older versions of daemon are unaffected when the Panel - // is updated. - // - // This claim will be removed in Panel@1.11 or later. - ->withClaim('user_id', $this->user->id); + $builder = $builder->withClaim('user_uuid', $this->user->uuid); } return $builder diff --git a/app/Services/Servers/TransferServerService.php b/app/Services/Servers/TransferServerService.php index d1aabf86d..d89d3f800 100644 --- a/app/Services/Servers/TransferServerService.php +++ b/app/Services/Servers/TransferServerService.php @@ -10,7 +10,7 @@ use App\Services\Nodes\NodeJWTService; use Carbon\CarbonImmutable; use Illuminate\Database\ConnectionInterface; use Illuminate\Support\Facades\Http; -use Lcobucci\JWT\Token\Plain; +use Lcobucci\JWT\UnencryptedToken; class TransferServerService { @@ -22,7 +22,7 @@ class TransferServerService private NodeJWTService $nodeJWTService, ) {} - private function notify(ServerTransfer $transfer, Plain $token): void + private function notify(ServerTransfer $transfer, UnencryptedToken $token): void { Http::daemon($transfer->oldNode)->post("/api/servers/{$transfer->server->uuid}/transfer", [ 'url' => $transfer->newNode->getConnectionAddress() . '/api/transfers', diff --git a/composer.json b/composer.json index bc86b449c..8652bbaee 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "laravel/socialite": "^5.21", "laravel/tinker": "^2.10.1", "laravel/ui": "^4.6", - "lcobucci/jwt": "~4.3.0", + "lcobucci/jwt": "^5.5", "league/flysystem-aws-s3-v3": "^3.29", "league/flysystem-memory": "^3.29", "phpseclib/phpseclib": "~3.0.18", diff --git a/composer.lock b/composer.lock index 22b374ce3..253e4b4b9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7138d3f3e583251a87fcbf5157c43315", + "content-hash": "e5d9f294519edc6e4cca937c579709f8", "packages": [ { "name": "abdelhamiderrahmouni/filament-monaco-editor", @@ -1020,16 +1020,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.352.4", + "version": "3.352.5", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "d3ce2a85687d55cd67d52682306227bc6aa836d6" + "reference": "e226dcc96c0a1165d9c8248ec637d1006b883609" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d3ce2a85687d55cd67d52682306227bc6aa836d6", - "reference": "d3ce2a85687d55cd67d52682306227bc6aa836d6", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/e226dcc96c0a1165d9c8248ec637d1006b883609", + "reference": "e226dcc96c0a1165d9c8248ec637d1006b883609", "shasum": "" }, "require": { @@ -1111,9 +1111,9 @@ "support": { "forum": "https://github.com/aws/aws-sdk-php/discussions", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.352.4" + "source": "https://github.com/aws/aws-sdk-php/tree/3.352.5" }, - "time": "2025-08-07T18:15:55+00:00" + "time": "2025-08-08T18:09:38+00:00" }, { "name": "blade-ui-kit/blade-heroicons", @@ -2258,33 +2258,32 @@ }, { "name": "doctrine/inflector", - "version": "2.0.10", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^11.0", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.3", - "phpunit/phpunit": "^8.5 || ^9.5", - "vimeo/psalm": "^4.25 || ^5.4" + "doctrine/coding-standard": "^12.0 || ^13.0", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-phpunit": "^1.4 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", + "phpunit/phpunit": "^8.5 || ^12.2" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + "Doctrine\\Inflector\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2329,7 +2328,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.10" + "source": "https://github.com/doctrine/inflector/tree/2.1.0" }, "funding": [ { @@ -2345,7 +2344,7 @@ "type": "tidelift" } ], - "time": "2024-02-18T20:23:39+00:00" + "time": "2025-08-10T19:31:58+00:00" }, { "name": "doctrine/lexer", @@ -4373,105 +4372,40 @@ }, "time": "2025-01-28T15:15:29+00:00" }, - { - "name": "lcobucci/clock", - "version": "3.3.1", - "source": { - "type": "git", - "url": "https://github.com/lcobucci/clock.git", - "reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/lcobucci/clock/zipball/db3713a61addfffd615b79bf0bc22f0ccc61b86b", - "reference": "db3713a61addfffd615b79bf0bc22f0ccc61b86b", - "shasum": "" - }, - "require": { - "php": "~8.2.0 || ~8.3.0 || ~8.4.0", - "psr/clock": "^1.0" - }, - "provide": { - "psr/clock-implementation": "1.0" - }, - "require-dev": { - "infection/infection": "^0.29", - "lcobucci/coding-standard": "^11.1.0", - "phpstan/extension-installer": "^1.3.1", - "phpstan/phpstan": "^1.10.25", - "phpstan/phpstan-deprecation-rules": "^1.1.3", - "phpstan/phpstan-phpunit": "^1.3.13", - "phpstan/phpstan-strict-rules": "^1.5.1", - "phpunit/phpunit": "^11.3.6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Lcobucci\\Clock\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Luís Cobucci", - "email": "lcobucci@gmail.com" - } - ], - "description": "Yet another clock abstraction", - "support": { - "issues": "https://github.com/lcobucci/clock/issues", - "source": "https://github.com/lcobucci/clock/tree/3.3.1" - }, - "funding": [ - { - "url": "https://github.com/lcobucci", - "type": "github" - }, - { - "url": "https://www.patreon.com/lcobucci", - "type": "patreon" - } - ], - "time": "2024-09-24T20:45:14+00:00" - }, { "name": "lcobucci/jwt", - "version": "4.3.0", + "version": "5.5.0", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4" + "reference": "a835af59b030d3f2967725697cf88300f579088e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/4d7de2fe0d51a96418c0d04004986e410e87f6b4", - "reference": "4d7de2fe0d51a96418c0d04004986e410e87f6b4", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/a835af59b030d3f2967725697cf88300f579088e", + "reference": "a835af59b030d3f2967725697cf88300f579088e", "shasum": "" }, "require": { - "ext-hash": "*", - "ext-json": "*", - "ext-mbstring": "*", "ext-openssl": "*", "ext-sodium": "*", - "lcobucci/clock": "^2.0 || ^3.0", - "php": "^7.4 || ^8.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/clock": "^1.0" }, "require-dev": { - "infection/infection": "^0.21", - "lcobucci/coding-standard": "^6.0", - "mikey179/vfsstream": "^1.6.7", + "infection/infection": "^0.29", + "lcobucci/clock": "^3.2", + "lcobucci/coding-standard": "^11.0", "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-deprecation-rules": "^1.0", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/php-invoker": "^3.1", - "phpunit/phpunit": "^9.5" + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", + "phpstan/phpstan-strict-rules": "^1.5.0", + "phpunit/phpunit": "^11.1" + }, + "suggest": { + "lcobucci/clock": ">= 3.2" }, "type": "library", "autoload": { @@ -4497,7 +4431,7 @@ ], "support": { "issues": "https://github.com/lcobucci/jwt/issues", - "source": "https://github.com/lcobucci/jwt/tree/4.3.0" + "source": "https://github.com/lcobucci/jwt/tree/5.5.0" }, "funding": [ { @@ -4509,7 +4443,7 @@ "type": "patreon" } ], - "time": "2023-01-02T13:28:00+00:00" + "time": "2025-01-26T21:29:45+00:00" }, { "name": "league/commonmark", @@ -14666,16 +14600,16 @@ }, { "name": "sebastian/comparator", - "version": "6.3.1", + "version": "6.3.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" + "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", - "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8", + "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8", "shasum": "" }, "require": { @@ -14734,15 +14668,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" } ], - "time": "2025-03-07T06:57:01+00:00" + "time": "2025-08-10T08:07:46+00:00" }, { "name": "sebastian/complexity", @@ -15323,16 +15269,16 @@ }, { "name": "sebastian/type", - "version": "5.1.2", + "version": "5.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", - "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", "shasum": "" }, "require": { @@ -15368,15 +15314,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/type/issues", "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" } ], - "time": "2025-03-18T13:35:50+00:00" + "time": "2025-08-09T06:55:48+00:00" }, { "name": "sebastian/version", diff --git a/tests/Integration/Api/Client/Server/WebsocketControllerTest.php b/tests/Integration/Api/Client/Server/WebsocketControllerTest.php index 7fdcf4374..689f50ceb 100644 --- a/tests/Integration/Api/Client/Server/WebsocketControllerTest.php +++ b/tests/Integration/Api/Client/Server/WebsocketControllerTest.php @@ -8,15 +8,12 @@ use Lcobucci\JWT\Configuration; use App\Models\Permission; use Lcobucci\JWT\Signer\Hmac\Sha256; use Lcobucci\JWT\Signer\Key\InMemory; +use Lcobucci\JWT\UnencryptedToken; use Lcobucci\JWT\Validation\Constraint\SignedWith; use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase; class WebsocketControllerTest extends ClientApiIntegrationTestCase { - /** - * Test that a subuser attempting to connect to the websocket receives an error if they - * do not explicitly have the permission. - */ public function test_subuser_without_websocket_permission_receives_error(): void { [$user, $server] = $this->generateTestAccount([Permission::ACTION_CONTROL_RESTART]); @@ -59,41 +56,34 @@ class WebsocketControllerTest extends ClientApiIntegrationTestCase $response->assertJsonStructure(['data' => ['token', 'socket']]); $connection = $response->json('data.socket'); - $this->assertStringStartsWith('wss://', $connection, 'Failed asserting that websocket connection address has expected "wss://" prefix.'); - $this->assertStringEndsWith("/api/servers/$server->uuid/ws", $connection, 'Failed asserting that websocket connection address uses expected Daemon endpoint.'); + $this->assertStringStartsWith('wss://', $connection); + $this->assertStringEndsWith("/api/servers/$server->uuid/ws", $connection); + + $key = InMemory::plainText($server->node->daemon_token); + $config = Configuration::forSymmetricSigner(new Sha256(), $key); - $config = Configuration::forSymmetricSigner(new Sha256(), $key = InMemory::plainText($server->node->daemon_token)); - $config->setValidationConstraints(new SignedWith(new Sha256(), $key)); - /** @var \Lcobucci\JWT\Token\Plain $token */ $token = $config->parser()->parse($response->json('data.token')); + $this->assertInstanceOf(UnencryptedToken::class, $token); + $constraints = [new SignedWith(new Sha256(), $key)]; $this->assertTrue( - $config->validator()->validate($token, ...$config->validationConstraints()), + $config->validator()->validate($token, ...$constraints), 'Failed to validate that the JWT data returned was signed using the Node\'s secret key.' ); - // The way we generate times for the JWT will truncate the microseconds from the - // time, but CarbonImmutable::now() will include them, thus causing test failures. - // - // This little chunk of logic just strips those out by generating a new CarbonImmutable - // instance from the current timestamp, which is how the JWT works. We also need to - // switch to UTC here for consistency. - $expect = CarbonImmutable::createFromTimestamp(CarbonImmutable::now()->getTimestamp())->timezone('UTC'); + $expect = CarbonImmutable::createFromTimestamp(CarbonImmutable::now()->getTimestamp())->timezone('UTC')->setMicroseconds(0); - // Check that the claims are generated correctly. - $this->assertTrue($token->hasBeenIssuedBy(config('app.url'))); - $this->assertTrue($token->isPermittedFor($server->node->getConnectionAddress())); - $this->assertEquals($expect, $token->claims()->get('iat')); - $this->assertEquals($expect->subMinutes(5), $token->claims()->get('nbf')); - $this->assertEquals($expect->addMinutes(10), $token->claims()->get('exp')); - $this->assertSame($user->id, $token->claims()->get('user_id')); - $this->assertSame($server->uuid, $token->claims()->get('server_uuid')); - $this->assertSame(['*'], $token->claims()->get('permissions')); + $claims = $token->claims(); + $this->assertSame(config('app.url'), $claims->get('iss')); + $this->assertSame($server->node->getConnectionAddress(), $claims->get('aud')[0] ?? null); + $this->assertEquals($expect, CarbonImmutable::instance($claims->get('iat'))->setMicroseconds(0)); + $this->assertEquals($expect->subMinutes(5), CarbonImmutable::instance($claims->get('nbf'))->setMicroseconds(0)); + $this->assertEquals($expect->addMinutes(10), CarbonImmutable::instance($claims->get('exp'))->setMicroseconds(0)); + $this->assertSame($user->uuid, $claims->get('user_uuid')); + $this->assertSame($server->uuid, $claims->get('server_uuid')); + $this->assertSame(['*'], $claims->get('permissions')); } - /** - * Test that the subuser's permissions are passed along correctly in the generated JWT. - */ public function test_jwt_is_configured_correctly_for_server_subuser(): void { $permissions = [Permission::ACTION_WEBSOCKET_CONNECT, Permission::ACTION_CONTROL_CONSOLE]; @@ -107,17 +97,18 @@ class WebsocketControllerTest extends ClientApiIntegrationTestCase $response->assertOk(); $response->assertJsonStructure(['data' => ['token', 'socket']]); - $config = Configuration::forSymmetricSigner(new Sha256(), $key = InMemory::plainText($server->node->daemon_token)); - $config->setValidationConstraints(new SignedWith(new Sha256(), $key)); - /** @var \Lcobucci\JWT\Token\Plain $token */ - $token = $config->parser()->parse($response->json('data.token')); + $key = InMemory::plainText($server->node->daemon_token); + $config = Configuration::forSymmetricSigner(new Sha256(), $key); + $token = $config->parser()->parse($response->json('data.token')); + $this->assertInstanceOf(UnencryptedToken::class, $token); + + $constraints = [new SignedWith(new Sha256(), $key)]; $this->assertTrue( - $config->validator()->validate($token, ...$config->validationConstraints()), + $config->validator()->validate($token, ...$constraints), 'Failed to validate that the JWT data returned was signed using the Node\'s secret key.' ); - // Check that the claims are generated correctly. $this->assertSame($permissions, $token->claims()->get('permissions')); } }