150 lines
4.6 KiB
PHP
150 lines
4.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Admin\Pages;
|
|
|
|
use App\Models\Setting;
|
|
use App\Services\Agent\AgentClient;
|
|
use BackedEnum;
|
|
use Exception;
|
|
use Filament\Forms\Components\Select;
|
|
use Filament\Forms\Components\Toggle;
|
|
use Filament\Forms\Concerns\InteractsWithForms;
|
|
use Filament\Forms\Contracts\HasForms;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Pages\Page;
|
|
use Filament\Schemas\Components\Section;
|
|
use Filament\Support\Icons\Heroicon;
|
|
use Illuminate\Contracts\Support\Htmlable;
|
|
|
|
class Waf extends Page implements HasForms
|
|
{
|
|
use InteractsWithForms;
|
|
|
|
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedShieldCheck;
|
|
|
|
protected static ?int $navigationSort = 20;
|
|
|
|
protected static ?string $slug = 'waf';
|
|
|
|
protected string $view = 'filament.admin.pages.waf';
|
|
|
|
public bool $wafInstalled = false;
|
|
|
|
public array $wafFormData = [];
|
|
|
|
public function getTitle(): string|Htmlable
|
|
{
|
|
return __('ModSecurity / WAF');
|
|
}
|
|
|
|
public static function getNavigationLabel(): string
|
|
{
|
|
return __('ModSecurity / WAF');
|
|
}
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->wafInstalled = $this->detectWaf();
|
|
$this->wafFormData = [
|
|
'enabled' => Setting::get('waf_enabled', '0') === '1',
|
|
'paranoia' => Setting::get('waf_paranoia', '1'),
|
|
'audit_log' => Setting::get('waf_audit_log', '1') === '1',
|
|
];
|
|
}
|
|
|
|
protected function detectWaf(): bool
|
|
{
|
|
$paths = [
|
|
'/etc/nginx/modsec/main.conf',
|
|
'/etc/nginx/modsecurity.conf',
|
|
'/etc/modsecurity/modsecurity.conf',
|
|
'/etc/modsecurity/modsecurity.conf-recommended',
|
|
];
|
|
|
|
foreach ($paths as $path) {
|
|
if (file_exists($path)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
protected function getForms(): array
|
|
{
|
|
return ['wafForm'];
|
|
}
|
|
|
|
public function wafForm(\Filament\Schemas\Schema $schema): \Filament\Schemas\Schema
|
|
{
|
|
return $schema
|
|
->statePath('wafFormData')
|
|
->schema([
|
|
Section::make(__('WAF Settings'))
|
|
->schema([
|
|
Toggle::make('enabled')
|
|
->label(__('Enable ModSecurity'))
|
|
->disabled(fn () => ! $this->wafInstalled)
|
|
->helperText(fn () => $this->wafInstalled ? null : __('ModSecurity is not installed. Install it to enable WAF.')),
|
|
Select::make('paranoia')
|
|
->label(__('Paranoia Level'))
|
|
->options([
|
|
'1' => '1 - Basic',
|
|
'2' => '2 - Moderate',
|
|
'3' => '3 - Strict',
|
|
'4' => '4 - Very Strict',
|
|
])
|
|
->default('1'),
|
|
Toggle::make('audit_log')
|
|
->label(__('Enable Audit Log')),
|
|
])
|
|
->columns(2),
|
|
]);
|
|
}
|
|
|
|
public function saveWafSettings(): void
|
|
{
|
|
$data = $this->wafForm->getState();
|
|
$requestedEnabled = ! empty($data['enabled']);
|
|
if ($requestedEnabled && ! $this->wafInstalled) {
|
|
$requestedEnabled = false;
|
|
}
|
|
|
|
Setting::set('waf_enabled', $requestedEnabled ? '1' : '0');
|
|
Setting::set('waf_paranoia', (string) ($data['paranoia'] ?? '1'));
|
|
Setting::set('waf_audit_log', ! empty($data['audit_log']) ? '1' : '0');
|
|
|
|
try {
|
|
$agent = new AgentClient;
|
|
$agent->wafApplySettings(
|
|
$requestedEnabled,
|
|
(string) ($data['paranoia'] ?? '1'),
|
|
! empty($data['audit_log'])
|
|
);
|
|
|
|
if (! $this->wafInstalled && ! empty($data['enabled'])) {
|
|
Notification::make()
|
|
->title(__('ModSecurity is not installed'))
|
|
->body(__('WAF was disabled automatically. Install ModSecurity to enable it.'))
|
|
->warning()
|
|
->send();
|
|
|
|
return;
|
|
}
|
|
|
|
Notification::make()
|
|
->title(__('WAF settings applied'))
|
|
->success()
|
|
->send();
|
|
} catch (Exception $e) {
|
|
Notification::make()
|
|
->title(__('WAF settings saved, but apply failed'))
|
|
->body($e->getMessage())
|
|
->warning()
|
|
->send();
|
|
}
|
|
}
|
|
}
|