diff --git a/app/Livewire/Modals/Fail2banBans.php b/app/Livewire/Modals/Fail2banBans.php new file mode 100644 index 0000000..686b487 --- /dev/null +++ b/app/Livewire/Modals/Fail2banBans.php @@ -0,0 +1,112 @@ +serverId = $serverId; + $this->loadJails($fail2ban); + } + + public static function modalMaxWidth(): string + { + return 'lg'; + } + + /** Read the live jail/banned-IP status (same Fail2banService::status the page calls). */ + private function loadJails(Fail2banService $fail2ban): void + { + $server = Server::find($this->serverId); + if (! $server) { + $this->error = __('common.server_not_found'); + + return; + } + + try { + $status = $fail2ban->status($server); + $this->jails = $status['jails'] ?? []; + $this->error = ! empty($status['readError']) ? __('servers.fail2ban_read_error') : null; + $this->loaded = true; + } catch (Throwable $e) { + $this->error = Str::limit($e->getMessage(), 120); + } + } + + /** + * Unban one IP — mirrors Show::unbanIp: call Fail2banService::unban, audit the + * success, refresh this list, and dispatch `fail2banChanged` so the page panel + * re-reads its own fail2ban state. + */ + public function unbanIp(string $jail, string $ip, Fail2banService $fail2ban): void + { + $server = Server::find($this->serverId); + if (! $server) { + $this->error = __('common.server_not_found'); + + return; + } + + try { + $res = $fail2ban->unban($server, $jail, $ip); + } catch (Throwable $e) { + $this->dispatch('notify', message: __('servers.notify_unban_failed', ['error' => Str::limit($e->getMessage(), 90)])); + + return; + } + if (! $res['ok']) { + $this->dispatch('notify', message: __('servers.notify_unban_failed', ['error' => Str::limit($res['output'] ?: __('servers.error_unknown'), 90)])); + + return; + } + + AuditEvent::create([ + 'user_id' => Auth::id(), + 'server_id' => $server->id, + 'actor' => Auth::user()?->name ?? 'system', + 'action' => 'fail2ban.unban', + 'target' => $ip.' · '.$jail.' · '.$server->name, + 'ip' => request()->ip(), + ]); + + $this->dispatch('notify', message: __('servers.notify_ip_unbanned', ['ip' => $ip])); + + // Re-read this modal's list, then tell the page panel to re-pull its own state. + $this->loadJails($fail2ban); + $this->dispatch('fail2banChanged'); + } + + public function render() + { + return view('livewire.modals.fail2ban-bans'); + } +} diff --git a/lang/de/servers.php b/lang/de/servers.php index 2ff282b..b155d7d 100644 --- a/lang/de/servers.php +++ b/lang/de/servers.php @@ -121,6 +121,10 @@ return [ 'fail2ban_banned' => 'gebannt: :count', 'fail2ban_failed' => 'Fehlversuche: :count', 'fail2ban_no_banned' => 'Keine gebannten IPs.', + 'fail2ban_jails_count' => ':count Jails', + 'fail2ban_view_bans' => 'Gesperrte IPs ansehen', + 'fail2ban_bans_title' => 'Gesperrte IPs', + 'fail2ban_bans_subtitle' => 'Aktive fail2ban-Jails und ihre aktuell gesperrten IP-Adressen. Zum Entsperren einer IP auf „Entsperren" tippen.', 'whitelist_label' => 'Whitelist (ignoreip)', 'whitelist_placeholder' => 'IP oder CIDR', diff --git a/lang/en/servers.php b/lang/en/servers.php index e390bec..ac96528 100644 --- a/lang/en/servers.php +++ b/lang/en/servers.php @@ -121,6 +121,10 @@ return [ 'fail2ban_banned' => 'banned: :count', 'fail2ban_failed' => 'failed attempts: :count', 'fail2ban_no_banned' => 'No banned IPs.', + 'fail2ban_jails_count' => ':count jails', + 'fail2ban_view_bans' => 'View banned IPs', + 'fail2ban_bans_title' => 'Banned IPs', + 'fail2ban_bans_subtitle' => 'Active fail2ban jails and their currently banned IP addresses. Tap “Unlock” to unban an IP.', 'whitelist_label' => 'Whitelist (ignoreip)', 'whitelist_placeholder' => 'IP or CIDR', diff --git a/resources/views/livewire/modals/fail2ban-bans.blade.php b/resources/views/livewire/modals/fail2ban-bans.blade.php new file mode 100644 index 0000000..3fd892e --- /dev/null +++ b/resources/views/livewire/modals/fail2ban-bans.blade.php @@ -0,0 +1,55 @@ +
{{ __('servers.fail2ban_bans_subtitle') }}
+{{ $error }}
+{{ $jail['name'] }}
++ ($jail['currentlyBanned'] ?? 0) > 0])>{{ __('servers.fail2ban_banned', ['count' => $jail['currentlyBanned'] ?? 0]) }} + · {{ __('servers.fail2ban_failed', ['count' => $jail['currentlyFailed'] ?? 0]) }} +
+{{ __('servers.fail2ban_no_banned') }}
+ @endif +{{ $loaded ? __('servers.fail2ban_no_banned') : __('servers.loading') }}
+{{ $jail['name'] }}
-- ($jail['currentlyBanned'] ?? 0) > 0])>{{ __('servers.fail2ban_banned', ['count' => $jail['currentlyBanned'] ?? 0]) }} - · {{ __('servers.fail2ban_failed', ['count' => $jail['currentlyFailed'] ?? 0]) }} -
-{{ __('servers.fail2ban_no_banned') }}
- @endif -+ {{ __('common.active') }} + · $f2bBanned > 0])>{{ __('servers.fail2ban_banned', ['count' => $f2bBanned]) }} + · {{ __('servers.fail2ban_jails_count', ['count' => count($f2bJails)]) }} +
+