From 9acea7b89befde39354c72f41dc7b26c1c4e4646 Mon Sep 17 00:00:00 2001 From: boban Date: Sat, 1 Nov 2025 22:20:53 +0100 Subject: [PATCH] =?UTF-8?q?Fix:=20Mailbox=20Stats=20=C3=BCber=20Dovecot=20?= =?UTF-8?q?mit=20config/mailpool.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Livewire/Ui/Security/Fail2banBanlist.php | 135 +++++++++++------- .../ui/system/backup-status-card.blade.php | 2 +- 2 files changed, 85 insertions(+), 52 deletions(-) diff --git a/app/Livewire/Ui/Security/Fail2banBanlist.php b/app/Livewire/Ui/Security/Fail2banBanlist.php index 27ecffd..4ccaa6a 100644 --- a/app/Livewire/Ui/Security/Fail2banBanlist.php +++ b/app/Livewire/Ui/Security/Fail2banBanlist.php @@ -4,12 +4,18 @@ namespace App\Livewire\Ui\Security; use Livewire\Attributes\On; use Livewire\Component; -use Illuminate\Support\Str; class Fail2banBanlist extends Component { + /** + * null oder '*' => alle Jails + * 'recidive' => nur dieses Jail + * 'mailwolt-blacklist' etc. + */ + public ?string $jail = null; + + /** @var array */ public array $banned = []; - public string $jail = 'mailwolt-blacklist'; // Dein dedizierter Jail #[On('f2b:refresh')] public function refreshList(): void @@ -17,61 +23,88 @@ class Fail2banBanlist extends Component $this->loadBannedIps(); } - public function mount(): void + public function mount(?string $jail = null): void { + // erlaubt optionalen Param via + $this->jail = $jail; $this->loadBannedIps(); } - private function loadBannedIps(): void - { - $output = @shell_exec(sprintf('sudo -n /usr/bin/fail2ban-client status %s 2>&1', escapeshellarg($this->jail))); - - if (!$output) { - $this->banned = []; - return; - } - - // Beispielausgabe: - // Status for the jail: mailwolt-blacklist - // |- Filter - // | |- Currently failed: 0 - // | `- Total failed: 0 - // `- Actions - // |- Currently banned: 2 - // | `- IP list: 203.0.113.45 198.51.100.22 - // `- Total banned: 2 - - if (preg_match('/IP list:\s*(.+)$/mi', $output, $m)) { - $ips = preg_split('/\s+/', trim($m[1])); - $this->banned = array_values(array_filter($ips, fn($ip) => filter_var($ip, FILTER_VALIDATE_IP))); - } else { - $this->banned = []; - } - } - - public function unban(string $ip): void - { - if (!filter_var($ip, FILTER_VALIDATE_IP)) { - return; - } - - $ipEsc = escapeshellarg($ip); - $cmd = sprintf('sudo -n /usr/bin/fail2ban-client set %s unbanip %s 2>&1', escapeshellarg($this->jail), $ipEsc); - @shell_exec($cmd); - - $this->dispatch('toast', - type: 'info', - badge: 'Fail2Ban', - title: 'IP entbannt', - text: "Die IP {$ip} wurde erfolgreich entbannt.", - duration: 6000, - ); - - $this->refreshList(); - } - public function render() { return view('livewire.ui.security.fail2ban-banlist'); } + + /* ================= core ================= */ + + private function loadBannedIps(): void + { + $jails = $this->jailList(); + + // ggf. nur ein bestimmtes Jail anzeigen + if (is_string($this->jail) && $this->jail !== '' && $this->jail !== '*') { + $jails = in_array($this->jail, $jails, true) ? [$this->jail] : []; + } + + $ips = []; + foreach ($jails as $j) { + $out = $this->f2b("status ".escapeshellarg($j)); + if (preg_match('/IP list:\s*(.+)$/mi', $out, $m)) { + $parts = preg_split('/\s+/', trim($m[1])); + foreach ($parts as $ip) { + if (filter_var($ip, FILTER_VALIDATE_IP)) $ips[] = $ip; + } + } + } + + $this->banned = array_values(array_unique($ips)); + } + + /** Entbannt IP in allen passenden Jails */ + public function unban(string $ip): void + { + if (!filter_var($ip, FILTER_VALIDATE_IP)) return; + + $jails = $this->jailList(); + if (is_string($this->jail) && $this->jail !== '' && $this->jail !== '*') { + $jails = in_array($this->jail, $jails, true) ? [$this->jail] : []; + } + + $cnt = 0; + foreach ($jails as $j) { + $this->f2b("set ".escapeshellarg($j)." unbanip ".escapeshellarg($ip)); + $cnt++; + } + + $this->loadBannedIps(); + + $this->dispatch('toast', + type: 'done', + badge: 'Fail2Ban', + title: 'IP entbannt', + text: ($this->jail && $this->jail !== '*') + ? "IP {$ip} in Jail „{$this->jail}“ entbannt." + : "IP {$ip} in {$cnt} Jail(s) entbannt.", + duration: 5000, + ); + } + + /* ================= helpers ================= */ + + /** Liefert Liste aller Jails über fail2ban-client */ + private function jailList(): array + { + $out = $this->f2b('status'); + if (preg_match('/Jail list:\s*(.+)$/mi', $out, $m)) { + $jails = array_map('trim', preg_split('/\s*,\s*/', trim($m[1]))); + return array_values(array_filter($jails, fn($v) => $v !== '')); + } + return []; + } + + /** führt fail2ban-client via sudo aus und gibt stdout zurück */ + private function f2b(string $args): string + { + return (string) @shell_exec('sudo -n /usr/bin/fail2ban-client '.$args.' 2>&1'); + } } diff --git a/resources/views/livewire/ui/system/backup-status-card.blade.php b/resources/views/livewire/ui/system/backup-status-card.blade.php index e0534f3..c0f27a8 100644 --- a/resources/views/livewire/ui/system/backup-status-card.blade.php +++ b/resources/views/livewire/ui/system/backup-status-card.blade.php @@ -1,5 +1,5 @@
+ @if($running) wire:poll.2s="refresh" @endif>