parent
46591669d6
commit
792f0e3528
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace App\Livewire\Ui\Security;
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
|
@ -8,11 +9,11 @@ use Livewire\Component;
|
|||
|
||||
class Fail2BanCard extends Component
|
||||
{
|
||||
public bool $available = true; // fail2ban-client vorhanden?
|
||||
public bool $permDenied = false; // sudo / Socket-Rechte fehlen?
|
||||
public bool $error = false; // anderer Fehler (Output unerwartet)
|
||||
public bool $available = true;
|
||||
public bool $permDenied = false;
|
||||
public bool $error = false;
|
||||
public int $activeBans = 0;
|
||||
public array $jails = []; // [['name','banned','bantime','ips'=>[...]]]
|
||||
public array $jails = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
|
|
@ -32,42 +33,36 @@ class Fail2BanCard extends Component
|
|||
|
||||
public function openDetails(string $jail): void
|
||||
{
|
||||
// wire-elements/modal (v2): Event-Namen + Component + Params
|
||||
$this->dispatch('openModal', component: 'ui.security.modal.fail2-ban-jail-modal', arguments: ['jail' => $jail]);
|
||||
}
|
||||
|
||||
/* ------------------- intern ------------------- */
|
||||
/* ---------------- intern ---------------- */
|
||||
|
||||
protected function load(bool $force = false): void
|
||||
{
|
||||
$this->available = true;
|
||||
$this->permDenied = false;
|
||||
$this->error = false;
|
||||
$this->available = $this->permDenied = $this->error = false;
|
||||
$this->activeBans = 0;
|
||||
$this->jails = [];
|
||||
|
||||
// existiert fail2ban-client?
|
||||
$bin = trim((string)@shell_exec('command -v fail2ban-client 2>/dev/null')) ?: '';
|
||||
if ($bin === '') {
|
||||
$this->available = false;
|
||||
return;
|
||||
}
|
||||
$this->available = true;
|
||||
|
||||
// Rechte / Erreichbarkeit
|
||||
[, $ping] = $this->f2b('ping');
|
||||
if ($this->looksDenied($ping)) {
|
||||
$this->permDenied = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Jails lesen
|
||||
[, $status] = $this->f2b('status');
|
||||
if ($this->looksDenied($status)) {
|
||||
$this->permDenied = true;
|
||||
return;
|
||||
}
|
||||
if (!preg_match('/Jail list:\s*(.+)$/mi', $status, $mm)) {
|
||||
// etwas stimmt nicht – loggen und „error“ zeigen
|
||||
$this->error = true;
|
||||
Log::warning('Fail2BanCard: unexpected status output', ['status' => $status]);
|
||||
return;
|
||||
|
|
@ -87,16 +82,8 @@ class Fail2BanCard extends Component
|
|||
|
||||
$banned = (int)($this->firstMatch('/Currently banned:\s+(\d+)/i', $s) ?: 0);
|
||||
$bantime = $this->getBantime($j);
|
||||
$ipLine = $this->firstMatch('/Banned IP list:\s*(.+)$/mi', $s) ?: '';
|
||||
$ips = $ipLine !== '' ? array_values(array_filter(array_map('trim', preg_split('/\s+/', $ipLine)))) : [];
|
||||
|
||||
$rows[] = [
|
||||
'name' => $j,
|
||||
'banned' => $banned,
|
||||
'bantime' => $bantime,
|
||||
// wir zeigen IPs NICHT mehr in der Card; Details sind im Modal
|
||||
'ips' => [],
|
||||
];
|
||||
$rows[] = ['name' => $j, 'banned' => $banned, 'bantime' => $bantime, 'ips' => []];
|
||||
$sum += $banned;
|
||||
}
|
||||
|
||||
|
|
@ -106,8 +93,8 @@ class Fail2BanCard extends Component
|
|||
|
||||
private function f2b(string $args): array
|
||||
{
|
||||
$sudo = '/usr/bin/sudo';
|
||||
$f2b = '/usr/bin/fail2ban-client';
|
||||
$sudo = $this->bin('sudo');
|
||||
$f2b = $this->bin('fail2ban-client');
|
||||
$cmd = "timeout 3 $sudo -n $f2b $args 2>&1";
|
||||
$out = (string)@shell_exec($cmd);
|
||||
|
||||
|
|
@ -125,22 +112,168 @@ class Fail2BanCard extends Component
|
|||
$this->permDenied = true;
|
||||
return 600;
|
||||
}
|
||||
$val = trim($out);
|
||||
if (preg_match('/-?\d+/', $val, $m)) return (int)$m[0];
|
||||
if (preg_match('/-?\d+/', trim($out), $m)) return (int)$m[0];
|
||||
return 600;
|
||||
}
|
||||
|
||||
private function looksDenied(string $out): bool
|
||||
{
|
||||
return preg_match('/(permission denied|not allowed to execute|a password is required)/i', $out) === 1;
|
||||
return (bool)preg_match('/(permission denied|not allowed to execute|a password is required)/i', $out);
|
||||
}
|
||||
|
||||
private function firstMatch(string $pattern, string $haystack): ?string
|
||||
{
|
||||
return preg_match($pattern, $haystack, $m) ? trim($m[1]) : null;
|
||||
}
|
||||
|
||||
private function bin(string $name): string
|
||||
{
|
||||
$p = trim((string)@shell_exec("command -v " . escapeshellarg($name) . " 2>/dev/null"));
|
||||
return $p !== '' ? $p : $name;
|
||||
}
|
||||
}
|
||||
|
||||
//namespace App\Livewire\Ui\Security;
|
||||
//
|
||||
//use Illuminate\Support\Facades\Log;
|
||||
//use Livewire\Attributes\On;
|
||||
//use Livewire\Component;
|
||||
//
|
||||
//class Fail2BanCard extends Component
|
||||
//{
|
||||
// public bool $available = true; // fail2ban-client vorhanden?
|
||||
// public bool $permDenied = false; // sudo / Socket-Rechte fehlen?
|
||||
// public bool $error = false; // anderer Fehler (Output unerwartet)
|
||||
// public int $activeBans = 0;
|
||||
// public array $jails = []; // [['name','banned','bantime','ips'=>[...]]]
|
||||
//
|
||||
// public function mount(): void
|
||||
// {
|
||||
// $this->load();
|
||||
// }
|
||||
//
|
||||
// public function render()
|
||||
// {
|
||||
// return view('livewire.ui.security.fail2-ban-card');
|
||||
// }
|
||||
//
|
||||
// #[On('f2b:refresh-banlist')]
|
||||
// public function refresh(): void
|
||||
// {
|
||||
// $this->load(true);
|
||||
// }
|
||||
//
|
||||
// public function openDetails(string $jail): void
|
||||
// {
|
||||
// // wire-elements/modal (v2): Event-Namen + Component + Params
|
||||
// $this->dispatch('openModal', component: 'ui.security.modal.fail2-ban-jail-modal', arguments: ['jail' => $jail]);
|
||||
// }
|
||||
//
|
||||
// /* ------------------- intern ------------------- */
|
||||
//
|
||||
// protected function load(bool $force = false): void
|
||||
// {
|
||||
// $this->available = true;
|
||||
// $this->permDenied = false;
|
||||
// $this->error = false;
|
||||
// $this->activeBans = 0;
|
||||
// $this->jails = [];
|
||||
//
|
||||
// // existiert fail2ban-client?
|
||||
// $bin = trim((string)@shell_exec('command -v fail2ban-client 2>/dev/null')) ?: '';
|
||||
// if ($bin === '') {
|
||||
// $this->available = false;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Rechte / Erreichbarkeit
|
||||
// [, $ping] = $this->f2b('ping');
|
||||
// if ($this->looksDenied($ping)) {
|
||||
// $this->permDenied = true;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Jails lesen
|
||||
// [, $status] = $this->f2b('status');
|
||||
// if ($this->looksDenied($status)) {
|
||||
// $this->permDenied = true;
|
||||
// return;
|
||||
// }
|
||||
// if (!preg_match('/Jail list:\s*(.+)$/mi', $status, $mm)) {
|
||||
// // etwas stimmt nicht – loggen und „error“ zeigen
|
||||
// $this->error = true;
|
||||
// Log::warning('Fail2BanCard: unexpected status output', ['status' => $status]);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// $jails = array_filter(array_map('trim', preg_split('/\s*,\s*/', $mm[1] ?? '')));
|
||||
// $sum = 0;
|
||||
// $rows = [];
|
||||
//
|
||||
// foreach ($jails as $j) {
|
||||
// $jEsc = escapeshellarg($j);
|
||||
// [, $s] = $this->f2b("status {$jEsc}");
|
||||
// if ($this->looksDenied($s)) {
|
||||
// $this->permDenied = true;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// $banned = (int)($this->firstMatch('/Currently banned:\s+(\d+)/i', $s) ?: 0);
|
||||
// $bantime = $this->getBantime($j);
|
||||
// $ipLine = $this->firstMatch('/Banned IP list:\s*(.+)$/mi', $s) ?: '';
|
||||
// $ips = $ipLine !== '' ? array_values(array_filter(array_map('trim', preg_split('/\s+/', $ipLine)))) : [];
|
||||
//
|
||||
// $rows[] = [
|
||||
// 'name' => $j,
|
||||
// 'banned' => $banned,
|
||||
// 'bantime' => $bantime,
|
||||
// // wir zeigen IPs NICHT mehr in der Card; Details sind im Modal
|
||||
// 'ips' => [],
|
||||
// ];
|
||||
// $sum += $banned;
|
||||
// }
|
||||
//
|
||||
// $this->activeBans = $sum;
|
||||
// $this->jails = $rows;
|
||||
// }
|
||||
//
|
||||
// private function f2b(string $args): array
|
||||
// {
|
||||
// $sudo = '/usr/bin/sudo';
|
||||
// $f2b = '/usr/bin/fail2ban-client';
|
||||
// $cmd = "timeout 3 $sudo -n $f2b $args 2>&1";
|
||||
// $out = (string)@shell_exec($cmd);
|
||||
//
|
||||
// $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');
|
||||
// if ($this->looksDenied($out)) {
|
||||
// $this->permDenied = true;
|
||||
// return 600;
|
||||
// }
|
||||
// $val = trim($out);
|
||||
// if (preg_match('/-?\d+/', $val, $m)) return (int)$m[0];
|
||||
// return 600;
|
||||
// }
|
||||
//
|
||||
// private function looksDenied(string $out): bool
|
||||
// {
|
||||
// return preg_match('/(permission denied|not allowed to execute|a password is required)/i', $out) === 1;
|
||||
// }
|
||||
//
|
||||
// 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\Attributes\On;
|
||||
|
|
|
|||
|
|
@ -7,28 +7,13 @@ use LivewireUI\Modal\ModalComponent;
|
|||
class Fail2BanJailModal extends ModalComponent
|
||||
{
|
||||
public string $jail = '';
|
||||
public array $rows = []; // [{ip,bantime,banned_at,remaining,until,time_text,meta_text,box_class}]
|
||||
public array $rows = [];
|
||||
|
||||
public static function modalMaxWidth(): string
|
||||
{
|
||||
return '4xl';
|
||||
}
|
||||
public static function modalMaxWidth(): string { return '4xl'; }
|
||||
|
||||
public function mount(string $jail): void
|
||||
{
|
||||
$this->jail = $jail;
|
||||
$this->load();
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.ui.security.modal.fail2-ban-jail-modal');
|
||||
}
|
||||
|
||||
public function refresh(): void
|
||||
{
|
||||
$this->load(true);
|
||||
}
|
||||
public function mount(string $jail): void { $this->jail = $jail; $this->load(); }
|
||||
public function refresh(): void { $this->load(true); }
|
||||
public function render() { return view('livewire.ui.security.modal.fail2-ban-jail-modal'); }
|
||||
|
||||
/* ---------------- intern ---------------- */
|
||||
|
||||
|
|
@ -36,8 +21,7 @@ class Fail2BanJailModal extends ModalComponent
|
|||
{
|
||||
$jail = $this->jail;
|
||||
|
||||
// Aktuell gebannte IPs
|
||||
[, $s] = $this->f2b('status ' . escapeshellarg($jail));
|
||||
[, $s] = $this->f2b('status '.escapeshellarg($jail));
|
||||
$ipList = $this->firstMatch('/Banned IP list:\s*(.+)$/mi', $s) ?: '';
|
||||
$ips = $ipList !== '' ? array_values(array_filter(array_map('trim', preg_split('/\s+/', $ipList)))) : [];
|
||||
|
||||
|
|
@ -47,24 +31,24 @@ class Fail2BanJailModal extends ModalComponent
|
|||
foreach ($ips as $ip) {
|
||||
$banAt = $this->lastBanTimestamp($jail, $ip); // Unix-Timestamp oder null
|
||||
|
||||
$remaining = null;
|
||||
$until = null;
|
||||
|
||||
$remaining = null; $until = null;
|
||||
if ($bantime === -1) {
|
||||
$remaining = -1;
|
||||
$remaining = -1; // permanent
|
||||
} elseif ($banAt !== null) {
|
||||
$remaining = max(0, $bantime - (time() - $banAt));
|
||||
$until = $remaining > 0 ? ($banAt + $bantime) : null;
|
||||
$until = $remaining > 0 ? $banAt + $bantime : null;
|
||||
} else {
|
||||
$remaining = -2; // ≈ Approximation (Bantime bekannt, Start unbekannt)
|
||||
}
|
||||
|
||||
[$timeText, $metaText, $boxClass] = $this->present($remaining, $banAt, $until);
|
||||
|
||||
$rows[] = [
|
||||
'ip' => $ip,
|
||||
'bantime' => $bantime,
|
||||
'ip' => $ip,
|
||||
'bantime' => $bantime,
|
||||
'banned_at' => $banAt,
|
||||
'remaining' => $remaining,
|
||||
'until' => $until,
|
||||
'until' => $until,
|
||||
'time_text' => $timeText,
|
||||
'meta_text' => $metaText,
|
||||
'box_class' => $boxClass,
|
||||
|
|
@ -74,13 +58,98 @@ class Fail2BanJailModal extends ModalComponent
|
|||
$this->rows = $rows;
|
||||
}
|
||||
|
||||
/** sudo + fail2ban-client */
|
||||
/** ROBUST: findet Binaries automatisch */
|
||||
private function bin(string $name): string
|
||||
{
|
||||
$p = trim((string)@shell_exec("command -v ".escapeshellarg($name)." 2>/dev/null"));
|
||||
return $p !== '' ? $p : $name;
|
||||
}
|
||||
|
||||
/** letzte "Ban <IP>"-Zeile → Unix-Timestamp (mit Fallbacks) */
|
||||
private function lastBanTimestamp(string $jail, string $ip): ?int
|
||||
{
|
||||
$sudo = $this->bin('sudo');
|
||||
$zgrep = $this->bin('zgrep');
|
||||
$grep = $this->bin('grep');
|
||||
$tail = $this->bin('tail');
|
||||
$journal = $this->bin('journalctl');
|
||||
|
||||
// 1) exakter Treffer: "[jail] Ban IP"
|
||||
$needleExact = sprintf('[%s] Ban %s', $jail, $ip);
|
||||
$qExact = escapeshellarg($needleExact);
|
||||
$cmd1 = "$sudo -n $zgrep -h -F $qExact /var/log/fail2ban.log* 2>/dev/null | $tail -n 1";
|
||||
$line = trim((string)@shell_exec($cmd1));
|
||||
|
||||
// 2) Fallback: nur "Ban IP"
|
||||
if ($line === '') {
|
||||
$qLoose = escapeshellarg("Ban $ip");
|
||||
$cmd2 = "$sudo -n $zgrep -h -F $qLoose /var/log/fail2ban.log* 2>/dev/null | $tail -n 1";
|
||||
$line = trim((string)@shell_exec($cmd2));
|
||||
}
|
||||
|
||||
// 3) Fallback: unkomprimiertes Log
|
||||
if ($line === '') {
|
||||
$cmd3 = "$sudo -n $grep -h -F $qExact /var/log/fail2ban.log 2>/dev/null | $tail -n 1";
|
||||
$line = trim((string)@shell_exec($cmd3));
|
||||
if ($line === '') {
|
||||
$cmd3b = "$sudo -n $grep -h -F ".escapeshellarg("Ban $ip")." /var/log/fail2ban.log 2>/dev/null | $tail -n 1";
|
||||
$line = trim((string)@shell_exec($cmd3b));
|
||||
}
|
||||
}
|
||||
|
||||
// 4) Fallback: journald
|
||||
if ($line === '') {
|
||||
$cmd4 = "$sudo -n $journal -u fail2ban --since '14 days ago' --no-pager | $grep -F $qExact | $tail -n 1";
|
||||
$line = trim((string)@shell_exec($cmd4));
|
||||
if ($line === '') {
|
||||
$cmd4b = "$sudo -n $journal -u fail2ban --since '14 days ago' --no-pager | $grep -F ".escapeshellarg("Ban $ip")." | $tail -n 1";
|
||||
$line = trim((string)@shell_exec($cmd4b));
|
||||
}
|
||||
}
|
||||
|
||||
if ($line === '') return null;
|
||||
|
||||
// "2025-10-25 11:22:05,958 ..." → Millisekunden ignorieren
|
||||
if (preg_match('/(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})/', $line, $m)) {
|
||||
$ts = strtotime($m[1].' '.$m[2]);
|
||||
return $ts ?: null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Darstellung: permanent / Restzeit / abgelaufen / ~approx / unbekannt */
|
||||
private function present(?int $remaining, ?int $banAt, ?int $until): array
|
||||
{
|
||||
$amber = 'border-amber-400/30 bg-amber-500/10';
|
||||
$rose = 'border-rose-400/30 bg-rose-500/10';
|
||||
$muted = 'border-white/10 bg-white/5';
|
||||
|
||||
if ($remaining === -1) {
|
||||
return ['permanent', $banAt ? ('seit '.$this->fmtTs($banAt)) : '—', $rose];
|
||||
}
|
||||
if ($remaining === -2) {
|
||||
return ['~ '.$this->fmtSecs($this->getApproxBantime()), '—', $amber];
|
||||
}
|
||||
if (is_int($remaining)) {
|
||||
if ($remaining > 0) {
|
||||
$meta = [];
|
||||
if ($banAt) $meta[] = 'seit '.$this->fmtTs($banAt);
|
||||
if ($until) $meta[] = 'bis '.$this->fmtTs($until);
|
||||
return [$this->fmtSecs($remaining), $meta ? implode(' • ', $meta) : '—', $amber];
|
||||
}
|
||||
return ['abgelaufen', $banAt ? ('seit '.$this->fmtTs($banAt)) : '—', $muted];
|
||||
}
|
||||
return ['—', '—', $muted];
|
||||
}
|
||||
|
||||
private function getApproxBantime(): int { return 600; }
|
||||
|
||||
private function f2b(string $args): array
|
||||
{
|
||||
$sudo = '/usr/bin/sudo';
|
||||
$f2b = '/usr/bin/fail2ban-client';
|
||||
$out = (string)@shell_exec("timeout 3 $sudo -n $f2b $args 2>&1");
|
||||
$ok = stripos($out, 'Status') !== false
|
||||
$sudo = $this->bin('sudo');
|
||||
$f2b = $this->bin('fail2ban-client');
|
||||
$out = (string)@shell_exec("timeout 3 $sudo -n $f2b $args 2>&1");
|
||||
$ok = stripos($out, 'Status') !== false
|
||||
|| stripos($out, 'Jail list') !== false
|
||||
|| stripos($out, 'pong') !== false;
|
||||
return [$ok, $out];
|
||||
|
|
@ -88,38 +157,9 @@ class Fail2BanJailModal extends ModalComponent
|
|||
|
||||
private function getBantime(string $jail): int
|
||||
{
|
||||
[, $out] = $this->f2b('get ' . escapeshellarg($jail) . ' bantime');
|
||||
[, $out] = $this->f2b('get '.escapeshellarg($jail).' bantime');
|
||||
$val = trim($out);
|
||||
if (preg_match('/-?\d+/', $val, $m)) return (int)$m[0];
|
||||
return 600;
|
||||
}
|
||||
|
||||
/** robust: zgrep + journalctl via sudo */
|
||||
private function lastBanTimestamp(string $jail, string $ip): ?int
|
||||
{
|
||||
$sudo = '/usr/bin/sudo';
|
||||
$zgrep = '/usr/bin/zgrep';
|
||||
$journal = '/usr/bin/journalctl';
|
||||
$tail = '/usr/bin/tail';
|
||||
|
||||
$needle = sprintf('[%s] Ban %s', $jail, $ip);
|
||||
$q = escapeshellarg($needle);
|
||||
|
||||
// Logs inkl. Rotation (gz)
|
||||
$cmd1 = "$sudo -n $zgrep -h $q /var/log/fail2ban.log* 2>/dev/null | $tail -n 1";
|
||||
$line = trim((string)@shell_exec($cmd1));
|
||||
|
||||
if ($line === '') { // Fallback: journald
|
||||
$cmd2 = "$sudo -n $journal -u fail2ban --since '14 days ago' --no-pager -g $q 2>/dev/null | $tail -n 1";
|
||||
$line = trim((string)@shell_exec($cmd2));
|
||||
}
|
||||
if ($line === '') return null;
|
||||
|
||||
if (preg_match('/(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})/', $line, $m)) {
|
||||
$ts = strtotime($m[1] . ' ' . $m[2]);
|
||||
return $ts ?: null;
|
||||
}
|
||||
return null;
|
||||
return preg_match('/-?\d+/', $val, $m) ? (int)$m[0] : 600;
|
||||
}
|
||||
|
||||
private function firstMatch(string $pattern, string $haystack): ?string
|
||||
|
|
@ -127,43 +167,581 @@ class Fail2BanJailModal extends ModalComponent
|
|||
return preg_match($pattern, $haystack, $m) ? trim($m[1]) : null;
|
||||
}
|
||||
|
||||
private function present(?int $remaining, ?int $banAt, ?int $until): array
|
||||
{
|
||||
$amber = 'border-amber-400/30 bg-amber-500/10';
|
||||
$rose = 'border-rose-400/30 bg-rose-500/10';
|
||||
$muted = 'border-white/10 bg-white/5';
|
||||
|
||||
if ($remaining === -1) {
|
||||
return ['permanent', $banAt ? ('seit ' . $this->fmtTs($banAt)) : '—', $rose];
|
||||
}
|
||||
if (is_int($remaining)) {
|
||||
if ($remaining > 0) {
|
||||
$meta = [];
|
||||
if ($banAt) $meta[] = 'seit ' . $this->fmtTs($banAt);
|
||||
if ($until) $meta[] = 'bis ' . $this->fmtTs($until);
|
||||
return [$this->fmtSecs($remaining), $meta ? implode(' • ', $meta) : '—', $amber];
|
||||
}
|
||||
return ['abgelaufen', $banAt ? ('seit ' . $this->fmtTs($banAt)) : '—', $muted];
|
||||
}
|
||||
return ['—', '—', $muted];
|
||||
}
|
||||
|
||||
private function fmtSecs(int $s): string
|
||||
{
|
||||
$h = intdiv($s, 3600);
|
||||
$m = intdiv($s % 3600, 60);
|
||||
$r = $s % 60;
|
||||
$h = intdiv($s, 3600); $m = intdiv($s % 3600, 60); $r = $s % 60;
|
||||
if ($h > 0) return sprintf('%dh %02dm %02ds', $h, $m, $r);
|
||||
if ($m > 0) return sprintf('%02dm %02ds', $m, $r);
|
||||
return sprintf('%ds', $r);
|
||||
}
|
||||
|
||||
private function fmtTs(int $ts): string
|
||||
{
|
||||
return date('d.m. H:i', $ts);
|
||||
}
|
||||
private function fmtTs(int $ts): string { return date('d.m. H:i', $ts); }
|
||||
}
|
||||
|
||||
//namespace App\Livewire\Ui\Security\Modal;
|
||||
//
|
||||
//use LivewireUI\Modal\ModalComponent;
|
||||
//
|
||||
//class Fail2BanJailModal extends ModalComponent
|
||||
//{
|
||||
// public string $jail = '';
|
||||
// public array $rows = [];
|
||||
//
|
||||
// public static function modalMaxWidth(): string
|
||||
// {
|
||||
// return '4xl';
|
||||
// }
|
||||
//
|
||||
// public function mount(string $jail): void
|
||||
// {
|
||||
// $this->jail = $jail;
|
||||
// $this->load();
|
||||
// }
|
||||
//
|
||||
// public function refresh(): void
|
||||
// {
|
||||
// $this->load(true);
|
||||
// }
|
||||
//
|
||||
// public function render()
|
||||
// {
|
||||
// return view('livewire.ui.security.modal.fail2-ban-jail-modal');
|
||||
// }
|
||||
//
|
||||
// /* ---------------- intern ---------------- */
|
||||
//
|
||||
// protected function load(bool $force = false): void
|
||||
// {
|
||||
// $jail = $this->jail;
|
||||
//
|
||||
// // Aktuell gebannte IPs + Bantime
|
||||
// [, $s] = $this->f2b('status ' . escapeshellarg($jail));
|
||||
// $ipList = $this->firstMatch('/Banned IP list:\s*(.+)$/mi', $s) ?: '';
|
||||
// $ips = $ipList !== '' ? array_values(array_filter(array_map('trim', preg_split('/\s+/', $ipList)))) : [];
|
||||
// $bantime = $this->getBantime($jail); // Sek., -1 = permanent
|
||||
//
|
||||
// $rows = [];
|
||||
// foreach ($ips as $ip) {
|
||||
// $banAt = $this->lastBanTimestamp($jail, $ip); // Unix-TS oder null
|
||||
//
|
||||
// $remaining = null;
|
||||
// $until = null;
|
||||
// if ($bantime === -1) {
|
||||
// $remaining = -1;
|
||||
// } elseif ($banAt !== null) {
|
||||
// $remaining = max(0, $bantime - (time() - $banAt));
|
||||
// $until = $remaining > 0 ? ($banAt + $bantime) : null;
|
||||
// } else {
|
||||
// // kein exakter Timestamp auffindbar → als Approximation ausweisen
|
||||
// $remaining = -2; // Kennzeichen für "~ Bantime"
|
||||
// }
|
||||
//
|
||||
// [$timeText, $metaText, $boxClass] = $this->present($remaining, $banAt, $until, $bantime);
|
||||
//
|
||||
// $rows[] = [
|
||||
// 'ip' => $ip,
|
||||
// 'bantime' => $bantime,
|
||||
// 'banned_at' => $banAt,
|
||||
// 'remaining' => $remaining, // -1=permanent, -2≈approx, 0..Sek, null=unbekannt
|
||||
// 'until' => $until,
|
||||
// 'time_text' => $timeText,
|
||||
// 'meta_text' => $metaText,
|
||||
// 'box_class' => $boxClass,
|
||||
// ];
|
||||
// }
|
||||
//
|
||||
// $this->rows = $rows;
|
||||
// }
|
||||
//
|
||||
// /** robust: findet Pfade automatisch, mehrere Fallbacks */
|
||||
// private function lastBanTimestamp(string $jail, string $ip): ?int
|
||||
// {
|
||||
// $sudo = $this->bin('sudo');
|
||||
// $zgrep = $this->bin('zgrep');
|
||||
// $grep = $this->bin('grep');
|
||||
// $tail = $this->bin('tail');
|
||||
// $journal = $this->bin('journalctl');
|
||||
//
|
||||
// // 1) exakte Suche: "[jail] Ban IP"
|
||||
// $needleExact = sprintf('[%s] Ban %s', $jail, $ip);
|
||||
// $qExact = escapeshellarg($needleExact);
|
||||
// $cmd1 = "$sudo -n $zgrep -h -F $qExact /var/log/fail2ban.log* 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string)@shell_exec($cmd1));
|
||||
//
|
||||
// // 2) locker: nur "Ban IP" (falls der Jail-Tag im Log anders ist)
|
||||
// if ($line === '') {
|
||||
// $qLoose = escapeshellarg("Ban $ip");
|
||||
// $cmd2 = "$sudo -n $zgrep -h -F $qLoose /var/log/fail2ban.log* 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string)@shell_exec($cmd2));
|
||||
// }
|
||||
//
|
||||
// // 3) unkomprimiertes Log als Fallback
|
||||
// if ($line === '') {
|
||||
// $cmd3 = "$sudo -n $grep -h -F $qExact /var/log/fail2ban.log 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string)@shell_exec($cmd3));
|
||||
// if ($line === '') {
|
||||
// $cmd3b = "$sudo -n $grep -h -F " . escapeshellarg("Ban $ip") . " /var/log/fail2ban.log 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string)@shell_exec($cmd3b));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 4) journald
|
||||
// if ($line === '') {
|
||||
// $cmd4 = "$sudo -n $journal -u fail2ban --since '14 days ago' --no-pager | $grep -F $qExact | $tail -n 1";
|
||||
// $line = trim((string)@shell_exec($cmd4));
|
||||
// if ($line === '') {
|
||||
// $cmd4b = "$sudo -n $journal -u fail2ban --since '14 days ago' --no-pager | $grep -F " . escapeshellarg("Ban $ip") . " | $tail -n 1";
|
||||
// $line = trim((string)@shell_exec($cmd4b));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ($line === '') return null;
|
||||
//
|
||||
// // 2025-10-30 22:34:59,491 ... -> Datum/Zeit extrahieren
|
||||
// if (preg_match('/(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})/', $line, $m)) {
|
||||
// $ts = strtotime($m[1] . ' ' . $m[2]);
|
||||
// return $ts ?: null;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// /** Anzeige-Logik */
|
||||
// private function present(?int $remaining, ?int $banAt, ?int $until, int $bantime): array
|
||||
// {
|
||||
// $amber = 'border-amber-400/30 bg-amber-500/10';
|
||||
// $rose = 'border-rose-400/30 bg-rose-500/10';
|
||||
// $muted = 'border-white/10 bg-white/5';
|
||||
//
|
||||
// if ($remaining === -1) {
|
||||
// return ['permanent', $banAt ? ('seit ' . $this->fmtTs($banAt)) : '—', $rose];
|
||||
// }
|
||||
// if ($remaining === -2) {
|
||||
// // nur ungefähre Bantime verfügbar
|
||||
// return ['~ ' . $this->fmtSecs($bantime), '—', $amber];
|
||||
// }
|
||||
// if (is_int($remaining)) {
|
||||
// if ($remaining > 0) {
|
||||
// $meta = [];
|
||||
// if ($banAt) $meta[] = 'seit ' . $this->fmtTs($banAt);
|
||||
// if ($until) $meta[] = 'bis ' . $this->fmtTs($until);
|
||||
// return [$this->fmtSecs($remaining), $meta ? implode(' • ', $meta) : '—', $amber];
|
||||
// }
|
||||
// return ['abgelaufen', $banAt ? ('seit ' . $this->fmtTs($banAt)) : '—', $muted];
|
||||
// }
|
||||
// return ['—', '—', $muted];
|
||||
// }
|
||||
//
|
||||
// /** sudo + fail2ban-client */
|
||||
// private function f2b(string $args): array
|
||||
// {
|
||||
// $sudo = $this->bin('sudo');
|
||||
// $f2b = $this->bin('fail2ban-client');
|
||||
// $out = (string)@shell_exec("timeout 3 $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;
|
||||
// }
|
||||
//
|
||||
// private function firstMatch(string $pattern, string $haystack): ?string
|
||||
// {
|
||||
// return preg_match($pattern, $haystack, $m) ? trim($m[1]) : null;
|
||||
// }
|
||||
//
|
||||
// /** findet den Pfad zu einem Binary robust */
|
||||
// private function bin(string $name): string
|
||||
// {
|
||||
// $p = trim((string)@shell_exec('command -v ' . escapeshellarg($name) . ' 2>/dev/null'));
|
||||
// return $p !== '' ? $p : $name;
|
||||
// }
|
||||
//
|
||||
// private function fmtSecs(int $s): string
|
||||
// {
|
||||
// $h = intdiv($s, 3600);
|
||||
// $m = intdiv($s % 3600, 60);
|
||||
// $r = $s % 60;
|
||||
// if ($h > 0) return sprintf('%dh %02dm %02ds', $h, $m, $r);
|
||||
// if ($m > 0) return sprintf('%02dm %02ds', $m, $r);
|
||||
// return sprintf('%ds', $r);
|
||||
// }
|
||||
//
|
||||
// private function fmtTs(int $ts): string
|
||||
// {
|
||||
// return date('d.m. H:i', $ts);
|
||||
// }
|
||||
//}
|
||||
|
||||
//namespace App\Livewire\Ui\Security\Modal;
|
||||
//
|
||||
//use LivewireUI\Modal\ModalComponent;
|
||||
//
|
||||
//class Fail2BanJailModal extends ModalComponent
|
||||
//{
|
||||
// public string $jail = '';
|
||||
// public array $rows = [];
|
||||
//
|
||||
// public static function modalMaxWidth(): string
|
||||
// {
|
||||
// return '4xl';
|
||||
// }
|
||||
//
|
||||
// public function mount(string $jail): void
|
||||
// {
|
||||
// $this->jail = $jail;
|
||||
// $this->load();
|
||||
// }
|
||||
//
|
||||
// public function render()
|
||||
// {
|
||||
// return view('livewire.ui.security.modal.fail2-ban-jail-modal');
|
||||
// }
|
||||
//
|
||||
// public function refresh(): void
|
||||
// {
|
||||
// $this->load(true);
|
||||
// }
|
||||
//
|
||||
// /* ---------------- intern ---------------- */
|
||||
//
|
||||
// protected function load(bool $force = false): void
|
||||
// {
|
||||
// $jail = $this->jail;
|
||||
//
|
||||
// [, $s] = $this->f2b('status ' . escapeshellarg($jail));
|
||||
// $ipLine = $this->firstMatch('/Banned IP list:\s*(.+)$/mi', $s) ?: '';
|
||||
// $ips = $ipLine !== '' ? array_values(array_filter(array_map('trim', preg_split('/\s+/', $ipLine)))) : [];
|
||||
//
|
||||
// $bantime = $this->getBantime($jail);
|
||||
//
|
||||
// $rows = [];
|
||||
// foreach ($ips as $ip) {
|
||||
// $banAt = $this->lastBanTimestamp($jail, $ip); // null wenn nicht gefunden
|
||||
//
|
||||
// $remaining = null;
|
||||
// $until = null;
|
||||
// if ($bantime === -1) {
|
||||
// $remaining = -1;
|
||||
// } elseif ($banAt !== null) {
|
||||
// $remaining = max(0, $bantime - (time() - $banAt));
|
||||
// $until = $remaining > 0 ? ($banAt + $bantime) : null;
|
||||
// }
|
||||
//
|
||||
// [$timeText, $metaText, $boxClass] = $this->present($remaining, $banAt, $until);
|
||||
//
|
||||
// $rows[] = [
|
||||
// 'ip' => $ip,
|
||||
// 'bantime' => $bantime,
|
||||
// 'banned_at' => $banAt,
|
||||
// 'remaining' => $remaining,
|
||||
// 'until' => $until,
|
||||
// 'time_text' => $timeText,
|
||||
// 'meta_text' => $metaText,
|
||||
// 'box_class' => $boxClass,
|
||||
// ];
|
||||
// }
|
||||
// $this->rows = $rows;
|
||||
// }
|
||||
//
|
||||
// /** ---- helpers ---- */
|
||||
//
|
||||
// private function f2b(string $args): array
|
||||
// {
|
||||
// $sudo = $this->bin('sudo');
|
||||
// $f2b = $this->bin('fail2ban-client');
|
||||
// $out = (string)@shell_exec("timeout 3 $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');
|
||||
// if (preg_match('/-?\d+/', trim($out), $m)) return (int)$m[0];
|
||||
// return 600;
|
||||
// }
|
||||
//
|
||||
// /** findet die letzte "Ban <IP>"-Zeile in log / rotierte .gz / journald */
|
||||
// private function lastBanTimestamp(string $jail, string $ip): ?int
|
||||
// {
|
||||
// $sudo = $this->bin('sudo');
|
||||
// $zgrep = $this->bin('zgrep'); // findet /bin/zgrep ODER /usr/bin/zgrep
|
||||
// $grep = $this->bin('grep');
|
||||
// $tail = $this->bin('tail');
|
||||
// $journal = $this->bin('journalctl');
|
||||
//
|
||||
// // 1) exakter Treffer: "[jail] Ban IP"
|
||||
// $needleExact = sprintf('[%s] Ban %s', $jail, $ip);
|
||||
// $qExact = escapeshellarg($needleExact);
|
||||
//
|
||||
// $cmd1 = "$sudo -n $zgrep -h -F $qExact /var/log/fail2ban.log* 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string) @shell_exec($cmd1));
|
||||
//
|
||||
// // 2) Fallback: nur "Ban IP" (falls Jail-Name im Log abweicht)
|
||||
// if ($line === '') {
|
||||
// $needleLoose = sprintf('Ban %s', $ip);
|
||||
// $qLoose = escapeshellarg($needleLoose);
|
||||
// $cmd2 = "$sudo -n $zgrep -h -F $qLoose /var/log/fail2ban.log* 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string) @shell_exec($cmd2));
|
||||
// }
|
||||
//
|
||||
// // 3) Fallback: unkomprimiertes Log mit grep
|
||||
// if ($line === '') {
|
||||
// $cmd3 = "$sudo -n $grep -h -F $qExact /var/log/fail2ban.log 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string) @shell_exec($cmd3));
|
||||
// if ($line === '') {
|
||||
// $cmd3b = "$sudo -n $grep -h -F ".escapeshellarg("Ban $ip")." /var/log/fail2ban.log 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string) @shell_exec($cmd3b));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 4) Fallback: journald
|
||||
// if ($line === '') {
|
||||
// $cmd4 = "$sudo -n $journal -u fail2ban --since '14 days ago' --no-pager | $grep -F $qExact | $tail -n 1";
|
||||
// $line = trim((string) @shell_exec($cmd4));
|
||||
// if ($line === '') {
|
||||
// $cmd4b = "$sudo -n $journal -u fail2ban --since '14 days ago' --no-pager | $grep -F ".escapeshellarg("Ban $ip")." | $tail -n 1";
|
||||
// $line = trim((string) @shell_exec($cmd4b));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ($line === '') return null;
|
||||
//
|
||||
// // Zeitstempel extrahieren (YYYY-MM-DD HH:MM:SS[,ms] egal)
|
||||
// if (preg_match('/(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})/', $line, $m)) {
|
||||
// $ts = strtotime($m[1].' '.$m[2]);
|
||||
// return $ts ?: null;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// private function firstMatch(string $pattern, string $haystack): ?string
|
||||
// {
|
||||
// return preg_match($pattern, $haystack, $m) ? trim($m[1]) : null;
|
||||
// }
|
||||
//
|
||||
// private function present(?int $remaining, ?int $banAt, ?int $until): array
|
||||
// {
|
||||
// $amber = 'border-amber-400/30 bg-amber-500/10';
|
||||
// $rose = 'border-rose-400/30 bg-rose-500/10';
|
||||
// $muted = 'border-white/10 bg-white/5';
|
||||
//
|
||||
// if ($remaining === -1) {
|
||||
// return ['permanent', $banAt ? ('seit '.$this->fmtTs($banAt)) : '—', $rose];
|
||||
// }
|
||||
// if ($remaining === -2) {
|
||||
// // zeigt ungefähre Bantime, falls Timestamp nicht gefunden wurde
|
||||
// return ['~ '.$this->fmtSecs($this->getApproxBantime()), '—', $amber];
|
||||
// }
|
||||
// if (is_int($remaining)) {
|
||||
// if ($remaining > 0) {
|
||||
// $meta = [];
|
||||
// if ($banAt) $meta[] = 'seit '.$this->fmtTs($banAt);
|
||||
// if ($until) $meta[] = 'bis '.$this->fmtTs($until);
|
||||
// return [$this->fmtSecs($remaining), $meta ? implode(' • ', $meta) : '—', $amber];
|
||||
// }
|
||||
// return ['abgelaufen', $banAt ? ('seit '.$this->fmtTs($banAt)) : '—', $muted];
|
||||
// }
|
||||
// return ['—', '—', $muted];
|
||||
// }
|
||||
//
|
||||
// private function getApproxBantime(): int { return 600; }
|
||||
//
|
||||
// private function fmtSecs(int $s): string
|
||||
// {
|
||||
// $h = intdiv($s, 3600);
|
||||
// $m = intdiv($s % 3600, 60);
|
||||
// $r = $s % 60;
|
||||
// if ($h > 0) return sprintf('%dh %02dm %02ds', $h, $m, $r);
|
||||
// if ($m > 0) return sprintf('%02dm %02ds', $m, $r);
|
||||
// return sprintf('%ds', $r);
|
||||
// }
|
||||
//
|
||||
// private function fmtTs(int $ts): string
|
||||
// {
|
||||
// return date('d.m. H:i', $ts);
|
||||
// }
|
||||
//
|
||||
// private function bin(string $name): string
|
||||
// {
|
||||
// $p = trim((string)@shell_exec("command -v ".escapeshellarg($name)." 2>/dev/null"));
|
||||
// return $p !== '' ? $p : $name;
|
||||
// }
|
||||
//}
|
||||
|
||||
//namespace App\Livewire\Ui\Security\Modal;
|
||||
//
|
||||
//use LivewireUI\Modal\ModalComponent;
|
||||
//
|
||||
//class Fail2BanJailModal extends ModalComponent
|
||||
//{
|
||||
// public string $jail = '';
|
||||
// public array $rows = []; // [{ip,bantime,banned_at,remaining,until,time_text,meta_text,box_class}]
|
||||
//
|
||||
// public static function modalMaxWidth(): string
|
||||
// {
|
||||
// return '4xl';
|
||||
// }
|
||||
//
|
||||
// public function mount(string $jail): void
|
||||
// {
|
||||
// $this->jail = $jail;
|
||||
// $this->load();
|
||||
// }
|
||||
//
|
||||
// public function render()
|
||||
// {
|
||||
// return view('livewire.ui.security.modal.fail2-ban-jail-modal');
|
||||
// }
|
||||
//
|
||||
// public function refresh(): void
|
||||
// {
|
||||
// $this->load(true);
|
||||
// }
|
||||
//
|
||||
// /* ---------------- intern ---------------- */
|
||||
//
|
||||
// protected function load(bool $force = false): void
|
||||
// {
|
||||
// $jail = $this->jail;
|
||||
//
|
||||
// // Aktuell gebannte IPs
|
||||
// [, $s] = $this->f2b('status ' . escapeshellarg($jail));
|
||||
// $ipList = $this->firstMatch('/Banned IP list:\s*(.+)$/mi', $s) ?: '';
|
||||
// $ips = $ipList !== '' ? array_values(array_filter(array_map('trim', preg_split('/\s+/', $ipList)))) : [];
|
||||
//
|
||||
// $bantime = $this->getBantime($jail);
|
||||
//
|
||||
// $rows = [];
|
||||
// foreach ($ips as $ip) {
|
||||
// $banAt = $this->lastBanTimestamp($jail, $ip); // Unix-Timestamp oder null
|
||||
//
|
||||
// $remaining = null;
|
||||
// $until = null;
|
||||
//
|
||||
// if ($bantime === -1) {
|
||||
// $remaining = -1;
|
||||
// } elseif ($banAt !== null) {
|
||||
// $remaining = max(0, $bantime - (time() - $banAt));
|
||||
// $until = $remaining > 0 ? ($banAt + $bantime) : null;
|
||||
// }
|
||||
//
|
||||
// [$timeText, $metaText, $boxClass] = $this->present($remaining, $banAt, $until);
|
||||
//
|
||||
// $rows[] = [
|
||||
// 'ip' => $ip,
|
||||
// 'bantime' => $bantime,
|
||||
// 'banned_at' => $banAt,
|
||||
// 'remaining' => $remaining,
|
||||
// 'until' => $until,
|
||||
// 'time_text' => $timeText,
|
||||
// 'meta_text' => $metaText,
|
||||
// 'box_class' => $boxClass,
|
||||
// ];
|
||||
// }
|
||||
//
|
||||
// $this->rows = $rows;
|
||||
// }
|
||||
//
|
||||
// /** sudo + fail2ban-client */
|
||||
// private function f2b(string $args): array
|
||||
// {
|
||||
// $sudo = '/usr/bin/sudo';
|
||||
// $f2b = '/usr/bin/fail2ban-client';
|
||||
// $out = (string)@shell_exec("timeout 3 $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;
|
||||
// }
|
||||
//
|
||||
// /** robust: zgrep + journalctl via sudo */
|
||||
// private function lastBanTimestamp(string $jail, string $ip): ?int
|
||||
// {
|
||||
// $sudo = '/usr/bin/sudo';
|
||||
// $zgrep = '/usr/bin/zgrep';
|
||||
// $journal = '/usr/bin/journalctl';
|
||||
// $tail = '/usr/bin/tail';
|
||||
//
|
||||
// $needle = sprintf('[%s] Ban %s', $jail, $ip);
|
||||
// $q = escapeshellarg($needle);
|
||||
//
|
||||
// // Logs inkl. Rotation (gz)
|
||||
// $cmd1 = "$sudo -n $zgrep -h $q /var/log/fail2ban.log* 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string)@shell_exec($cmd1));
|
||||
//
|
||||
// if ($line === '') { // Fallback: journald
|
||||
// $cmd2 = "$sudo -n $journal -u fail2ban --since '14 days ago' --no-pager -g $q 2>/dev/null | $tail -n 1";
|
||||
// $line = trim((string)@shell_exec($cmd2));
|
||||
// }
|
||||
// if ($line === '') return null;
|
||||
//
|
||||
// if (preg_match('/(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}:\d{2})/', $line, $m)) {
|
||||
// $ts = strtotime($m[1] . ' ' . $m[2]);
|
||||
// return $ts ?: null;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// private function firstMatch(string $pattern, string $haystack): ?string
|
||||
// {
|
||||
// return preg_match($pattern, $haystack, $m) ? trim($m[1]) : null;
|
||||
// }
|
||||
//
|
||||
// private function present(?int $remaining, ?int $banAt, ?int $until): array
|
||||
// {
|
||||
// $amber = 'border-amber-400/30 bg-amber-500/10';
|
||||
// $rose = 'border-rose-400/30 bg-rose-500/10';
|
||||
// $muted = 'border-white/10 bg-white/5';
|
||||
//
|
||||
// if ($remaining === -1) {
|
||||
// return ['permanent', $banAt ? ('seit ' . $this->fmtTs($banAt)) : '—', $rose];
|
||||
// }
|
||||
// if (is_int($remaining)) {
|
||||
// if ($remaining > 0) {
|
||||
// $meta = [];
|
||||
// if ($banAt) $meta[] = 'seit ' . $this->fmtTs($banAt);
|
||||
// if ($until) $meta[] = 'bis ' . $this->fmtTs($until);
|
||||
// return [$this->fmtSecs($remaining), $meta ? implode(' • ', $meta) : '—', $amber];
|
||||
// }
|
||||
// return ['abgelaufen', $banAt ? ('seit ' . $this->fmtTs($banAt)) : '—', $muted];
|
||||
// }
|
||||
// return ['—', '—', $muted];
|
||||
// }
|
||||
//
|
||||
// private function fmtSecs(int $s): string
|
||||
// {
|
||||
// $h = intdiv($s, 3600);
|
||||
// $m = intdiv($s % 3600, 60);
|
||||
// $r = $s % 60;
|
||||
// if ($h > 0) return sprintf('%dh %02dm %02ds', $h, $m, $r);
|
||||
// if ($m > 0) return sprintf('%02dm %02ds', $m, $r);
|
||||
// return sprintf('%ds', $r);
|
||||
// }
|
||||
//
|
||||
// private function fmtTs(int $ts): string
|
||||
// {
|
||||
// return date('d.m. H:i', $ts);
|
||||
// }
|
||||
//}
|
||||
|
||||
//
|
||||
//namespace App\Livewire\Ui\Security\Modal;
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in New Issue