diff --git a/app/Livewire/Project/Shared/ExecuteContainerCommand.php b/app/Livewire/Project/Shared/ExecuteContainerCommand.php index df69a2250..3c2323206 100644 --- a/app/Livewire/Project/Shared/ExecuteContainerCommand.php +++ b/app/Livewire/Project/Shared/ExecuteContainerCommand.php @@ -49,17 +49,18 @@ class ExecuteContainerCommand extends Component if (! auth()->user()->isAdmin()) { abort(403); } + $this->parameters = get_route_parameters(); $this->containers = collect(); $this->servers = collect(); if (data_get($this->parameters, 'application_uuid')) { $this->type = 'application'; $this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail(); - if ($this->resource->destination->server->isFunctional()) { + if ($this->resource->destination->server->isFunctional() && $this->resource->destination->server->isTerminalEnabled()) { $this->servers = $this->servers->push($this->resource->destination->server); } foreach ($this->resource->additional_servers as $server) { - if ($server->isFunctional()) { + if ($server->isFunctional() && $server->isTerminalEnabled()) { $this->servers = $this->servers->push($server); } } @@ -71,14 +72,14 @@ class ExecuteContainerCommand extends Component abort(404); } $this->resource = $resource; - if ($this->resource->destination->server->isFunctional()) { + if ($this->resource->destination->server->isFunctional() && $this->resource->destination->server->isTerminalEnabled()) { $this->servers = $this->servers->push($this->resource->destination->server); } $this->loadContainers(); } elseif (data_get($this->parameters, 'service_uuid')) { $this->type = 'service'; $this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail(); - if ($this->resource->server->isFunctional()) { + if ($this->resource->server->isFunctional() && $this->resource->server->isTerminalEnabled()) { $this->servers = $this->servers->push($this->resource->server); } $this->loadContainers(); diff --git a/app/Livewire/Server/Advanced.php b/app/Livewire/Server/Advanced.php index b2b8b1518..a420a38d7 100644 --- a/app/Livewire/Server/Advanced.php +++ b/app/Livewire/Server/Advanced.php @@ -4,9 +4,12 @@ namespace App\Livewire\Server; use App\Helpers\SslHelper; use App\Jobs\RegenerateSslCertJob; +use App\Models\InstanceSettings; use App\Models\Server; use App\Models\SslCertificate; use Carbon\Carbon; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Hash; use Livewire\Attributes\Validate; use Livewire\Component; @@ -36,6 +39,9 @@ class Advanced extends Component #[Validate(['integer', 'min:1'])] public int $dynamicTimeout = 1; + #[Validate(['boolean'])] + public bool $isTerminalEnabled = false; + public function mount(string $server_uuid) { try { @@ -63,6 +69,37 @@ class Advanced extends Component $this->showCertificate = ! $this->showCertificate; } + public function toggleTerminal($password) + { + try { + // Check if user is admin or owner + if (! auth()->user()->isAdmin()) { + throw new \Exception('Only team administrators and owners can modify terminal access.'); + } + + // Verify password unless two-step confirmation is disabled + if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) { + if (! Hash::check($password, Auth::user()->password)) { + $this->addError('password', 'The provided password is incorrect.'); + + return; + } + } + + // Toggle the terminal setting + $this->server->settings->is_terminal_enabled = ! $this->server->settings->is_terminal_enabled; + $this->server->settings->save(); + + // Update the local property + $this->isTerminalEnabled = $this->server->settings->is_terminal_enabled; + + $status = $this->isTerminalEnabled ? 'enabled' : 'disabled'; + $this->dispatch('success', "Terminal access has been {$status}."); + } catch (\Throwable $e) { + return handleError($e, $this); + } + } + public function saveCaCertificate() { try { @@ -149,6 +186,7 @@ class Advanced extends Component $this->dynamicTimeout = $this->server->settings->dynamic_timeout; $this->serverDiskUsageNotificationThreshold = $this->server->settings->server_disk_usage_notification_threshold; $this->serverDiskUsageCheckFrequency = $this->server->settings->server_disk_usage_check_frequency; + $this->isTerminalEnabled = $this->server->settings->is_terminal_enabled; } } diff --git a/app/Livewire/Terminal/Index.php b/app/Livewire/Terminal/Index.php index a24a237c5..10084a991 100644 --- a/app/Livewire/Terminal/Index.php +++ b/app/Livewire/Terminal/Index.php @@ -21,7 +21,9 @@ class Index extends Component if (! auth()->user()->isAdmin()) { abort(403); } - $this->servers = Server::isReachable()->get(); + $this->servers = Server::isReachable()->get()->filter(function ($server) { + return $server->isTerminalEnabled(); + }); } public function loadContainers() diff --git a/app/Models/Server.php b/app/Models/Server.php index fb9be5de7..7e0a10ce8 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -952,6 +952,11 @@ $schema://$host { } } + public function isTerminalEnabled() + { + return $this->settings->is_terminal_enabled ?? false; + } + public function isSwarm() { return data_get($this, 'settings.is_swarm_manager') || data_get($this, 'settings.is_swarm_worker'); diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php index f4b776cca..3abd55e9c 100644 --- a/app/Models/ServerSetting.php +++ b/app/Models/ServerSetting.php @@ -28,6 +28,7 @@ use OpenApi\Attributes as OA; 'is_sentinel_enabled' => ['type' => 'boolean'], 'is_swarm_manager' => ['type' => 'boolean'], 'is_swarm_worker' => ['type' => 'boolean'], + 'is_terminal_enabled' => ['type' => 'boolean'], 'is_usable' => ['type' => 'boolean'], 'logdrain_axiom_api_key' => ['type' => 'string'], 'logdrain_axiom_dataset_name' => ['type' => 'string'], @@ -59,6 +60,7 @@ class ServerSetting extends Model 'sentinel_token' => 'encrypted', 'is_reachable' => 'boolean', 'is_usable' => 'boolean', + 'is_terminal_enabled' => 'boolean', ]; protected static function booted() diff --git a/database/migrations/2025_05_29_100258_add_terminal_enabled_to_server_settings.php b/database/migrations/2025_05_29_100258_add_terminal_enabled_to_server_settings.php new file mode 100644 index 000000000..45db2f28b --- /dev/null +++ b/database/migrations/2025_05_29_100258_add_terminal_enabled_to_server_settings.php @@ -0,0 +1,28 @@ +boolean('is_terminal_enabled')->default(true); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('server_settings', function (Blueprint $table) { + $table->dropColumn('is_terminal_enabled'); + }); + } +}; diff --git a/resources/views/components/modal-confirmation.blade.php b/resources/views/components/modal-confirmation.blade.php index 3d7bf83dd..75a9e0885 100644 --- a/resources/views/components/modal-confirmation.blade.php +++ b/resources/views/components/modal-confirmation.blade.php @@ -23,11 +23,15 @@ 'dispatchEventType' => 'success', 'dispatchEventMessage' => '', 'ignoreWire' => true, + 'temporaryDisableTwoStepConfirmation' => false, ]) @php use App\Models\InstanceSettings; $disableTwoStepConfirmation = data_get(InstanceSettings::get(), 'disable_two_step_confirmation'); + if ($temporaryDisableTwoStepConfirmation) { + $disableTwoStepConfirmation = false; + } @endphp