clusev/app/Models/HostCredential.php

57 lines
2.0 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
/**
* The SSH login for the "Clusev host" terminal (a singleton — one host). Stored encrypted; only
* ever read over the internal network by the terminal resolve endpoint, never sent to the browser.
* When no row exists the host terminal is "not configured" and the tile opens the setup form.
*/
class HostCredential extends Model
{
/** Explicit allowlist (never $guarded=[]) so request input can't set unintended columns. */
protected $fillable = ['host', 'port', 'username', 'auth_type', 'secret', 'passphrase'];
/** Never serialize the credential fields (mirrors SshCredential). */
protected $hidden = ['secret', 'passphrase'];
protected $casts = [
'port' => 'integer',
'secret' => 'encrypted',
'passphrase' => 'encrypted',
];
/** The single configured host login, or null when the operator hasn't set one up yet. */
public static function current(): ?self
{
return static::query()->orderBy('id')->first();
}
/**
* A TRANSIENT Server (never persisted) that points SSH tooling — FleetService, DockerService —
* at the Clusev host itself, reusing the encrypted host login. The SshCredential is likewise
* transient; its encrypted 'secret' cast round-trips the plaintext back for CredentialVault.
* verifyHostKey skips pinning a non-persisted server, so this creates no fleet row.
*/
public function toServer(): Server
{
$cred = new SshCredential(['username' => $this->username, 'auth_type' => $this->auth_type]);
$cred->secret = $this->secret;
if ($this->passphrase) {
$cred->passphrase = $this->passphrase;
}
$server = new Server([
'name' => 'Clusev Host',
'ip' => $this->host,
'ssh_port' => $this->port,
'status' => 'online',
]);
$server->setRelation('credential', $cred);
return $server;
}
}