mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-14 08:42:38 -04:00
Import: - Check every uuid in a bundle against a strict id format before any write, and quote the SSH mux socket and key paths in local shell commands. A bundle uuid could run commands in the Coolify container. - Validate bundle fqdns, git source URLs, paths, networks, cron expressions, and database ports; cap the number of items. - Do not confirm that another team has a uuid. - Refuse a project icon path with a uuid that is not a plain id. Claim, finish, and migrate: - Pass checklist step keys to wire:click with Js::from (stored XSS). - Link only to https target server URLs. - Validate target_instance_url in /transfer/complete; never prefill an unverified URL for a transfer back; scope the transfer-back token to write+deploy for 1 hour. - Release on an owner marker only when it is newer than the own claim. - Do not touch apps that only use the server as an additional destination when an archive is released or deleted. - Give Sentinel a new token on claim. - Add a checklist step to remove the previous instance's SSH key. - Block a transfer while backups or scheduled tasks run. - Authorize refreshMigration and PrivateKey checkConnection, clear tokens from Livewire state, hide migration log/error from members. Archives: - Refuse ip, user, port, private key, and Cloudflare tunnel changes. - Throttle Enable management and require a free server slot for it and for a transfer back. - Skip cloud provider calls. - Re-read force_disabled before each SSH command, so running jobs stop. - Probe the import check target at the resolved address only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
131 lines
4.5 KiB
PHP
131 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Server\PrivateKey;
|
|
|
|
use App\Models\PrivateKey;
|
|
use App\Models\Server;
|
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
use Illuminate\Http\Exceptions\ThrottleRequestsException;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Livewire\Component;
|
|
|
|
class Show extends Component
|
|
{
|
|
use AuthorizesRequests;
|
|
|
|
public Server $server;
|
|
|
|
public $privateKeys = [];
|
|
|
|
public $parameters = [];
|
|
|
|
public function mount(string $server_uuid)
|
|
{
|
|
try {
|
|
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
|
|
$this->loadPrivateKeys();
|
|
} catch (\Throwable $e) {
|
|
return handleError($e, $this);
|
|
}
|
|
}
|
|
|
|
private function loadPrivateKeys(): void
|
|
{
|
|
$this->privateKeys = PrivateKey::where('team_id', $this->server->team_id)->get()
|
|
->where('is_git_related', false)
|
|
->sortBy(fn (PrivateKey $privateKey) => $privateKey->id !== $this->server->private_key_id)
|
|
->values();
|
|
}
|
|
|
|
public function setPrivateKey($privateKeyId)
|
|
{
|
|
$ownedPrivateKey = PrivateKey::where('team_id', $this->server->team_id)->find($privateKeyId);
|
|
if (is_null($ownedPrivateKey)) {
|
|
$this->dispatch('error', 'You are not allowed to use this private key.');
|
|
|
|
return;
|
|
}
|
|
$this->authorize('update', $this->server);
|
|
if ($this->server->isTransferredAway()) {
|
|
$this->dispatch('error', 'The private key of a transferred server cannot be changed.');
|
|
|
|
return;
|
|
}
|
|
try {
|
|
Server::throttleValidation($this->server->team_id, $this->server->ip);
|
|
} catch (ThrottleRequestsException $e) {
|
|
return handleError($e, $this);
|
|
}
|
|
try {
|
|
DB::transaction(function () use ($ownedPrivateKey) {
|
|
$this->server->privateKey()->associate($ownedPrivateKey);
|
|
$this->server->save();
|
|
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection(justCheckingNewKey: true);
|
|
if (! $uptime) {
|
|
throw new \Exception($error);
|
|
}
|
|
});
|
|
$this->loadPrivateKeys();
|
|
$this->dispatch('success', 'Private key updated successfully.');
|
|
$this->dispatch('refreshServerShow');
|
|
} catch (\Exception $e) {
|
|
$this->server->refresh();
|
|
$this->server->validateConnection();
|
|
$this->dispatch('error', $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function generatePrivateKey(string $type): void
|
|
{
|
|
try {
|
|
$this->authorize('create', PrivateKey::class);
|
|
$this->authorize('update', $this->server);
|
|
|
|
if (! in_array($type, ['ed25519', 'rsa'], true)) {
|
|
$this->dispatch('error', 'Invalid private key type.');
|
|
|
|
return;
|
|
}
|
|
|
|
$keyData = PrivateKey::generateNewKeyPair($type);
|
|
$privateKey = PrivateKey::createAndStore([
|
|
'name' => $keyData['name'],
|
|
'description' => $keyData['description'],
|
|
'private_key' => $keyData['private_key'],
|
|
'team_id' => $this->server->team_id,
|
|
]);
|
|
|
|
$this->loadPrivateKeys();
|
|
$this->dispatch('copyPublicKeyToClipboard', publicKey: $privateKey->public_key);
|
|
$this->dispatch('success', 'Private key created successfully.');
|
|
} catch (\Throwable $e) {
|
|
handleError($e, $this);
|
|
}
|
|
}
|
|
|
|
public function checkConnection()
|
|
{
|
|
try {
|
|
$this->authorize('update', $this->server);
|
|
Server::throttleValidation($this->server->team_id, $this->server->ip);
|
|
['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
|
|
if ($uptime) {
|
|
$this->dispatch('success', 'Server is reachable.');
|
|
$this->dispatch('refreshServerShow');
|
|
} else {
|
|
$sanitizedError = htmlspecialchars($error ?? '', ENT_QUOTES, 'UTF-8');
|
|
$this->dispatch('error', 'Server is not reachable.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help.<br><br>Error: '.$sanitizedError);
|
|
|
|
return;
|
|
}
|
|
} catch (\Throwable $e) {
|
|
return handleError($e, $this);
|
|
}
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.server.private-key.show');
|
|
}
|
|
}
|