From 06067f375c549b0627f0a3fa3d6c52b8dd032b83 Mon Sep 17 00:00:00 2001 From: "Michael (Parker) Parker" Date: Tue, 12 Aug 2025 09:08:10 -0500 Subject: [PATCH 1/5] Add fcgi package for healthcheck I missed adding the package to the dockerfile so the healthcheck is failing --- Dockerfile | 2 +- Dockerfile.dev | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 436d04882..5db6281af 100644 --- a/Dockerfile +++ b/Dockerfile @@ -64,7 +64,7 @@ WORKDIR /var/www/html # Install additional required libraries RUN apk add --no-cache \ - caddy ca-certificates supervisor supercronic + caddy ca-certificates supervisor supercronic fcgi COPY --chown=root:www-data --chmod=640 --from=composerbuild /build . COPY --chown=root:www-data --chmod=640 --from=yarnbuild /build/public ./public diff --git a/Dockerfile.dev b/Dockerfile.dev index 0872e7ab4..982235a49 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -68,7 +68,7 @@ WORKDIR /var/www/html # Install additional required libraries RUN apk add --no-cache \ - caddy ca-certificates supervisor supercronic coreutils + caddy ca-certificates supervisor supercronic fcgi coreutils COPY --chown=root:www-data --chmod=640 --from=composerbuild /build . COPY --chown=root:www-data --chmod=640 --from=yarnbuild /build/public ./public From 15075b6ab81ceff698b7737e52388895558ca1a5 Mon Sep 17 00:00:00 2001 From: "Michael (Parker) Parker" Date: Wed, 13 Aug 2025 13:44:21 -0500 Subject: [PATCH 2/5] re-add file server directive --- docker/Caddyfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/Caddyfile b/docker/Caddyfile index 96559e477..92c2f8dae 100644 --- a/docker/Caddyfile +++ b/docker/Caddyfile @@ -13,5 +13,6 @@ root * /var/www/html/public encode gzip + file_server php_fastcgi 127.0.0.1:9000 } From c77a37ec8996bd180e4277a4090237f5ee67b15d Mon Sep 17 00:00:00 2001 From: Boy132 Date: Thu, 14 Aug 2025 08:29:58 +0200 Subject: [PATCH 3/5] Fix & cleanup OAuthController (#1599) --- app/Extensions/OAuth/OAuthSchemaInterface.php | 2 + app/Extensions/OAuth/Schemas/OAuthSchema.php | 20 ++- app/Http/Controllers/Auth/OAuthController.php | 134 ++++++++++-------- lang/en/admin/setting.php | 1 + 4 files changed, 99 insertions(+), 58 deletions(-) diff --git a/app/Extensions/OAuth/OAuthSchemaInterface.php b/app/Extensions/OAuth/OAuthSchemaInterface.php index 6d7610677..46c82a630 100644 --- a/app/Extensions/OAuth/OAuthSchemaInterface.php +++ b/app/Extensions/OAuth/OAuthSchemaInterface.php @@ -34,4 +34,6 @@ interface OAuthSchemaInterface public function isEnabled(): bool; public function shouldCreateMissingUsers(): bool; + + public function shouldLinkMissingUsers(): bool; } diff --git a/app/Extensions/OAuth/Schemas/OAuthSchema.php b/app/Extensions/OAuth/Schemas/OAuthSchema.php index 250dba5da..94b6f91a4 100644 --- a/app/Extensions/OAuth/Schemas/OAuthSchema.php +++ b/app/Extensions/OAuth/Schemas/OAuthSchema.php @@ -63,9 +63,20 @@ abstract class OAuthSchema implements OAuthSchemaInterface ->offIcon('tabler-x') ->onColor('success') ->offColor('danger') - ->formatStateUsing(fn ($state): bool => (bool) $state) + ->formatStateUsing(fn ($state) => (bool) $state) ->afterStateUpdated(fn ($state, Set $set) => $set("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS", (bool) $state)) ->default(env("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS")), + Toggle::make("OAUTH_{$id}_SHOULD_LINK_MISSING_USERS") + ->label(trans('admin/setting.oauth.link_missing_users')) + ->columnSpanFull() + ->inline(false) + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->formatStateUsing(fn ($state) => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set("OAUTH_{$id}_SHOULD_LINK_MISSING_USERS", (bool) $state)) + ->default(env("OAUTH_{$id}_SHOULD_LINK_MISSING_USERS")), ]; } @@ -116,4 +127,11 @@ abstract class OAuthSchema implements OAuthSchemaInterface return env("OAUTH_{$id}_SHOULD_CREATE_MISSING_USERS", false); } + + public function shouldLinkMissingUsers(): bool + { + $id = Str::upper($this->getId()); + + return env("OAUTH_{$id}_SHOULD_LINK_MISSING_USERS", false); + } } diff --git a/app/Http/Controllers/Auth/OAuthController.php b/app/Http/Controllers/Auth/OAuthController.php index 31de3cb9d..12c820706 100644 --- a/app/Http/Controllers/Auth/OAuthController.php +++ b/app/Http/Controllers/Auth/OAuthController.php @@ -2,38 +2,37 @@ namespace App\Http\Controllers\Auth; +use App\Extensions\OAuth\OAuthSchemaInterface; 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; use Illuminate\Http\Request; +use Laravel\Socialite\Contracts\User as OAuthUser; use Laravel\Socialite\Facades\Socialite; +use Symfony\Component\HttpFoundation\RedirectResponse as SymfonyRedirectResponse; class OAuthController extends Controller { public function __construct( - private readonly AuthManager $auth, - private UserCreationService $userCreation, - private readonly UserUpdateService $updateService, + private readonly UserCreationService $userCreation, private readonly OAuthService $oauthService, ) {} /** * Redirect user to the OAuth provider */ - public function redirect(string $driver): RedirectResponse + public function redirect(string $driver): SymfonyRedirectResponse|RedirectResponse { - // Driver is disabled - redirect to normal login if (!$this->oauthService->get($driver)->isEnabled()) { return redirect()->route('auth.login'); } - return Socialite::with($driver)->redirect(); + return Socialite::driver($driver)->redirect(); } /** @@ -43,7 +42,6 @@ class OAuthController extends Controller { $driver = $this->oauthService->get($driver); - // Unknown driver or driver is disabled - redirect to normal login if (!$driver || !$driver->isEnabled()) { return redirect()->route('auth.login'); } @@ -52,67 +50,89 @@ class OAuthController extends Controller if ($request->get('error')) { report($request->get('error_description') ?? $request->get('error')); - Notification::make() - ->title('Something went wrong') - ->body($request->get('error')) - ->danger() - ->persistent() - ->send(); - - return redirect()->route('auth.login'); + return $this->errorRedirect($request->get('error')); } $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->getId()] = $oauthUser->getId(); - - $this->updateService->handle($request->user(), ['oauth' => $oauth]); + $this->linkUser($request->user(), $driver, $oauthUser); return redirect(EditProfile::getUrl(['tab' => '-oauth-tab'], panel: 'app')); } $user = User::whereJsonContains('oauth->'. $driver->getId(), $oauthUser->getId())->first(); - - 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'); - } - - $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(), - ], - ]); + if ($user) { + return $this->loginUser($user); } - $this->auth->guard()->login($user, true); + return $this->handleMissingUser($driver, $oauthUser); + } + + private function linkUser(User $user, OAuthSchemaInterface $driver, OAuthUser $oauthUser): User + { + $oauth = $user->oauth; + $oauth[$driver->getId()] = $oauthUser->getId(); + + $user->update(['oauth' => $oauth]); + + return $user->refresh(); + } + + private function handleMissingUser(OAuthSchemaInterface $driver, OAuthUser $oauthUser): RedirectResponse + { + $email = $oauthUser->getEmail(); + + if (!$email) { + return $this->errorRedirect(); + } + + $user = User::whereEmail($email)->first(); + if ($user) { + if (!$driver->shouldLinkMissingUsers()) { + return $this->errorRedirect(); + } + + $user = $this->linkUser($user, $driver, $oauthUser); + } else { + if (!$driver->shouldCreateMissingUsers()) { + return $this->errorRedirect(); + } + + try { + $user = $this->userCreation->handle([ + 'username' => $oauthUser->getNickname(), + 'email' => $email, + 'oauth' => [ + $driver->getId() => $oauthUser->getId(), + ], + ]); + } catch (Exception $exception) { + report($exception); + + return $this->errorRedirect(); + } + } + + return $this->loginUser($user); + } + + private function loginUser(User $user): RedirectResponse + { + auth()->guard()->login($user, true); return redirect('/'); } + + private function errorRedirect(?string $error = null): RedirectResponse + { + Notification::make() + ->title($error ? 'Something went wrong' : 'No linked User found') + ->body($error) + ->danger() + ->persistent() + ->send(); + + return redirect()->route('auth.login'); + } } diff --git a/lang/en/admin/setting.php b/lang/en/admin/setting.php index 718e9511f..97bafa4ab 100644 --- a/lang/en/admin/setting.php +++ b/lang/en/admin/setting.php @@ -98,6 +98,7 @@ return [ 'display_name' => 'Display Name', 'auth_url' => 'Authorization callback URL', 'create_missing_users' => 'Auto Create Missing Users?', + 'link_missing_users' => 'Auto Link Missing Users?', ], 'misc' => [ 'auto_allocation' => [ From b5ebd544f4b35d5eae897eec877d92785f34f226 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Fri, 15 Aug 2025 14:06:53 +0200 Subject: [PATCH 4/5] Improve translation for "link" and "unlink" (oauth) (#1612) --- app/Filament/Pages/Auth/EditProfile.php | 2 +- lang/en/profile.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Filament/Pages/Auth/EditProfile.php b/app/Filament/Pages/Auth/EditProfile.php index 8056dc2e2..8d86e1f73 100644 --- a/app/Filament/Pages/Auth/EditProfile.php +++ b/app/Filament/Pages/Auth/EditProfile.php @@ -174,7 +174,7 @@ class EditProfile extends BaseEditProfile $unlink = array_key_exists($id, $this->getUser()->oauth ?? []); $actions[] = Action::make("oauth_$id") - ->label(($unlink ? trans('profile.unlink') : trans('profile.link')) . $name) + ->label(trans('profile.' . ($unlink ? 'unlink' : 'link'), ['name' => $name])) ->icon($unlink ? 'tabler-unlink' : 'tabler-link') ->color(Color::hex($schema->getHexColor())) ->action(function (UserUpdateService $updateService) use ($id, $name, $unlink) { diff --git a/lang/en/profile.php b/lang/en/profile.php index e0d2085cd..662f84df1 100644 --- a/lang/en/profile.php +++ b/lang/en/profile.php @@ -21,8 +21,8 @@ return [ 'timezone' => 'Timezone', 'language' => 'Language', 'language_help' => 'Your language :state has not been translated yet!', - 'link' => 'Link ', - 'unlink' => 'Unlink ', + 'link' => 'Link :name', + 'unlink' => 'Unlink :name', 'unlinked' => ':name unlinked', 'scan_qr' => 'Scan QR Code', 'code' => 'Code', From f31aa78f6f392e8985d383ac8ed26dca46c1b2f9 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Fri, 15 Aug 2025 14:07:23 +0200 Subject: [PATCH 5/5] Fix gap for profile repeaters (api keys, ssh keys, activity logs) (#1613) --- app/Filament/Pages/Auth/EditProfile.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/Filament/Pages/Auth/EditProfile.php b/app/Filament/Pages/Auth/EditProfile.php index 8d86e1f73..0ad423ad9 100644 --- a/app/Filament/Pages/Auth/EditProfile.php +++ b/app/Filament/Pages/Auth/EditProfile.php @@ -322,6 +322,7 @@ class EditProfile extends BaseEditProfile Section::make(trans('profile.api_keys'))->columnSpan(2)->schema([ Repeater::make('api_keys') ->hiddenLabel() + ->inlineLabel(false) ->relationship('apiKeys') ->addable(false) ->itemLabel(fn ($state) => $state['identifier']) @@ -406,6 +407,7 @@ class EditProfile extends BaseEditProfile Section::make(trans('profile.ssh_keys'))->columnSpan(2)->schema([ Repeater::make('ssh_keys') ->hiddenLabel() + ->inlineLabel(false) ->relationship('sshKeys') ->addable(false) ->itemLabel(fn ($state) => $state['name']) @@ -445,14 +447,17 @@ class EditProfile extends BaseEditProfile ->icon('tabler-history') ->schema([ Repeater::make('activity') - ->label('') + ->hiddenLabel() + ->inlineLabel(false) ->deletable(false) ->addable(false) ->relationship(null, function (Builder $query) { $query->orderBy('timestamp', 'desc'); }) ->schema([ - Placeholder::make('activity!')->label('')->content(fn (ActivityLog $log) => new HtmlString($log->htmlable())), + Placeholder::make('log') + ->hiddenLabel() + ->content(fn (ActivityLog $log) => new HtmlString($log->htmlable())), ]), ]),