clusev/app/Livewire/Modals/Fail2banBan.php

89 lines
2.2 KiB
PHP

<?php
namespace App\Livewire\Modals;
use App\Models\AuditEvent;
use App\Models\Server;
use App\Services\Fail2banService;
use Illuminate\Support\Facades\Auth;
use LivewireUI\Modal\ModalComponent;
use Throwable;
/**
* Manually ban an IP in a fail2ban jail (R5: a deliberate confirm dialog, not a
* native popup). Fail2banService refuses to ban loopback or Clusev's own connection,
* so this can never lock the operator out.
*/
class Fail2banBan extends ModalComponent
{
public int $serverId;
/** @var array<int, string> */
public array $jails = [];
public string $jail = '';
public string $ip = '';
public ?string $error = null;
/**
* @param array<int, string> $jails
*/
public function mount(int $serverId, array $jails = []): void
{
$this->serverId = $serverId;
$this->jails = array_values($jails);
$this->jail = $this->jails[0] ?? 'sshd';
}
public static function modalMaxWidth(): string
{
return 'lg';
}
public function save(Fail2banService $fail2ban): void
{
$this->error = null;
$server = Server::find($this->serverId);
if (! $server) {
$this->error = 'Server nicht gefunden.';
return;
}
try {
$res = $fail2ban->ban($server, $this->jail, trim($this->ip));
} catch (Throwable $e) {
$this->error = $e->getMessage();
return;
}
if (! $res['ok']) {
$this->error = $res['output'] !== '' ? $res['output'] : 'Sperren fehlgeschlagen.';
return;
}
AuditEvent::create([
'user_id' => Auth::id(),
'server_id' => $server->id,
'actor' => Auth::user()?->name ?? 'system',
'action' => 'fail2ban.ban',
'target' => trim($this->ip).' · '.$this->jail.' · '.$server->name,
'ip' => request()->ip(),
]);
$this->dispatch('fail2banChanged');
$this->dispatch('notify', message: 'IP '.trim($this->ip).' gesperrt.');
$this->closeModal();
}
public function render()
{
return view('livewire.modals.fail2ban-ban');
}
}