diff --git a/app/Filament/Pages/Installer/PanelInstaller.php b/app/Filament/Pages/Installer/PanelInstaller.php index 00b182af08..e8e733a034 100644 --- a/app/Filament/Pages/Installer/PanelInstaller.php +++ b/app/Filament/Pages/Installer/PanelInstaller.php @@ -42,7 +42,7 @@ public function getMaxWidth(): MaxWidth|string return MaxWidth::SevenExtraLarge; } - public function mount() + public function mount(): void { if (is_installed()) { abort(404); @@ -90,7 +90,7 @@ protected function hasUnsavedDataChangesAlert(): bool return true; } - public function submit() + public function submit(): void { try { $inputs = $this->form->getState(); diff --git a/app/Filament/Pages/Installer/Steps/DatabaseStep.php b/app/Filament/Pages/Installer/Steps/DatabaseStep.php index 94a7952e2f..b81c5d49d8 100644 --- a/app/Filament/Pages/Installer/Steps/DatabaseStep.php +++ b/app/Filament/Pages/Installer/Steps/DatabaseStep.php @@ -24,7 +24,7 @@ public static function make(): Step ->hintIcon('tabler-question-mark') ->hintIconTooltip(fn (Get $get) => $get('env.DB_CONNECTION') === 'sqlite' ? 'The path of your .sqlite file relative to the database folder.' : 'The name of the panel database.') ->required() - ->default(fn (Get $get) => env('DB_DATABASE', $get('env.DB_CONNECTION') === 'sqlite' ? 'database.sqlite' : 'panel')), + ->default(fn (Get $get) => $get('env.DB_CONNECTION') === 'sqlite' ? env('DB_DATABASE', 'database.sqlite') : 'panel'), TextInput::make('env.DB_HOST') ->label('Database Host') ->hintIcon('tabler-question-mark') diff --git a/app/Filament/Pages/Installer/Steps/EnvironmentStep.php b/app/Filament/Pages/Installer/Steps/EnvironmentStep.php index d9cc5eafaa..b90feb26a9 100644 --- a/app/Filament/Pages/Installer/Steps/EnvironmentStep.php +++ b/app/Filament/Pages/Installer/Steps/EnvironmentStep.php @@ -51,7 +51,7 @@ public static function make(): Step ->hintIcon('tabler-question-mark') ->hintIconTooltip('This will be the URL you access your Panel from.') ->required() - ->default(config('app.url')) + ->default(fn () => request()->root()) ->live() ->afterStateUpdated(fn ($state, Set $set) => $set('env.SESSION_SECURE_COOKIE', str_starts_with($state, 'https://'))), Toggle::make('env.SESSION_SECURE_COOKIE') diff --git a/app/Filament/Pages/Installer/Steps/RequirementsStep.php b/app/Filament/Pages/Installer/Steps/RequirementsStep.php index 483e4ca1bc..f761a71c9e 100644 --- a/app/Filament/Pages/Installer/Steps/RequirementsStep.php +++ b/app/Filament/Pages/Installer/Steps/RequirementsStep.php @@ -2,11 +2,13 @@ namespace App\Filament\Pages\Installer\Steps; +use Filament\Forms\Components\Actions\Action as FormAction; use Filament\Forms\Components\Placeholder; use Filament\Forms\Components\Section; use Filament\Forms\Components\Wizard\Step; use Filament\Notifications\Notification; use Filament\Support\Exceptions\Halt; +use Symfony\Component\Process\Process; class RequirementsStep { @@ -31,43 +33,70 @@ public static function make(): Step 'GD' => extension_loaded('gd'), 'intl' => extension_loaded('intl'), 'mbstring' => extension_loaded('mbstring'), - 'MySQL' => extension_loaded('pdo_mysql'), - 'SQLite3' => extension_loaded('pdo_sqlite'), + 'MySQL' => extension_loaded('pdo_mysql') ?: (extension_loaded('pdo_sqlite') ? 2 : 0), + 'SQLite3' => extension_loaded('pdo_sqlite') ?: (extension_loaded('pdo_mysql') ? 2 : 0), 'XML' => extension_loaded('xml'), 'Zip' => extension_loaded('zip'), ]; - $allExtensionsInstalled = !in_array(false, $phpExtensions); + $allExtensionsInstalled = !in_array(0, $phpExtensions); $fields[] = Section::make('PHP Extensions') ->description(implode(', ', array_keys($phpExtensions))) ->icon($allExtensionsInstalled ? 'tabler-check' : 'tabler-x') - ->iconColor($allExtensionsInstalled ? 'success' : 'danger') + ->iconColor(in_array(2, $phpExtensions) ? 'primary' : ($allExtensionsInstalled ? 'success' : 'danger')) ->schema([ Placeholder::make('') ->content('All needed PHP Extensions are installed.') + ->helperText(implode(', ', [$phpExtensions['MySQL'] == 1 ? 'Mysql' : '', $phpExtensions['SQLite3'] == 1 ? 'SQLite3' : ''])) ->visible($allExtensionsInstalled), Placeholder::make('') - ->content('The following PHP Extensions are missing: ' . implode(', ', array_keys($phpExtensions, false))) + ->content('The following PHP Extensions are missing: ' . implode(', ', array_keys($phpExtensions, 0))) ->visible(!$allExtensionsInstalled), ]); $folderPermissions = [ - 'Storage' => substr(sprintf('%o', fileperms(base_path('storage/'))), -4) >= 755, - 'Cache' => substr(sprintf('%o', fileperms(base_path('bootstrap/cache/'))), -4) >= 755, + 'Ownership' => function_exists('posix_getpwuid') ? self::checkOwner() : 2, + 'Storage' => substr(sprintf('%o', fileperms(base_path('storage/'))), -4) == 755, + 'Cache' => substr(sprintf('%o', fileperms(base_path('bootstrap/cache/'))), -4) == 755, ]; - $correctFolderPermissions = !in_array(false, $folderPermissions); + $correctFolderPermissions = !in_array(0, $folderPermissions); $fields[] = Section::make('Folder Permissions') ->description(implode(', ', array_keys($folderPermissions))) ->icon($correctFolderPermissions ? 'tabler-check' : 'tabler-x') - ->iconColor($correctFolderPermissions ? 'success' : 'danger') + ->iconColor($correctFolderPermissions && $folderPermissions['Ownership'] == 2 ? 'primary' : ($correctFolderPermissions ? 'success' : 'danger')) ->schema([ Placeholder::make('') ->content('All Folders have the correct permissions.') + ->helperText($folderPermissions['Ownership'] == 2 ? "(Couldn't check ownership)" : null) ->visible($correctFolderPermissions), Placeholder::make('') - ->content('The following Folders have wrong permissions: ' . implode(', ', array_keys($folderPermissions, false))) - ->visible(!$correctFolderPermissions), + ->key('wrong_chmod') + ->content('The following Folders have wrong permissions: ' . implode(', ', array_keys($folderPermissions, 0))) + ->visible(!$correctFolderPermissions) + ->hintAction( + FormAction::make('chmod') + ->label('Fix that') + ->icon('tabler-refresh') + ->hidden($correctFolderPermissions) + ->action(function () { + $process = new Process(['chmod', '-R', '755', 'storage', 'bootstrap/cache']); + $process->run(function ($type, $buffer) { + if ($type === Process::ERR) { + Notification::make() + ->title("Couldn't chmod !") + ->body($buffer) + ->danger() + ->send(); + } else { + Notification::make() + ->title($buffer) + ->info() + ->send(); + } + }); + }) + ), ]); return Step::make('requirements') @@ -84,4 +113,16 @@ public static function make(): Step } }); } + + public static function checkOwner(): bool + { + $rightUser = posix_getpwuid(fileowner(base_path('public'))); + $folders = ['public', 'database', 'bootstrap', 'storage']; + $result = []; + foreach ($folders as $folder) { + $result[] = posix_getpwuid(fileowner(base_path($folder)))['name'] == $rightUser['name']; + } + + return !in_array(0, $result); + } } diff --git a/app/Filament/Pages/Settings.php b/app/Filament/Pages/Settings.php index ea1e099c83..ffeeaec6e1 100644 --- a/app/Filament/Pages/Settings.php +++ b/app/Filament/Pages/Settings.php @@ -26,6 +26,8 @@ use Filament\Pages\Page; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Notification as MailNotification; +use GuzzleHttp\Client; +use GuzzleHttp\Exception\GuzzleException; /** * @property Form $form @@ -148,25 +150,27 @@ private function generalSettings(): array ->requiresConfirmation() ->action(fn (Set $set) => $set('TRUSTED_PROXIES', [])), FormAction::make('cloudflare') - ->label('Set to Cloudflare IPs') + ->label('Add Cloudflare IPs') ->icon('tabler-brand-cloudflare') - ->action(fn (Set $set) => $set('TRUSTED_PROXIES', [ - '173.245.48.0/20', - '103.21.244.0/22', - '103.22.200.0/22', - '103.31.4.0/22', - '141.101.64.0/18', - '108.162.192.0/18', - '190.93.240.0/20', - '188.114.96.0/20', - '197.234.240.0/22', - '198.41.128.0/17', - '162.158.0.0/15', - '104.16.0.0/13', - '104.24.0.0/14', - '172.64.0.0/13', - '131.0.72.0/22', - ])), + ->action(function (Get $get, Set $set) { + $client = new Client(); + try { + $response = $client->request('GET', 'https://api.cloudflare.com/client/v4/ips', + [ + 'timeout' => config('panel.guzzle.timeout'), + 'connect_timeout' => config('panel.guzzle.connect_timeout'), + ] + ); + if ($response->getStatusCode() === 200) { + $body = json_decode($response->getBody(), true)['result']; + $body = array_unique(array_merge($body['ipv4_cidrs'], $body['ipv6_cidrs'])); + $ips = array_unique(array_merge($get('TRUSTED_PROXIES') ?? [], $body)); + $set('TRUSTED_PROXIES', $ips); + } + } catch (GuzzleException $e) { + exit($e); + } + }), ]), ]; }