parent
4d1fd64158
commit
ee44ff3def
|
|
@ -7,10 +7,9 @@ use Livewire\Component;
|
|||
|
||||
class Fail2BanCard extends Component
|
||||
{
|
||||
public bool $available = true; // fail2ban-client vorhanden?
|
||||
public bool $permDenied = false; // Socket/Root-Rechte fehlen?
|
||||
public int $activeBans = 0; // Summe gebannter IPs
|
||||
/** @var array<int,array{name:string,banned:int,bantime:int}> */
|
||||
public bool $available = true;
|
||||
public bool $permDenied = false;
|
||||
public int $activeBans = 0;
|
||||
public array $jails = [];
|
||||
|
||||
public function mount(): void
|
||||
|
|
@ -28,12 +27,13 @@ class Fail2BanCard extends Component
|
|||
$this->load(true);
|
||||
}
|
||||
|
||||
// Optional: öffnet später dein Detail-Modal/Tab
|
||||
public function openDetails(string $jail): void
|
||||
{
|
||||
$this->dispatch('openModal', component: 'ui.security.modal.fail2-ban-jail-modal', arguments: ['jail' => $jail]);
|
||||
// KORREKTER DISPATCH für wire-elements/modal
|
||||
$this->dispatch('openModal', 'ui.security.modal.fail2ban-jail-modal', ['jail' => $jail]);
|
||||
}
|
||||
/* ---------------- intern ---------------- */
|
||||
|
||||
/* ------------------- intern ------------------- */
|
||||
|
||||
protected function load(bool $force = false): void
|
||||
{
|
||||
|
|
@ -46,7 +46,6 @@ class Fail2BanCard extends Component
|
|||
return;
|
||||
}
|
||||
|
||||
// Rechtecheck
|
||||
[$ok, $raw] = $this->f2b('ping');
|
||||
if (!$ok && stripos($raw, 'permission denied') !== false) {
|
||||
$this->available = true;
|
||||
|
|
@ -56,18 +55,16 @@ class Fail2BanCard extends Component
|
|||
return;
|
||||
}
|
||||
|
||||
// Jails laden
|
||||
[, $status] = $this->f2b('status');
|
||||
$jailsLn = $this->firstMatch('/Jail list:\s*(.+)$/mi', $status);
|
||||
$jails = $jailsLn ? array_filter(array_map('trim', preg_split('/\s*,\s*/', $jailsLn))) : [];
|
||||
|
||||
$rows = [];
|
||||
$sum = 0;
|
||||
|
||||
foreach ($jails as $j) {
|
||||
[, $s] = $this->f2b('status ' . escapeshellarg($j));
|
||||
$banned = (int)($this->firstMatch('/Currently banned:\s+(\d+)/i', $s) ?: 0);
|
||||
$bantime = $this->getBantime($j); // Sek.; -1 = permanent
|
||||
$bantime = $this->getBantime($j);
|
||||
$rows[] = ['name' => $j, 'banned' => $banned, 'bantime' => $bantime];
|
||||
$sum += $banned;
|
||||
}
|
||||
|
|
@ -78,15 +75,12 @@ class Fail2BanCard extends Component
|
|||
$this->jails = $rows;
|
||||
}
|
||||
|
||||
/** sudo + fail2ban-client ausführen; [ok, output] */
|
||||
private function f2b(string $args): array
|
||||
{
|
||||
$sudo = '/usr/bin/sudo';
|
||||
$f2b = '/usr/bin/fail2ban-client';
|
||||
$out = (string)@shell_exec("timeout 2 $sudo -n $f2b $args 2>&1");
|
||||
$ok = stripos($out, 'Status') !== false
|
||||
|| stripos($out, 'Jail list') !== false
|
||||
|| stripos($out, 'pong') !== false;
|
||||
$ok = str_contains($out, 'Status') || str_contains($out, 'Jail list') || str_contains($out, 'pong');
|
||||
return [$ok, $out];
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +89,7 @@ class Fail2BanCard extends Component
|
|||
[, $out] = $this->f2b('get ' . escapeshellarg($jail) . ' bantime');
|
||||
$val = trim($out);
|
||||
if (preg_match('/-?\d+/', $val, $m)) return (int)$m[0];
|
||||
return 600; // defensiver Default
|
||||
return 600;
|
||||
}
|
||||
|
||||
private function firstMatch(string $pattern, string $haystack): ?string
|
||||
|
|
@ -105,6 +99,110 @@ class Fail2BanCard extends Component
|
|||
}
|
||||
|
||||
|
||||
//namespace App\Livewire\Ui\Security;
|
||||
//
|
||||
//use Livewire\Component;
|
||||
//
|
||||
//class Fail2BanCard extends Component
|
||||
//{
|
||||
// public bool $available = true; // fail2ban-client vorhanden?
|
||||
// public bool $permDenied = false; // Socket/Root-Rechte fehlen?
|
||||
// public int $activeBans = 0; // Summe gebannter IPs
|
||||
// /** @var array<int,array{name:string,banned:int,bantime:int}> */
|
||||
// public array $jails = [];
|
||||
//
|
||||
// public function mount(): void
|
||||
// {
|
||||
// $this->load();
|
||||
// }
|
||||
//
|
||||
// public function render()
|
||||
// {
|
||||
// return view('livewire.ui.security.fail2-ban-card');
|
||||
// }
|
||||
//
|
||||
// public function refresh(): void
|
||||
// {
|
||||
// $this->load(true);
|
||||
// }
|
||||
//
|
||||
// // Optional: öffnet später dein Detail-Modal/Tab
|
||||
// public function openDetails(string $jail): void
|
||||
// {
|
||||
// $this->dispatch('openModal', 'ui.security.modal.fail2-ban-jail-modal', ['jail' => $jail]);
|
||||
// }
|
||||
// /* ---------------- intern ---------------- */
|
||||
//
|
||||
// protected function load(bool $force = false): void
|
||||
// {
|
||||
// $bin = trim((string)@shell_exec('command -v fail2ban-client 2>/dev/null')) ?: '';
|
||||
// if ($bin === '') {
|
||||
// $this->available = false;
|
||||
// $this->permDenied = false;
|
||||
// $this->activeBans = 0;
|
||||
// $this->jails = [];
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Rechtecheck
|
||||
// [$ok, $raw] = $this->f2b('ping');
|
||||
// if (!$ok && stripos($raw, 'permission denied') !== false) {
|
||||
// $this->available = true;
|
||||
// $this->permDenied = true;
|
||||
// $this->activeBans = 0;
|
||||
// $this->jails = [];
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Jails laden
|
||||
// [, $status] = $this->f2b('status');
|
||||
// $jailsLn = $this->firstMatch('/Jail list:\s*(.+)$/mi', $status);
|
||||
// $jails = $jailsLn ? array_filter(array_map('trim', preg_split('/\s*,\s*/', $jailsLn))) : [];
|
||||
//
|
||||
// $rows = [];
|
||||
// $sum = 0;
|
||||
//
|
||||
// foreach ($jails as $j) {
|
||||
// [, $s] = $this->f2b('status ' . escapeshellarg($j));
|
||||
// $banned = (int)($this->firstMatch('/Currently banned:\s+(\d+)/i', $s) ?: 0);
|
||||
// $bantime = $this->getBantime($j); // Sek.; -1 = permanent
|
||||
// $rows[] = ['name' => $j, 'banned' => $banned, 'bantime' => $bantime];
|
||||
// $sum += $banned;
|
||||
// }
|
||||
//
|
||||
// $this->available = true;
|
||||
// $this->permDenied = false;
|
||||
// $this->activeBans = $sum;
|
||||
// $this->jails = $rows;
|
||||
// }
|
||||
//
|
||||
// /** sudo + fail2ban-client ausführen; [ok, output] */
|
||||
// private function f2b(string $args): array
|
||||
// {
|
||||
// $sudo = '/usr/bin/sudo';
|
||||
// $f2b = '/usr/bin/fail2ban-client';
|
||||
// $out = (string)@shell_exec("timeout 2 $sudo -n $f2b $args 2>&1");
|
||||
// $ok = stripos($out, 'Status') !== false
|
||||
// || stripos($out, 'Jail list') !== false
|
||||
// || stripos($out, 'pong') !== false;
|
||||
// return [$ok, $out];
|
||||
// }
|
||||
//
|
||||
// private function getBantime(string $jail): int
|
||||
// {
|
||||
// [, $out] = $this->f2b('get ' . escapeshellarg($jail) . ' bantime');
|
||||
// $val = trim($out);
|
||||
// if (preg_match('/-?\d+/', $val, $m)) return (int)$m[0];
|
||||
// return 600; // defensiver Default
|
||||
// }
|
||||
//
|
||||
// private function firstMatch(string $pattern, string $haystack): ?string
|
||||
// {
|
||||
// return preg_match($pattern, $haystack, $m) ? trim($m[1]) : null;
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
//namespace App\Livewire\Ui\Security;
|
||||
//
|
||||
//use Livewire\Component;
|
||||
|
|
|
|||
|
|
@ -30,14 +30,22 @@
|
|||
<div class="rounded-xl border border-white/10 bg-white/5 px-3 py-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-white/85 font-medium">{{ $j['name'] }}</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-[11px] text-white/60">
|
||||
Bannzeit:
|
||||
@if($j['bantime'] === -1)
|
||||
permanent
|
||||
@else
|
||||
{{ $j['bantime'] }}s
|
||||
@endif
|
||||
</span>
|
||||
<span class="px-2 py-0.5 rounded-full border text-[11px]
|
||||
{{ $j['banned']>0 ? 'text-amber-200 border-amber-400/30 bg-amber-500/10' : 'text-white/60 border-white/20 bg-white/5' }}">
|
||||
{{ $j['banned'] }} gebannt
|
||||
</span>
|
||||
{{-- Optional: Details öffnen (Tab/Modal) --}}
|
||||
<button wire:click="openDetails('{{ $j['name'] }}')"
|
||||
|
||||
{{-- fix: stop event bubbling --}}
|
||||
<button wire:click.stop="openDetails('{{ $j['name'] }}')"
|
||||
class="text-[11px] px-2 py-0.5 rounded border border-white/15 bg-white/5 hover:bg-white/10">
|
||||
Details
|
||||
</button>
|
||||
|
|
@ -79,6 +87,68 @@
|
|||
{{-- @endif--}}
|
||||
{{-- </div>--}}
|
||||
|
||||
{{-- @if(!$available)--}}
|
||||
{{-- <div class="text-sm text-white/60">fail2ban-client wurde nicht gefunden.</div>--}}
|
||||
{{-- @elseif($permDenied)--}}
|
||||
{{-- <div class="text-sm text-amber-200">--}}
|
||||
{{-- Keine Berechtigung auf <code class="font-mono">/var/run/fail2ban/fail2ban.sock</code>.--}}
|
||||
{{-- <span class="opacity-80">Sudo-Regel prüfen.</span>--}}
|
||||
{{-- </div>--}}
|
||||
{{-- @else--}}
|
||||
{{-- <div class="space-y-2">--}}
|
||||
{{-- @forelse($jails as $j)--}}
|
||||
{{-- <div class="rounded-xl border border-white/10 bg-white/5 px-3 py-2">--}}
|
||||
{{-- <div class="flex items-center justify-between">--}}
|
||||
{{-- <div class="text-white/85 font-medium">{{ $j['name'] }}</div>--}}
|
||||
|
||||
{{-- <div class="flex items-center gap-2">--}}
|
||||
{{-- <span class="px-2 py-0.5 rounded-full border text-[11px]--}}
|
||||
{{-- {{ $j['banned']>0 ? 'text-amber-200 border-amber-400/30 bg-amber-500/10' : 'text-white/60 border-white/20 bg-white/5' }}">--}}
|
||||
{{-- {{ $j['banned'] }} gebannt--}}
|
||||
{{-- </span>--}}
|
||||
{{-- --}}{{-- Optional: Details öffnen (Tab/Modal) --}}
|
||||
{{-- <button wire:click="openDetails('{{ $j['name'] }}')"--}}
|
||||
{{-- class="text-[11px] px-2 py-0.5 rounded border border-white/15 bg-white/5 hover:bg-white/10">--}}
|
||||
{{-- Details--}}
|
||||
{{-- </button>--}}
|
||||
{{-- </div>--}}
|
||||
{{-- </div>--}}
|
||||
{{-- </div>--}}
|
||||
{{-- @empty--}}
|
||||
{{-- <div class="text-sm text-white/60">Keine Jails gefunden.</div>--}}
|
||||
{{-- @endforelse--}}
|
||||
{{-- </div>--}}
|
||||
|
||||
{{-- <div class="mt-4 flex justify-end">--}}
|
||||
{{-- <button wire:click="refresh" wire:loading.attr="disabled"--}}
|
||||
{{-- class="px-3 py-1.5 text-[12px] rounded-lg bg-white/5 border border-white/10 hover:bg-white/10">--}}
|
||||
{{-- <i class="ph ph-arrows-clockwise text-[13px]"></i>--}}
|
||||
{{-- <span wire:loading.remove>Neu prüfen</span>--}}
|
||||
{{-- <span wire:loading>prüfe…</span>--}}
|
||||
{{-- </button>--}}
|
||||
{{-- </div>--}}
|
||||
{{-- @endif--}}
|
||||
{{--</div>--}}
|
||||
|
||||
{{--<div class="glass-card p-4 rounded-2xl border border-white/10 bg-white/5">--}}
|
||||
{{-- <div class="flex items-center justify-between mb-3">--}}
|
||||
{{-- <div class="inline-flex items-center gap-2 bg-white/5 border border-white/10 px-2.5 py-1 rounded-full">--}}
|
||||
{{-- <i class="ph ph-shield-checkered text-white/70 text-[13px]"></i>--}}
|
||||
{{-- <span class="text-[11px] uppercase text-white/70">Fail2Ban</span>--}}
|
||||
{{-- </div>--}}
|
||||
|
||||
{{-- @if($available)--}}
|
||||
{{-- <span class="px-2 py-0.5 rounded-full border text-xs--}}
|
||||
{{-- {{ $activeBans>0 ? 'text-amber-200 border-amber-400/30 bg-amber-500/10' : 'text-emerald-300 border-emerald-400/30 bg-emerald-500/10' }}">--}}
|
||||
{{-- {{ $activeBans }} aktuell--}}
|
||||
{{-- </span>--}}
|
||||
{{-- @else--}}
|
||||
{{-- <span class="px-2 py-0.5 rounded-full border text-xs text-rose-300 border-rose-400/30 bg-rose-500/10">--}}
|
||||
{{-- nicht installiert--}}
|
||||
{{-- </span>--}}
|
||||
{{-- @endif--}}
|
||||
{{-- </div>--}}
|
||||
|
||||
{{-- @if(!$available)--}}
|
||||
{{-- <div class="text-sm text-white/60">fail2ban-client wurde nicht gefunden.</div>--}}
|
||||
{{-- @else--}}
|
||||
|
|
|
|||
Loading…
Reference in New Issue