wafInstalled = $this->detectWaf(); $whitelistRaw = Setting::get('waf_whitelist_rules', '[]'); $whitelistRules = json_decode($whitelistRaw, true); if (! is_array($whitelistRules)) { $whitelistRules = []; } $this->wafFormData = [ 'enabled' => Setting::get('waf_enabled', '0') === '1', 'paranoia' => Setting::get('waf_paranoia', '1'), 'audit_log' => Setting::get('waf_audit_log', '1') === '1', 'whitelist_rules' => $whitelistRules, ]; } 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), Section::make(__('Whitelist Rules')) ->description(__('Exclude trusted traffic from specific ModSecurity rule IDs.')) ->schema([ Repeater::make('whitelist_rules') ->label(__('Whitelist Entries')) ->schema([ TextInput::make('label') ->label(__('Name')) ->placeholder(__('Admin API allowlist')) ->maxLength(80), Select::make('match_type') ->label(__('Match Type')) ->options([ 'ip' => __('IP Address or CIDR'), 'uri_exact' => __('Exact URI'), 'uri_prefix' => __('URI Prefix'), 'host' => __('Host Header'), ]) ->required(), TextInput::make('match_value') ->label(__('Match Value')) ->placeholder(__('Example: 203.0.113.10 or /wp-admin/admin-ajax.php')) ->required(), TextInput::make('rule_ids') ->label(__('Rule IDs')) ->placeholder(__('Example: 942100,949110')) ->helperText(__('Comma-separated ModSecurity rule IDs to disable for matches.')) ->required(), Toggle::make('enabled') ->label(__('Enabled')) ->default(true), ]) ->itemLabel(fn (array $state): ?string => $state['label'] ?? $state['match_value'] ?? null) ->addActionLabel(__('Add Whitelist Rule')) ->collapsible() ->columns(['default' => 2, 'md' => 2]), ]) ->columns(1), ]); } 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'); Setting::set('waf_whitelist_rules', json_encode(array_values($data['whitelist_rules'] ?? []), JSON_UNESCAPED_SLASHES)); try { $agent = new AgentClient; $agent->wafApplySettings( $requestedEnabled, (string) ($data['paranoia'] ?? '1'), ! empty($data['audit_log']), $data['whitelist_rules'] ?? [] ); 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(); } } }