Merge pull request #6675 from ShadowArcanist/shadow/security-terminal-access

chore(ui): move terminal access settings to security page
This commit is contained in:
Andras Bacsai 2025-09-25 09:50:57 +02:00 committed by GitHub
commit 1a2783ccc9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 140 additions and 74 deletions

View file

@ -27,9 +27,6 @@ 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 {
@ -42,36 +39,7 @@ public function mount(string $server_uuid)
}
}
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 syncData(bool $toModel = false)
{
@ -88,7 +56,6 @@ public function syncData(bool $toModel = false)
$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;
}
}

View file

@ -0,0 +1,79 @@
<?php
namespace App\Livewire\Server\Security;
use App\Models\InstanceSettings;
use App\Models\Server;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Livewire\Attributes\Validate;
use Livewire\Component;
class TerminalAccess extends Component
{
public Server $server;
public array $parameters = [];
#[Validate(['boolean'])]
public bool $isTerminalEnabled = false;
public function mount(string $server_uuid)
{
try {
$this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
$this->parameters = get_route_parameters();
$this->syncData();
} catch (\Throwable) {
return redirect()->route('server.index');
}
}
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 syncData(bool $toModel = false)
{
if ($toModel) {
$this->authorize('update', $this->server);
$this->validate();
// No other fields to sync for terminal access
} else {
$this->isTerminalEnabled = $this->server->settings->is_terminal_enabled;
}
}
public function render()
{
return view('livewire.server.security.terminal-access');
}
}

View file

@ -3,4 +3,8 @@
href="{{ route('server.security.patches', $parameters) }}">
Server Patching
</a>
<a class="{{ request()->routeIs('server.security.terminal-access') ? 'menu-item menu-item-active' : 'menu-item' }}"
href="{{ route('server.security.terminal-access', $parameters) }}">
Terminal Access
</a>
</div>

View file

@ -14,47 +14,6 @@
<div class="mb-4">Advanced configuration for your server.</div>
</div>
<div class="flex items-center gap-2">
<h3>Terminal Access</h3>
<x-helper
helper="Control whether terminal access is available for this server and its containers.<br/>Only team
administrators and owners can modify this setting." />
@if ($isTerminalEnabled)
<span
class="px-2 py-1 text-xs font-semibold text-green-800 bg-green-100 rounded dark:text-green-100 dark:bg-green-800">
Enabled
</span>
@else
<span
class="px-2 py-1 text-xs font-semibold text-red-800 bg-red-100 rounded dark:text-red-100 dark:bg-red-800">
Disabled
</span>
@endif
</div>
<div class="flex flex-col gap-4">
<div class="flex items-center gap-4 pt-4">
@if (auth()->user()->isAdmin())
<div wire:key="terminal-access-change-{{ $isTerminalEnabled }}" class="pb-4">
<x-modal-confirmation title="Confirm Terminal Access Change?"
temporaryDisableTwoStepConfirmation
buttonTitle="{{ $isTerminalEnabled ? 'Disable Terminal' : 'Enable Terminal' }}"
submitAction="toggleTerminal" :actions="[
$isTerminalEnabled
? 'This will disable terminal access for this server and all its containers.'
: 'This will enable terminal access for this server and all its containers.',
$isTerminalEnabled
? 'Users will no longer be able to access terminal views from the UI.'
: 'Users will be able to access terminal views from the UI.',
'This change will take effect immediately.',
]" confirmationText="{{ $server->name }}"
shortConfirmationLabel="Server Name"
step3ButtonText="{{ $isTerminalEnabled ? 'Disable Terminal' : 'Enable Terminal' }}">
</x-modal-confirmation>
</div>
@endif
</div>
</div>
<h3>Disk Usage</h3>
<div class="flex flex-col gap-6">
<div class="flex flex-col">

View file

@ -0,0 +1,55 @@
<div>
<x-slot:title>
{{ data_get_str($server, 'name')->limit(10) }} > Terminal Access | Coolify
</x-slot>
<livewire:server.navbar :server="$server" />
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex flex-col h-full gap-8 sm:flex-row">
<x-server.sidebar-security :server="$server" :parameters="$parameters" />
<div class="w-full">
<div>
<div class="flex items-center gap-2">
<h2>Terminal Access</h2>
<x-helper
helper="Decide if users (including admins and the owner) can access the terminal for this server and its containers from the dashboard.<br/>
Only team administrators and owners can change this setting."/>
@if (auth()->user()->isAdmin())
<div wire:key="terminal-access-change-{{ $isTerminalEnabled }}">
<x-modal-confirmation title="Confirm Terminal Access Change?"
temporaryDisableTwoStepConfirmation
buttonTitle="{{ $isTerminalEnabled ? 'Disable Terminal' : 'Enable Terminal' }}"
submitAction="toggleTerminal" :actions="[
$isTerminalEnabled
? 'This will disable terminal access for this server and all its containers.'
: 'This will enable terminal access for this server and all its containers.',
$isTerminalEnabled
? 'Users will no longer be able to access terminal views from the UI.'
: 'Users will be able to access terminal views from the UI.',
'This change will take effect immediately.',
]" confirmationText="{{ $server->name }}"
shortConfirmationLabel="Server Name"
step3ButtonText="{{ $isTerminalEnabled ? 'Disable Terminal' : 'Enable Terminal' }}"
isHighlightedButton>
</x-modal-confirmation>
</div>
@endif
</div>
<div class="mb-4">Manage terminal access to this server and its containers.</div>
</div>
<div class="flex items-center gap-2">
<h3>Terminal Status:</h3>
@if ($isTerminalEnabled)
<span
class="px-2 py-1 text-xs font-semibold text-green-800 bg-green-100 rounded dark:text-green-100 dark:bg-green-800">
Operational
</span>
@else
<span
class="px-2 py-1 text-xs font-semibold text-red-800 bg-red-100 rounded dark:text-red-100 dark:bg-red-800">
Disabled
</span>
@endif
</div>
</div>
</div>
</div>

View file

@ -51,6 +51,7 @@
use App\Livewire\Server\Proxy\Show as ProxyShow;
use App\Livewire\Server\Resources as ResourcesShow;
use App\Livewire\Server\Security\Patches;
use App\Livewire\Server\Security\TerminalAccess;
use App\Livewire\Server\Show as ServerShow;
use App\Livewire\Settings\Advanced as SettingsAdvanced;
use App\Livewire\Settings\Index as SettingsIndex;
@ -260,6 +261,7 @@
Route::get('/docker-cleanup', DockerCleanup::class)->name('server.docker-cleanup');
Route::get('/security', fn () => redirect(route('dashboard')))->name('server.security')->middleware('can.update.resource');
Route::get('/security/patches', Patches::class)->name('server.security.patches')->middleware('can.update.resource');
Route::get('/security/terminal-access', TerminalAccess::class)->name('server.security.terminal-access')->middleware('can.update.resource');
});
Route::get('/destinations', DestinationIndex::class)->name('destination.index');
Route::get('/destination/{destination_uuid}', DestinationShow::class)->name('destination.show');