user()?->can('manage-network'), 403); $this->serverId = $serverId; $this->action = $action; $this->enable = $enable; $server = Server::find($serverId); if (! $server) { $this->error = __('common.server_not_found'); return; } try { $hardening = app(HardeningService::class); $this->heading = $hardening->title($action, $enable); $this->description = $hardening->description($action, $enable); } catch (Throwable $e) { $this->error = $e->getMessage(); } } public static function modalMaxWidth(): string { return 'lg'; } public function apply(): void { abort_unless(auth()->user()?->can('manage-network'), 403); if ($this->error !== null || $this->done) { return; } $server = Server::find($this->serverId); if (! $server) { $this->error = __('common.server_not_found'); return; } try { $result = app(HardeningService::class)->apply($server, $this->action, $this->enable); } catch (Throwable $e) { $this->done = true; $this->ok = false; $this->output = $e->getMessage(); return; } $this->done = true; $this->ok = $result['ok']; // Clean result only โ€” no raw command output on success; a bounded reason on failure. 400, // not 200: our own guard messages (e.g. backend.ssh_root_self_lockout, 202 chars) must // never be cut mid-sentence โ€” the box wraps with break-words, so length is fine. $this->output = $this->ok ? '' : Str::limit(trim($result['output']) ?: __('modals.hardening_action.error_unknown'), 400); AuditEvent::create([ 'user_id' => Auth::id(), 'server_id' => $server->id, 'actor' => Auth::user()?->name ?? 'system', 'action' => 'harden.'.$this->action.($this->enable ? '.on' : '.off'), 'target' => $server->name.' ยท '.$this->heading.($this->ok ? '' : ' '.__('modals.hardening_action.audit_failed_suffix')), 'ip' => request()->ip(), ]); if ($this->ok) { $this->dispatch('hardeningApplied'); $this->dispatch('notify', message: __('modals.hardening_action.notify_applied', ['action' => $this->heading])); } else { $this->dispatch('notify', message: __('modals.hardening_action.notify_failed', ['action' => $this->heading])); } } public function render() { return view('livewire.modals.hardening-action'); } }