`), notifies, asks the page to * reload the snapshot, and — on success — closes. * * Action keys: ssh_root, ssh_password, fail2ban, unattended, firewall. */ class HardeningAction extends ModalComponent { public int $serverId; public string $action; /** Optional TCP port (reserved for future allow/deny firewall actions). */ public ?int $port = null; public string $heading = ''; public string $description = ''; public string $preview = ''; /** Result of the apply run, set after the operator confirms. */ public bool $done = false; public bool $ok = false; public string $output = ''; /** Set when the action key is unknown / server vanished — blocks apply. */ public ?string $error = null; public function mount(int $serverId, string $action, ?int $port = null): void { $this->serverId = $serverId; $this->action = $action; $this->port = $port; $server = Server::find($serverId); if (! $server) { $this->error = 'Server nicht gefunden.'; return; } try { if ($action === 'firewall') { $this->heading = 'Firewall (UFW) aktivieren'; $this->description = 'Öffnet zuerst den SSH-Port und 80/443, dann wird UFW aktiviert — die laufende SSH-Sitzung bleibt erreichbar.'; $this->preview = app(FirewallService::class)->enablePreview($server); } else { $hardening = app(HardeningService::class); $this->heading = $hardening->title($action); $this->description = $hardening->description($action); $this->preview = $hardening->preview($server, $action); } } catch (Throwable $e) { $this->error = $e->getMessage(); } } public static function modalMaxWidth(): string { return 'lg'; } public function apply(): void { if ($this->error !== null || $this->done) { return; } $server = Server::find($this->serverId); if (! $server) { $this->error = 'Server nicht gefunden.'; return; } try { $result = $this->action === 'firewall' ? app(FirewallService::class)->enable($server) : app(HardeningService::class)->apply($server, $this->action); } catch (Throwable $e) { $this->done = true; $this->ok = false; $this->output = $e->getMessage(); return; } $this->done = true; $this->ok = $result['ok']; $this->output = $result['output'] !== '' ? $result['output'] : ($result['ok'] ? 'Erfolgreich angewendet.' : 'Fehlgeschlagen.'); AuditEvent::create([ 'user_id' => Auth::id(), 'server_id' => $server->id, 'actor' => Auth::user()?->name ?? 'system', 'action' => 'harden.'.$this->action, 'target' => $server->name.' · '.$this->heading.($this->ok ? '' : ' (fehlgeschlagen)'), 'ip' => request()->ip(), ]); if ($this->ok) { $this->dispatch('hardeningApplied'); $this->dispatch('notify', message: $this->heading.' angewendet.'); } else { $this->dispatch('notify', message: $this->heading.' fehlgeschlagen.'); } } public function render() { return view('livewire.modals.hardening-action'); } }