user()?->can('manage-fleet'), 403); $this->serverId = $serverId; } public static function modalMaxWidth(): string { return 'lg'; } /** Generate a fresh ed25519 keypair: the public key is installed on save, * the private key is shown once for the operator to store. */ public function generate(): void { $this->error = null; $key = EC::createKey('ed25519'); // The comment is what identifies the key in the server's list — use the operator's name. $this->publicKey = $key->getPublicKey()->toString('OpenSSH', ['comment' => $this->keyComment() ?: 'clusev-key']); $this->generatedPrivate = (string) $key->toString('OpenSSH'); } /** Sanitised key label, safe as an authorized_keys comment (single line, ≤64 chars), or '' if none. */ private function keyComment(): string { $name = preg_replace('/[\x00-\x1F\x7F]+/', ' ', $this->keyName) ?? ''; $name = trim(preg_replace('/\s+/', ' ', $name) ?? ''); return mb_substr($name, 0, 64); } /** Set the OpenSSH comment of a public-key line to $comment (only when a name was given). */ private function withComment(string $pub, string $comment): string { if ($comment === '') { return $pub; } $parts = preg_split('/\s+/', trim($pub), 3); if (count($parts) < 2) { return $pub; // not a recognisable key line — let the SSH layer reject it } return $parts[0].' '.$parts[1].' '.$comment; } public function save(FleetService $fleet): void { // Re-gate on save: refuse a demoted user / hand-crafted /livewire/update after mount. abort_unless(auth()->user()?->can('manage-fleet'), 403); $this->error = null; $server = Server::find($this->serverId); if (! $server) { $this->error = __('common.server_not_found'); return; } $name = $this->keyComment(); try { // Force the key's comment to the operator's name so it is identifiable in the list. $fleet->addAuthorizedKey($server, $this->withComment($this->publicKey, $name)); } catch (Throwable $e) { $this->error = $e->getMessage(); return; } AuditEvent::create([ 'user_id' => Auth::id(), 'server_id' => $server->id, 'actor' => Auth::user()?->name ?? 'system', 'action' => 'ssh_key.add', 'target' => $name !== '' ? $server->name.' · '.$name : $server->name, 'ip' => request()->ip(), ]); $this->dispatch('keyChanged'); $this->dispatch('notify', message: __('modals.add_ssh_key.notify_added')); $this->closeModal(); } public function render() { return view('livewire.modals.add-ssh-key'); } }