diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 465d15470..e9d7b82b2 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -72,5 +72,7 @@ class Kernel extends HttpKernel 'api.ability' => \App\Http\Middleware\ApiAbility::class, 'api.sensitive' => \App\Http\Middleware\ApiSensitiveData::class, 'can.create.resources' => \App\Http\Middleware\CanCreateResources::class, + 'can.update.resource' => \App\Http\Middleware\CanUpdateResource::class, + 'can.access.terminal' => \App\Http\Middleware\CanAccessTerminal::class, ]; } diff --git a/app/Http/Middleware/CanAccessTerminal.php b/app/Http/Middleware/CanAccessTerminal.php new file mode 100644 index 000000000..dcccd819b --- /dev/null +++ b/app/Http/Middleware/CanAccessTerminal.php @@ -0,0 +1,31 @@ +check()) { + // abort(401, 'Authentication required'); + // } + + // // Only admins/owners can access terminal functionality + // if (! auth()->user()->can('canAccessTerminal')) { + // abort(403, 'Access to terminal functionality is restricted to team administrators'); + // } + + // return $next($request); + } +} diff --git a/app/Http/Middleware/CanCreateResources.php b/app/Http/Middleware/CanCreateResources.php index e91118ab0..ba0ab67c1 100644 --- a/app/Http/Middleware/CanCreateResources.php +++ b/app/Http/Middleware/CanCreateResources.php @@ -16,10 +16,11 @@ class CanCreateResources */ public function handle(Request $request, Closure $next): Response { - if (! Gate::allows('createAnyResource')) { - abort(403, 'You do not have permission to create resources.'); - } - return $next($request); + // if (! Gate::allows('createAnyResource')) { + // abort(403, 'You do not have permission to create resources.'); + // } + + // return $next($request); } } diff --git a/app/Http/Middleware/CanUpdateResource.php b/app/Http/Middleware/CanUpdateResource.php new file mode 100644 index 000000000..372af4498 --- /dev/null +++ b/app/Http/Middleware/CanUpdateResource.php @@ -0,0 +1,75 @@ +route('application_uuid')) { + // $resource = Application::where('uuid', $request->route('application_uuid'))->first(); + // } elseif ($request->route('service_uuid')) { + // $resource = Service::where('uuid', $request->route('service_uuid'))->first(); + // } elseif ($request->route('stack_service_uuid')) { + // // Handle ServiceApplication or ServiceDatabase + // $stack_service_uuid = $request->route('stack_service_uuid'); + // $resource = ServiceApplication::where('uuid', $stack_service_uuid)->first() ?? + // ServiceDatabase::where('uuid', $stack_service_uuid)->first(); + // } elseif ($request->route('database_uuid')) { + // // Try different database types + // $database_uuid = $request->route('database_uuid'); + // $resource = StandalonePostgresql::where('uuid', $database_uuid)->first() ?? + // StandaloneMysql::where('uuid', $database_uuid)->first() ?? + // StandaloneMariadb::where('uuid', $database_uuid)->first() ?? + // StandaloneRedis::where('uuid', $database_uuid)->first() ?? + // StandaloneKeydb::where('uuid', $database_uuid)->first() ?? + // StandaloneDragonfly::where('uuid', $database_uuid)->first() ?? + // StandaloneClickhouse::where('uuid', $database_uuid)->first() ?? + // StandaloneMongodb::where('uuid', $database_uuid)->first(); + // } elseif ($request->route('server_uuid')) { + // // For server routes, check if user can manage servers + // if (! auth()->user()->isAdmin()) { + // abort(403, 'You do not have permission to access this resource.'); + // } + + // return $next($request); + // } elseif ($request->route('environment_uuid')) { + // $resource = Environment::where('uuid', $request->route('environment_uuid'))->first(); + // } elseif ($request->route('project_uuid')) { + // $resource = Project::ownedByCurrentTeam()->where('uuid', $request->route('project_uuid'))->first(); + // } + + // if (! $resource) { + // abort(404, 'Resource not found.'); + // } + + // if (! Gate::allows('update', $resource)) { + // abort(403, 'You do not have permission to update this resource.'); + // } + + // return $next($request); + } +} diff --git a/app/Livewire/Destination/Show.php b/app/Livewire/Destination/Show.php index 5c4d6c170..98cf72376 100644 --- a/app/Livewire/Destination/Show.php +++ b/app/Livewire/Destination/Show.php @@ -5,12 +5,15 @@ namespace App\Livewire\Destination; use App\Models\Server; use App\Models\StandaloneDocker; use App\Models\SwarmDocker; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Attributes\Locked; use Livewire\Attributes\Validate; use Livewire\Component; class Show extends Component { + use AuthorizesRequests; + #[Locked] public $destination; @@ -63,6 +66,8 @@ class Show extends Component public function submit() { try { + $this->authorize('update', $this->destination); + $this->syncData(true); $this->dispatch('success', 'Destination saved.'); } catch (\Throwable $e) { @@ -73,6 +78,8 @@ class Show extends Component public function delete() { try { + $this->authorize('delete', $this->destination); + if ($this->destination->getMorphClass() === \App\Models\StandaloneDocker::class) { if ($this->destination->attachedTo()) { return $this->dispatch('error', 'You must delete all resources before deleting this destination.'); diff --git a/app/Livewire/Notifications/Discord.php b/app/Livewire/Notifications/Discord.php index e0425fa17..28d1cb866 100644 --- a/app/Livewire/Notifications/Discord.php +++ b/app/Livewire/Notifications/Discord.php @@ -5,11 +5,14 @@ namespace App\Livewire\Notifications; use App\Models\DiscordNotificationSettings; use App\Models\Team; use App\Notifications\Test; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Attributes\Validate; use Livewire\Component; class Discord extends Component { + use AuthorizesRequests; + public Team $team; public DiscordNotificationSettings $settings; @@ -67,6 +70,7 @@ class Discord extends Component try { $this->team = auth()->user()->currentTeam(); $this->settings = $this->team->discordNotificationSettings; + $this->authorize('view', $this->settings); $this->syncData(); } catch (\Throwable $e) { return handleError($e, $this); @@ -77,6 +81,7 @@ class Discord extends Component { if ($toModel) { $this->validate(); + $this->authorize('update', $this->settings); $this->settings->discord_enabled = $this->discordEnabled; $this->settings->discord_webhook_url = $this->discordWebhookUrl; @@ -182,6 +187,7 @@ class Discord extends Component public function sendTestNotification() { try { + $this->authorize('sendTest', $this->settings); $this->team->notify(new Test(channel: 'discord')); $this->dispatch('success', 'Test notification sent.'); } catch (\Throwable $e) { diff --git a/app/Livewire/Notifications/Email.php b/app/Livewire/Notifications/Email.php index 128321ed2..d62a08417 100644 --- a/app/Livewire/Notifications/Email.php +++ b/app/Livewire/Notifications/Email.php @@ -5,6 +5,7 @@ namespace App\Livewire\Notifications; use App\Models\EmailNotificationSettings; use App\Models\Team; use App\Notifications\Test; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\RateLimiter; use Livewire\Attributes\Locked; use Livewire\Attributes\Validate; @@ -12,6 +13,8 @@ use Livewire\Component; class Email extends Component { + use AuthorizesRequests; + protected $listeners = ['refresh' => '$refresh']; #[Locked] @@ -110,6 +113,7 @@ class Email extends Component $this->team = auth()->user()->currentTeam(); $this->emails = auth()->user()->email; $this->settings = $this->team->emailNotificationSettings; + $this->authorize('view', $this->settings); $this->syncData(); $this->testEmailAddress = auth()->user()->email; } catch (\Throwable $e) { @@ -121,6 +125,7 @@ class Email extends Component { if ($toModel) { $this->validate(); + $this->authorize('update', $this->settings); $this->settings->smtp_enabled = $this->smtpEnabled; $this->settings->smtp_from_address = $this->smtpFromAddress; $this->settings->smtp_from_name = $this->smtpFromName; @@ -311,6 +316,7 @@ class Email extends Component public function sendTestEmail() { try { + $this->authorize('sendTest', $this->settings); $this->validate([ 'testEmailAddress' => 'required|email', ], [ @@ -338,6 +344,7 @@ class Email extends Component public function copyFromInstanceSettings() { + $this->authorize('update', $this->settings); $settings = instanceSettings(); $this->smtpFromAddress = $settings->smtp_from_address; $this->smtpFromName = $settings->smtp_from_name; diff --git a/app/Livewire/Notifications/Pushover.php b/app/Livewire/Notifications/Pushover.php index bd5ab79c8..9c7ff64ad 100644 --- a/app/Livewire/Notifications/Pushover.php +++ b/app/Livewire/Notifications/Pushover.php @@ -5,12 +5,15 @@ namespace App\Livewire\Notifications; use App\Models\PushoverNotificationSettings; use App\Models\Team; use App\Notifications\Test; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Attributes\Locked; use Livewire\Attributes\Validate; use Livewire\Component; class Pushover extends Component { + use AuthorizesRequests; + protected $listeners = ['refresh' => '$refresh']; #[Locked] @@ -72,6 +75,7 @@ class Pushover extends Component try { $this->team = auth()->user()->currentTeam(); $this->settings = $this->team->pushoverNotificationSettings; + $this->authorize('view', $this->settings); $this->syncData(); } catch (\Throwable $e) { return handleError($e, $this); @@ -82,6 +86,7 @@ class Pushover extends Component { if ($toModel) { $this->validate(); + $this->authorize('update', $this->settings); $this->settings->pushover_enabled = $this->pushoverEnabled; $this->settings->pushover_user_key = $this->pushoverUserKey; $this->settings->pushover_api_token = $this->pushoverApiToken; @@ -175,6 +180,7 @@ class Pushover extends Component public function sendTestNotification() { try { + $this->authorize('sendTest', $this->settings); $this->team->notify(new Test(channel: 'pushover')); $this->dispatch('success', 'Test notification sent.'); } catch (\Throwable $e) { diff --git a/app/Livewire/Notifications/Slack.php b/app/Livewire/Notifications/Slack.php index 9c847ce57..d21399c42 100644 --- a/app/Livewire/Notifications/Slack.php +++ b/app/Livewire/Notifications/Slack.php @@ -5,12 +5,15 @@ namespace App\Livewire\Notifications; use App\Models\SlackNotificationSettings; use App\Models\Team; use App\Notifications\Test; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Attributes\Locked; use Livewire\Attributes\Validate; use Livewire\Component; class Slack extends Component { + use AuthorizesRequests; + protected $listeners = ['refresh' => '$refresh']; #[Locked] @@ -69,6 +72,7 @@ class Slack extends Component try { $this->team = auth()->user()->currentTeam(); $this->settings = $this->team->slackNotificationSettings; + $this->authorize('view', $this->settings); $this->syncData(); } catch (\Throwable $e) { return handleError($e, $this); @@ -79,6 +83,7 @@ class Slack extends Component { if ($toModel) { $this->validate(); + $this->authorize('update', $this->settings); $this->settings->slack_enabled = $this->slackEnabled; $this->settings->slack_webhook_url = $this->slackWebhookUrl; @@ -168,6 +173,7 @@ class Slack extends Component public function sendTestNotification() { try { + $this->authorize('sendTest', $this->settings); $this->team->notify(new Test(channel: 'slack')); $this->dispatch('success', 'Test notification sent.'); } catch (\Throwable $e) { diff --git a/app/Livewire/Notifications/Telegram.php b/app/Livewire/Notifications/Telegram.php index 07393d4ea..ca9df47c1 100644 --- a/app/Livewire/Notifications/Telegram.php +++ b/app/Livewire/Notifications/Telegram.php @@ -5,12 +5,15 @@ namespace App\Livewire\Notifications; use App\Models\Team; use App\Models\TelegramNotificationSettings; use App\Notifications\Test; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Attributes\Locked; use Livewire\Attributes\Validate; use Livewire\Component; class Telegram extends Component { + use AuthorizesRequests; + protected $listeners = ['refresh' => '$refresh']; #[Locked] @@ -111,6 +114,7 @@ class Telegram extends Component try { $this->team = auth()->user()->currentTeam(); $this->settings = $this->team->telegramNotificationSettings; + $this->authorize('view', $this->settings); $this->syncData(); } catch (\Throwable $e) { return handleError($e, $this); @@ -121,6 +125,7 @@ class Telegram extends Component { if ($toModel) { $this->validate(); + $this->authorize('update', $this->settings); $this->settings->telegram_enabled = $this->telegramEnabled; $this->settings->telegram_token = $this->telegramToken; $this->settings->telegram_chat_id = $this->telegramChatId; @@ -241,6 +246,7 @@ class Telegram extends Component public function sendTestNotification() { try { + $this->authorize('sendTest', $this->settings); $this->team->notify(new Test(channel: 'telegram')); $this->dispatch('success', 'Test notification sent.'); } catch (\Throwable $e) { diff --git a/app/Livewire/Project/Application/Preview/Form.php b/app/Livewire/Project/Application/Preview/Form.php index edcab44c8..ff951ec54 100644 --- a/app/Livewire/Project/Application/Preview/Form.php +++ b/app/Livewire/Project/Application/Preview/Form.php @@ -3,12 +3,15 @@ namespace App\Livewire\Project\Application\Preview; use App\Models\Application; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Attributes\Validate; use Livewire\Component; use Spatie\Url\Url; class Form extends Component { + use AuthorizesRequests; + public Application $application; #[Validate('required')] @@ -27,6 +30,7 @@ class Form extends Component public function submit() { try { + $this->authorize('update', $this->application); $this->resetErrorBag(); $this->validate(); $this->application->preview_url_template = str_replace(' ', '', $this->previewUrlTemplate); @@ -41,6 +45,7 @@ class Form extends Component public function resetToDefault() { try { + $this->authorize('update', $this->application); $this->application->preview_url_template = '{{pr_id}}.{{domain}}'; $this->previewUrlTemplate = $this->application->preview_url_template; $this->application->save(); diff --git a/app/Livewire/Project/Application/Previews.php b/app/Livewire/Project/Application/Previews.php index 5f07b02f3..9164c1475 100644 --- a/app/Livewire/Project/Application/Previews.php +++ b/app/Livewire/Project/Application/Previews.php @@ -38,6 +38,7 @@ class Previews extends Component public function load_prs() { try { + $this->authorize('update', $this->application); ['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/pulls"); $this->rate_limit_remaining = $rate_limit_remaining; $this->pull_requests = $data->sortBy('number')->values(); diff --git a/app/Livewire/Project/Database/Import.php b/app/Livewire/Project/Database/Import.php index 6622abaaf..3f974f63d 100644 --- a/app/Livewire/Project/Database/Import.php +++ b/app/Livewire/Project/Database/Import.php @@ -176,6 +176,7 @@ EOD; return; } try { + $this->importRunning = true; $this->importCommands = []; if (filled($this->customLocation)) { $backupFileName = '/tmp/restore_'.$this->resource->uuid; diff --git a/app/Livewire/Project/Index.php b/app/Livewire/Project/Index.php index 5347d74f0..5381fa78d 100644 --- a/app/Livewire/Project/Index.php +++ b/app/Livewire/Project/Index.php @@ -20,6 +20,7 @@ class Index extends Component $this->private_keys = PrivateKey::ownedByCurrentTeam()->get(); $this->projects = Project::ownedByCurrentTeam()->get()->map(function ($project) { $project->settingsRoute = route('project.edit', ['project_uuid' => $project->uuid]); + $project->canUpdate = auth()->user()->can('update', $project); return $project; }); diff --git a/app/Livewire/Project/Service/Configuration.php b/app/Livewire/Project/Service/Configuration.php index 8ac74e7de..559851e3a 100644 --- a/app/Livewire/Project/Service/Configuration.php +++ b/app/Livewire/Project/Service/Configuration.php @@ -3,11 +3,14 @@ namespace App\Livewire\Project\Service; use App\Models\Service; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Auth; use Livewire\Component; class Configuration extends Component { + use AuthorizesRequests; + public $currentRoute; public $project; @@ -40,24 +43,30 @@ class Configuration extends Component public function mount() { - $this->parameters = get_route_parameters(); - $this->currentRoute = request()->route()->getName(); - $this->query = request()->query(); - $project = currentTeam() - ->projects() - ->select('id', 'uuid', 'team_id') - ->where('uuid', request()->route('project_uuid')) - ->firstOrFail(); - $environment = $project->environments() - ->select('id', 'uuid', 'name', 'project_id') - ->where('uuid', request()->route('environment_uuid')) - ->firstOrFail(); - $this->service = $environment->services()->whereUuid(request()->route('service_uuid'))->firstOrFail(); + try { + $this->parameters = get_route_parameters(); + $this->currentRoute = request()->route()->getName(); + $this->query = request()->query(); + $project = currentTeam() + ->projects() + ->select('id', 'uuid', 'team_id') + ->where('uuid', request()->route('project_uuid')) + ->firstOrFail(); + $environment = $project->environments() + ->select('id', 'uuid', 'name', 'project_id') + ->where('uuid', request()->route('environment_uuid')) + ->firstOrFail(); + $this->service = $environment->services()->whereUuid(request()->route('service_uuid'))->firstOrFail(); - $this->project = $project; - $this->environment = $environment; - $this->applications = $this->service->applications->sort(); - $this->databases = $this->service->databases->sort(); + $this->authorize('view', $this->service); + + $this->project = $project; + $this->environment = $environment; + $this->applications = $this->service->applications->sort(); + $this->databases = $this->service->databases->sort(); + } catch (\Throwable $e) { + return handleError($e, $this); + } } public function refreshServices() @@ -70,6 +79,7 @@ class Configuration extends Component public function restartApplication($id) { try { + $this->authorize('update', $this->service); $application = $this->service->applications->find($id); if ($application) { $application->restart(); @@ -83,6 +93,7 @@ class Configuration extends Component public function restartDatabase($id) { try { + $this->authorize('update', $this->service); $database = $this->service->databases->find($id); if ($database) { $database->restart(); diff --git a/app/Livewire/Project/Service/Database.php b/app/Livewire/Project/Service/Database.php index 0af757c8c..abf4c45a7 100644 --- a/app/Livewire/Project/Service/Database.php +++ b/app/Livewire/Project/Service/Database.php @@ -6,6 +6,7 @@ use App\Actions\Database\StartDatabaseProxy; use App\Actions\Database\StopDatabaseProxy; use App\Models\InstanceSettings; use App\Models\ServiceDatabase; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; @@ -13,6 +14,8 @@ use Livewire\Component; class Database extends Component { + use AuthorizesRequests; + public ServiceDatabase $database; public ?string $db_url_public = null; @@ -40,24 +43,31 @@ class Database extends Component public function mount() { - $this->parameters = get_route_parameters(); - if ($this->database->is_public) { - $this->db_url_public = $this->database->getServiceDatabaseUrl(); + try { + $this->parameters = get_route_parameters(); + $this->authorize('view', $this->database); + if ($this->database->is_public) { + $this->db_url_public = $this->database->getServiceDatabaseUrl(); + } + $this->refreshFileStorages(); + } catch (\Throwable $e) { + return handleError($e, $this); } - $this->refreshFileStorages(); } public function delete($password) { - 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; - } - } - try { + $this->authorize('delete', $this->database); + + 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; + } + } + $this->database->delete(); $this->dispatch('success', 'Database deleted.'); @@ -69,24 +79,35 @@ class Database extends Component public function instantSaveExclude() { - $this->submit(); + try { + $this->authorize('update', $this->database); + $this->submit(); + } catch (\Throwable $e) { + return handleError($e, $this); + } } public function instantSaveLogDrain() { - if (! $this->database->service->destination->server->isLogDrainEnabled()) { - $this->database->is_log_drain_enabled = false; - $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); + try { + $this->authorize('update', $this->database); + if (! $this->database->service->destination->server->isLogDrainEnabled()) { + $this->database->is_log_drain_enabled = false; + $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); - return; + return; + } + $this->submit(); + $this->dispatch('success', 'You need to restart the service for the changes to take effect.'); + } catch (\Throwable $e) { + return handleError($e, $this); } - $this->submit(); - $this->dispatch('success', 'You need to restart the service for the changes to take effect.'); } public function convertToApplication() { try { + $this->authorize('update', $this->database); $service = $this->database->service; $serviceDatabase = $this->database; @@ -122,28 +143,33 @@ class Database extends Component public function instantSave() { - if ($this->database->is_public && ! $this->database->public_port) { - $this->dispatch('error', 'Public port is required.'); - $this->database->is_public = false; - - return; - } - if ($this->database->is_public) { - if (! str($this->database->status)->startsWith('running')) { - $this->dispatch('error', 'Database must be started to be publicly accessible.'); + try { + $this->authorize('update', $this->database); + if ($this->database->is_public && ! $this->database->public_port) { + $this->dispatch('error', 'Public port is required.'); $this->database->is_public = false; return; } - StartDatabaseProxy::run($this->database); - $this->db_url_public = $this->database->getServiceDatabaseUrl(); - $this->dispatch('success', 'Database is now publicly accessible.'); - } else { - StopDatabaseProxy::run($this->database); - $this->db_url_public = null; - $this->dispatch('success', 'Database is no longer publicly accessible.'); + if ($this->database->is_public) { + if (! str($this->database->status)->startsWith('running')) { + $this->dispatch('error', 'Database must be started to be publicly accessible.'); + $this->database->is_public = false; + + return; + } + StartDatabaseProxy::run($this->database); + $this->db_url_public = $this->database->getServiceDatabaseUrl(); + $this->dispatch('success', 'Database is now publicly accessible.'); + } else { + StopDatabaseProxy::run($this->database); + $this->db_url_public = null; + $this->dispatch('success', 'Database is no longer publicly accessible.'); + } + $this->submit(); + } catch (\Throwable $e) { + return handleError($e, $this); } - $this->submit(); } public function refreshFileStorages() @@ -154,11 +180,13 @@ class Database extends Component public function submit() { try { + $this->authorize('update', $this->database); $this->validate(); $this->database->save(); updateCompose($this->database); $this->dispatch('success', 'Database saved.'); - } catch (\Throwable) { + } catch (\Throwable $e) { + return handleError($e, $this); } finally { $this->dispatch('generateDockerCompose'); } diff --git a/app/Livewire/Project/Service/FileStorage.php b/app/Livewire/Project/Service/FileStorage.php index 5b88c15eb..2933a8cca 100644 --- a/app/Livewire/Project/Service/FileStorage.php +++ b/app/Livewire/Project/Service/FileStorage.php @@ -15,12 +15,15 @@ use App\Models\StandaloneMongodb; use App\Models\StandaloneMysql; use App\Models\StandalonePostgresql; use App\Models\StandaloneRedis; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; use Livewire\Component; class FileStorage extends Component { + use AuthorizesRequests; + public LocalFileVolume $fileStorage; public ServiceApplication|StandaloneRedis|StandalonePostgresql|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse|ServiceDatabase|Application $resource; @@ -54,6 +57,8 @@ class FileStorage extends Component public function convertToDirectory() { try { + $this->authorize('update', $this->resource); + $this->fileStorage->deleteStorageOnServer(); $this->fileStorage->is_directory = true; $this->fileStorage->content = null; @@ -70,6 +75,8 @@ class FileStorage extends Component public function loadStorageOnServer() { try { + $this->authorize('update', $this->resource); + $this->fileStorage->loadStorageOnServer(); $this->dispatch('success', 'File storage loaded from server.'); } catch (\Throwable $e) { @@ -82,6 +89,8 @@ class FileStorage extends Component public function convertToFile() { try { + $this->authorize('update', $this->resource); + $this->fileStorage->deleteStorageOnServer(); $this->fileStorage->is_directory = false; $this->fileStorage->content = null; @@ -99,6 +108,8 @@ class FileStorage extends Component public function delete($password) { + $this->authorize('update', $this->resource); + if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) { if (! Hash::check($password, Auth::user()->password)) { $this->addError('password', 'The provided password is incorrect.'); @@ -127,6 +138,8 @@ class FileStorage extends Component public function submit() { + $this->authorize('update', $this->resource); + $original = $this->fileStorage->getOriginal(); try { $this->validate(); diff --git a/app/Livewire/Project/Service/Index.php b/app/Livewire/Project/Service/Index.php index 39f4e106d..8d37d3e31 100644 --- a/app/Livewire/Project/Service/Index.php +++ b/app/Livewire/Project/Service/Index.php @@ -5,11 +5,14 @@ namespace App\Livewire\Project\Service; use App\Models\Service; use App\Models\ServiceApplication; use App\Models\ServiceDatabase; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Collection; use Livewire\Component; class Index extends Component { + use AuthorizesRequests; + public ?Service $service = null; public ?ServiceApplication $serviceApplication = null; @@ -36,6 +39,7 @@ class Index extends Component if (! $this->service) { return redirect()->route('dashboard'); } + $this->authorize('view', $this->service); $service = $this->service->applications()->whereUuid($this->parameters['stack_service_uuid'])->first(); if ($service) { $this->serviceApplication = $service; @@ -52,7 +56,12 @@ class Index extends Component public function generateDockerCompose() { - $this->service->parse(); + try { + $this->authorize('update', $this->service); + $this->service->parse(); + } catch (\Throwable $e) { + return handleError($e, $this); + } } public function render() diff --git a/app/Livewire/Project/Service/ServiceApplicationView.php b/app/Livewire/Project/Service/ServiceApplicationView.php index 64f7ab95c..5e178374b 100644 --- a/app/Livewire/Project/Service/ServiceApplicationView.php +++ b/app/Livewire/Project/Service/ServiceApplicationView.php @@ -4,6 +4,7 @@ namespace App\Livewire\Project\Service; use App\Models\InstanceSettings; use App\Models\ServiceApplication; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Hash; @@ -12,6 +13,8 @@ use Spatie\Url\Url; class ServiceApplicationView extends Component { + use AuthorizesRequests; + public ServiceApplication $application; public $parameters; @@ -34,32 +37,44 @@ class ServiceApplicationView extends Component public function instantSave() { - $this->submit(); + try { + $this->authorize('update', $this->application); + $this->submit(); + } catch (\Throwable $e) { + return handleError($e, $this); + } } public function instantSaveAdvanced() { - if (! $this->application->service->destination->server->isLogDrainEnabled()) { - $this->application->is_log_drain_enabled = false; - $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); + try { + $this->authorize('update', $this->application); + if (! $this->application->service->destination->server->isLogDrainEnabled()) { + $this->application->is_log_drain_enabled = false; + $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); - return; + return; + } + $this->application->save(); + $this->dispatch('success', 'You need to restart the service for the changes to take effect.'); + } catch (\Throwable $e) { + return handleError($e, $this); } - $this->application->save(); - $this->dispatch('success', 'You need to restart the service for the changes to take effect.'); } public function delete($password) { - 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; - } - } - try { + $this->authorize('delete', $this->application); + + 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; + } + } + $this->application->delete(); $this->dispatch('success', 'Application deleted.'); @@ -71,12 +86,18 @@ class ServiceApplicationView extends Component public function mount() { - $this->parameters = get_route_parameters(); + try { + $this->parameters = get_route_parameters(); + $this->authorize('view', $this->application); + } catch (\Throwable $e) { + return handleError($e, $this); + } } public function convertToDatabase() { try { + $this->authorize('update', $this->application); $service = $this->application->service; $serviceApplication = $this->application; @@ -111,6 +132,7 @@ class ServiceApplicationView extends Component public function submit() { try { + $this->authorize('update', $this->application); $this->application->fqdn = str($this->application->fqdn)->replaceEnd(',', '')->trim(); $this->application->fqdn = str($this->application->fqdn)->replaceStart(',', '')->trim(); $this->application->fqdn = str($this->application->fqdn)->trim()->explode(',')->map(function ($domain) { diff --git a/app/Livewire/Project/Service/Storage.php b/app/Livewire/Project/Service/Storage.php index 4b64a8b5e..26cd54425 100644 --- a/app/Livewire/Project/Service/Storage.php +++ b/app/Livewire/Project/Service/Storage.php @@ -3,10 +3,13 @@ namespace App\Livewire\Project\Service; use App\Models\LocalPersistentVolume; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Storage extends Component { + use AuthorizesRequests; + public $resource; public $fileStorage; @@ -42,6 +45,8 @@ class Storage extends Component public function addNewVolume($data) { try { + $this->authorize('update', $this->resource); + LocalPersistentVolume::create([ 'name' => $data['name'], 'mount_path' => $data['mount_path'], diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Add.php b/app/Livewire/Project/Shared/EnvironmentVariable/Add.php index 0dbf0f957..cf7843f84 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/Add.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/Add.php @@ -2,10 +2,13 @@ namespace App\Livewire\Project\Shared\EnvironmentVariable; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Add extends Component { + use AuthorizesRequests; + public $parameters; public bool $shared = false; diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php index 966d626b1..1a9daf77b 100644 --- a/app/Livewire/Project/Shared/EnvironmentVariable/Show.php +++ b/app/Livewire/Project/Shared/EnvironmentVariable/Show.php @@ -5,11 +5,12 @@ namespace App\Livewire\Project\Shared\EnvironmentVariable; use App\Models\EnvironmentVariable as ModelsEnvironmentVariable; use App\Models\SharedEnvironmentVariable; use App\Traits\EnvironmentVariableProtection; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Show extends Component { - use EnvironmentVariableProtection; + use AuthorizesRequests, EnvironmentVariableProtection; public $parameters; @@ -75,6 +76,11 @@ class Show extends Component } } + public function getResourceProperty() + { + return $this->env->resourceable ?? $this->env; + } + public function refresh() { $this->syncData(); @@ -140,6 +146,8 @@ class Show extends Component public function lock() { + $this->authorize('update', $this->env); + $this->env->is_shown_once = true; if ($this->isSharedVariable) { unset($this->env->is_required); @@ -158,6 +166,8 @@ class Show extends Component public function submit() { try { + $this->authorize('update', $this->env); + if (! $this->isSharedVariable && $this->is_required && str($this->value)->isEmpty()) { $oldValue = $this->env->getOriginal('value'); $this->value = $oldValue; @@ -179,9 +189,11 @@ class Show extends Component public function delete() { try { + $this->authorize('delete', $this->env); + // Check if the variable is used in Docker Compose - if ($this->type === 'service' || $this->type === 'application' && $this->env->resource()?->docker_compose) { - [$isUsed, $reason] = $this->isEnvironmentVariableUsedInDockerCompose($this->env->key, $this->env->resource()?->docker_compose); + if ($this->type === 'service' || $this->type === 'application' && $this->env->resourceable?->docker_compose) { + [$isUsed, $reason] = $this->isEnvironmentVariableUsedInDockerCompose($this->env->key, $this->env->resourceable?->docker_compose); if ($isUsed) { $this->dispatch('error', "Cannot delete environment variable '{$this->env->key}'

Please remove it from the Docker Compose file first."); diff --git a/app/Livewire/Project/Shared/HealthChecks.php b/app/Livewire/Project/Shared/HealthChecks.php index 83162e36a..ae94f7cf2 100644 --- a/app/Livewire/Project/Shared/HealthChecks.php +++ b/app/Livewire/Project/Shared/HealthChecks.php @@ -2,10 +2,13 @@ namespace App\Livewire\Project\Shared; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class HealthChecks extends Component { + use AuthorizesRequests; + public $resource; protected $rules = [ @@ -27,6 +30,7 @@ class HealthChecks extends Component public function instantSave() { + $this->authorize('update', $this->resource); $this->resource->save(); $this->dispatch('success', 'Health check updated.'); } @@ -34,6 +38,7 @@ class HealthChecks extends Component public function submit() { try { + $this->authorize('update', $this->resource); $this->validate(); $this->resource->save(); $this->dispatch('success', 'Health check updated.'); diff --git a/app/Livewire/Project/Shared/ResourceLimits.php b/app/Livewire/Project/Shared/ResourceLimits.php index 608dfbf02..196badec8 100644 --- a/app/Livewire/Project/Shared/ResourceLimits.php +++ b/app/Livewire/Project/Shared/ResourceLimits.php @@ -2,10 +2,13 @@ namespace App\Livewire\Project\Shared; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class ResourceLimits extends Component { + use AuthorizesRequests; + public $resource; protected $rules = [ @@ -31,6 +34,7 @@ class ResourceLimits extends Component public function submit() { try { + $this->authorize('update', $this->resource); if (! $this->resource->limits_memory) { $this->resource->limits_memory = '0'; } diff --git a/app/Livewire/Project/Shared/ScheduledTask/Add.php b/app/Livewire/Project/Shared/ScheduledTask/Add.php index c286fee5a..e4b666532 100644 --- a/app/Livewire/Project/Shared/ScheduledTask/Add.php +++ b/app/Livewire/Project/Shared/ScheduledTask/Add.php @@ -3,12 +3,15 @@ namespace App\Livewire\Project\Shared\ScheduledTask; use App\Models\ScheduledTask; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Collection; use Livewire\Attributes\Locked; use Livewire\Component; class Add extends Component { + use AuthorizesRequests; + public $parameters; #[Locked] @@ -20,6 +23,9 @@ class Add extends Component #[Locked] public Collection $containerNames; + #[Locked] + public $resource; + public string $name; public string $command; @@ -45,6 +51,22 @@ class Add extends Component public function mount() { $this->parameters = get_route_parameters(); + + // Get the resource based on type and id + switch ($this->type) { + case 'application': + $this->resource = \App\Models\Application::findOrFail($this->id); + break; + case 'service': + $this->resource = \App\Models\Service::findOrFail($this->id); + break; + case 'standalone-postgresql': + $this->resource = \App\Models\StandalonePostgresql::findOrFail($this->id); + break; + default: + throw new \Exception('Invalid resource type'); + } + if ($this->containerNames->count() > 0) { $this->container = $this->containerNames->first(); } @@ -53,6 +75,7 @@ class Add extends Component public function submit() { try { + $this->authorize('update', $this->resource); $this->validate(); $isValid = validate_cron_expression($this->frequency); if (! $isValid) { diff --git a/app/Livewire/Project/Shared/ScheduledTask/Show.php b/app/Livewire/Project/Shared/ScheduledTask/Show.php index fe6e36d5c..c8d07ae36 100644 --- a/app/Livewire/Project/Shared/ScheduledTask/Show.php +++ b/app/Livewire/Project/Shared/ScheduledTask/Show.php @@ -6,12 +6,15 @@ use App\Jobs\ScheduledTaskJob; use App\Models\Application; use App\Models\ScheduledTask; use App\Models\Service; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Attributes\Locked; use Livewire\Attributes\Validate; use Livewire\Component; class Show extends Component { + use AuthorizesRequests; + public Application|Service $resource; public ScheduledTask $task; @@ -109,6 +112,7 @@ class Show extends Component public function instantSave() { try { + $this->authorize('update', $this->resource); $this->syncData(true); $this->dispatch('success', 'Scheduled task updated.'); $this->refreshTasks(); @@ -120,6 +124,7 @@ class Show extends Component public function submit() { try { + $this->authorize('update', $this->resource); $this->syncData(true); $this->dispatch('success', 'Scheduled task updated.'); } catch (\Exception $e) { @@ -139,6 +144,7 @@ class Show extends Component public function delete() { try { + $this->authorize('update', $this->resource); $this->task->delete(); if ($this->type === 'application') { @@ -154,6 +160,7 @@ class Show extends Component public function executeNow() { try { + $this->authorize('update', $this->resource); ScheduledTaskJob::dispatch($this->task); $this->dispatch('success', 'Scheduled task executed.'); } catch (\Exception $e) { diff --git a/app/Livewire/Project/Shared/Storages/Add.php b/app/Livewire/Project/Shared/Storages/Add.php index dc015386c..006d41c14 100644 --- a/app/Livewire/Project/Shared/Storages/Add.php +++ b/app/Livewire/Project/Shared/Storages/Add.php @@ -4,10 +4,13 @@ namespace App\Livewire\Project\Shared\Storages; use App\Models\Application; use App\Models\LocalFileVolume; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Add extends Component { + use AuthorizesRequests; + public $resource; public $uuid; @@ -77,6 +80,8 @@ class Add extends Component public function submitFileStorage() { try { + $this->authorize('update', $this->resource); + $this->validate([ 'file_storage_path' => 'string', 'file_storage_content' => 'nullable|string', @@ -112,6 +117,8 @@ class Add extends Component public function submitFileStorageDirectory() { try { + $this->authorize('update', $this->resource); + $this->validate([ 'file_storage_directory_source' => 'string', 'file_storage_directory_destination' => 'string', @@ -140,6 +147,8 @@ class Add extends Component public function submitPersistentVolume() { try { + $this->authorize('update', $this->resource); + $this->validate([ 'name' => 'required|string', 'mount_path' => 'required|string', diff --git a/app/Livewire/Project/Shared/Storages/Show.php b/app/Livewire/Project/Shared/Storages/Show.php index 54b1be3af..3928ee1d4 100644 --- a/app/Livewire/Project/Shared/Storages/Show.php +++ b/app/Livewire/Project/Shared/Storages/Show.php @@ -4,14 +4,19 @@ namespace App\Livewire\Project\Shared\Storages; use App\Models\InstanceSettings; use App\Models\LocalPersistentVolume; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; use Livewire\Component; class Show extends Component { + use AuthorizesRequests; + public LocalPersistentVolume $storage; + public $resource; + public bool $isReadOnly = false; public bool $isFirst = true; @@ -34,6 +39,8 @@ class Show extends Component public function submit() { + $this->authorize('update', $this->resource); + $this->validate(); $this->storage->save(); $this->dispatch('success', 'Storage updated successfully'); @@ -41,6 +48,8 @@ class Show extends Component public function delete($password) { + $this->authorize('update', $this->resource); + if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) { if (! Hash::check($password, Auth::user()->password)) { $this->addError('password', 'The provided password is incorrect.'); diff --git a/app/Livewire/Project/Shared/Tags.php b/app/Livewire/Project/Shared/Tags.php index 811859cb8..37b8b277a 100644 --- a/app/Livewire/Project/Shared/Tags.php +++ b/app/Livewire/Project/Shared/Tags.php @@ -3,12 +3,15 @@ namespace App\Livewire\Project\Shared; use App\Models\Tag; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Attributes\Validate; use Livewire\Component; // Refactored ✅ class Tags extends Component { + use AuthorizesRequests; + public $resource = null; #[Validate('required|string|min:2')] @@ -34,6 +37,7 @@ class Tags extends Component public function submit() { try { + $this->authorize('update', $this->resource); $this->validate(); $tags = str($this->newTags)->trim()->explode(' '); foreach ($tags as $tag) { @@ -66,6 +70,7 @@ class Tags extends Component public function addTag(string $id, string $name) { try { + $this->authorize('update', $this->resource); $name = strip_tags($name); if ($this->resource->tags()->where('id', $id)->exists()) { $this->dispatch('error', 'Duplicate tags.', "Tag $name already added."); @@ -83,6 +88,7 @@ class Tags extends Component public function deleteTag(string $id) { try { + $this->authorize('update', $this->resource); $this->resource->tags()->detach($id); $found_more_tags = Tag::ownedByCurrentTeam()->find($id); if ($found_more_tags && $found_more_tags->applications()->count() == 0 && $found_more_tags->services()->count() == 0) { diff --git a/app/Livewire/Project/Shared/Webhooks.php b/app/Livewire/Project/Shared/Webhooks.php index 57c65c4dd..eafc653d5 100644 --- a/app/Livewire/Project/Shared/Webhooks.php +++ b/app/Livewire/Project/Shared/Webhooks.php @@ -2,11 +2,14 @@ namespace App\Livewire\Project\Shared; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; // Refactored ✅ class Webhooks extends Component { + use AuthorizesRequests; + public $resource; public ?string $deploywebhook; diff --git a/app/Livewire/Security/ApiTokens.php b/app/Livewire/Security/ApiTokens.php index 72684bdc6..a263acedf 100644 --- a/app/Livewire/Security/ApiTokens.php +++ b/app/Livewire/Security/ApiTokens.php @@ -3,10 +3,14 @@ namespace App\Livewire\Security; use App\Models\InstanceSettings; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; +use Laravel\Sanctum\PersonalAccessToken; use Livewire\Component; class ApiTokens extends Component { + use AuthorizesRequests; + public ?string $description = null; public $tokens = []; @@ -15,6 +19,10 @@ class ApiTokens extends Component public $isApiEnabled; + public bool $canUseRootPermissions = false; + + public bool $canUseWritePermissions = false; + public function render() { return view('livewire.security.api-tokens'); @@ -23,6 +31,8 @@ class ApiTokens extends Component public function mount() { $this->isApiEnabled = InstanceSettings::get()->is_api_enabled; + $this->canUseRootPermissions = auth()->user()->can('useRootPermissions', PersonalAccessToken::class); + $this->canUseWritePermissions = auth()->user()->can('useWritePermissions', PersonalAccessToken::class); $this->getTokens(); } @@ -33,6 +43,23 @@ class ApiTokens extends Component public function updatedPermissions($permissionToUpdate) { + // Check if user is trying to use restricted permissions + if ($permissionToUpdate == 'root' && ! $this->canUseRootPermissions) { + $this->dispatch('error', 'You do not have permission to use root permissions.'); + // Remove root from permissions if it was somehow added + $this->permissions = array_diff($this->permissions, ['root']); + + return; + } + + if (in_array($permissionToUpdate, ['write', 'write:sensitive']) && ! $this->canUseWritePermissions) { + $this->dispatch('error', 'You do not have permission to use write permissions.'); + // Remove write permissions if they were somehow added + $this->permissions = array_diff($this->permissions, ['write', 'write:sensitive']); + + return; + } + if ($permissionToUpdate == 'root') { $this->permissions = ['root']; } elseif ($permissionToUpdate == 'read:sensitive' && ! in_array('read', $this->permissions)) { @@ -50,6 +77,17 @@ class ApiTokens extends Component public function addNewToken() { try { + $this->authorize('create', PersonalAccessToken::class); + + // Validate permissions based on user role + if (in_array('root', $this->permissions) && ! $this->canUseRootPermissions) { + throw new \Exception('You do not have permission to create tokens with root permissions.'); + } + + if (array_intersect(['write', 'write:sensitive'], $this->permissions) && ! $this->canUseWritePermissions) { + throw new \Exception('You do not have permission to create tokens with write permissions.'); + } + $this->validate([ 'description' => 'required|min:3|max:255', ]); @@ -65,6 +103,7 @@ class ApiTokens extends Component { try { $token = auth()->user()->tokens()->where('id', $id)->firstOrFail(); + $this->authorize('delete', $token); $token->delete(); $this->getTokens(); } catch (\Exception $e) { diff --git a/app/Livewire/Security/PrivateKey/Index.php b/app/Livewire/Security/PrivateKey/Index.php index 76441a67e..950ec152d 100644 --- a/app/Livewire/Security/PrivateKey/Index.php +++ b/app/Livewire/Security/PrivateKey/Index.php @@ -3,10 +3,13 @@ namespace App\Livewire\Security\PrivateKey; use App\Models\PrivateKey; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Index extends Component { + use AuthorizesRequests; + public function render() { $privateKeys = PrivateKey::ownedByCurrentTeam(['name', 'uuid', 'is_git_related', 'description'])->get(); @@ -18,6 +21,7 @@ class Index extends Component public function cleanupUnusedKeys() { + $this->authorize('create', PrivateKey::class); PrivateKey::cleanupUnusedKeys(); $this->dispatch('success', 'Unused keys have been cleaned up.'); } diff --git a/app/Livewire/Server/Proxy/DynamicConfigurationNavbar.php b/app/Livewire/Server/Proxy/DynamicConfigurationNavbar.php index 392ad38fa..f377bbeb9 100644 --- a/app/Livewire/Server/Proxy/DynamicConfigurationNavbar.php +++ b/app/Livewire/Server/Proxy/DynamicConfigurationNavbar.php @@ -3,12 +3,17 @@ namespace App\Livewire\Server\Proxy; use App\Models\Server; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class DynamicConfigurationNavbar extends Component { + use AuthorizesRequests; + public $server_id; + public Server $server; + public $fileName = ''; public $value = ''; @@ -17,18 +22,18 @@ class DynamicConfigurationNavbar extends Component public function delete(string $fileName) { - $server = Server::ownedByCurrentTeam()->whereId($this->server_id)->first(); - $proxy_path = $server->proxyPath(); - $proxy_type = $server->proxyType(); + $this->authorize('update', $this->server); + $proxy_path = $this->server->proxyPath(); + $proxy_type = $this->server->proxyType(); $file = str_replace('|', '.', $fileName); if ($proxy_type === 'CADDY' && $file === 'Caddyfile') { $this->dispatch('error', 'Cannot delete Caddyfile.'); return; } - instant_remote_process(["rm -f {$proxy_path}/dynamic/{$file}"], $server); + instant_remote_process(["rm -f {$proxy_path}/dynamic/{$file}"], $this->server); if ($proxy_type === 'CADDY') { - $server->reloadCaddy(); + $this->server->reloadCaddy(); } $this->dispatch('success', 'File deleted.'); $this->dispatch('loadDynamicConfigurations'); diff --git a/app/Livewire/SharedVariables/Environment/Show.php b/app/Livewire/SharedVariables/Environment/Show.php index e88ac5f13..bee757a64 100644 --- a/app/Livewire/SharedVariables/Environment/Show.php +++ b/app/Livewire/SharedVariables/Environment/Show.php @@ -4,10 +4,13 @@ namespace App\Livewire\SharedVariables\Environment; use App\Models\Application; use App\Models\Project; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Show extends Component { + use AuthorizesRequests; + public Project $project; public Application $application; @@ -21,6 +24,8 @@ class Show extends Component public function saveKey($data) { try { + $this->authorize('update', $this->environment); + $found = $this->environment->environment_variables()->where('key', $data['key'])->first(); if ($found) { throw new \Exception('Variable already exists.'); diff --git a/app/Livewire/SharedVariables/Project/Show.php b/app/Livewire/SharedVariables/Project/Show.php index 0171283c4..712a9960b 100644 --- a/app/Livewire/SharedVariables/Project/Show.php +++ b/app/Livewire/SharedVariables/Project/Show.php @@ -3,10 +3,13 @@ namespace App\Livewire\SharedVariables\Project; use App\Models\Project; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Show extends Component { + use AuthorizesRequests; + public Project $project; protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey' => 'saveKey', 'environmentVariableDeleted' => '$refresh']; @@ -14,6 +17,8 @@ class Show extends Component public function saveKey($data) { try { + $this->authorize('update', $this->project); + $found = $this->project->environment_variables()->where('key', $data['key'])->first(); if ($found) { throw new \Exception('Variable already exists.'); diff --git a/app/Livewire/SharedVariables/Team/Index.php b/app/Livewire/SharedVariables/Team/Index.php index a76ccf58a..82473528c 100644 --- a/app/Livewire/SharedVariables/Team/Index.php +++ b/app/Livewire/SharedVariables/Team/Index.php @@ -3,10 +3,13 @@ namespace App\Livewire\SharedVariables\Team; use App\Models\Team; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Index extends Component { + use AuthorizesRequests; + public Team $team; protected $listeners = ['refreshEnvs' => '$refresh', 'saveKey' => 'saveKey', 'environmentVariableDeleted' => '$refresh']; @@ -14,6 +17,8 @@ class Index extends Component public function saveKey($data) { try { + $this->authorize('update', $this->team); + $found = $this->team->environment_variables()->where('key', $data['key'])->first(); if ($found) { throw new \Exception('Variable already exists.'); diff --git a/app/Livewire/Source/Github/Change.php b/app/Livewire/Source/Github/Change.php index e73c9dc73..9ad5444b9 100644 --- a/app/Livewire/Source/Github/Change.php +++ b/app/Livewire/Source/Github/Change.php @@ -5,6 +5,7 @@ namespace App\Livewire\Source\Github; use App\Jobs\GithubAppPermissionJob; use App\Models\GithubApp; use App\Models\PrivateKey; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Http; use Lcobucci\JWT\Configuration; use Lcobucci\JWT\Signer\Key\InMemory; @@ -13,7 +14,9 @@ use Livewire\Component; class Change extends Component { - public string $webhook_endpoint; + use AuthorizesRequests; + + public string $webhook_endpoint = ''; public ?string $ipv4 = null; @@ -69,6 +72,8 @@ class Change extends Component public function checkPermissions() { try { + $this->authorize('view', $this->github_app); + GithubAppPermissionJob::dispatchSync($this->github_app); $this->github_app->refresh()->makeVisible('client_secret')->makeVisible('webhook_secret'); $this->dispatch('success', 'Github App permissions updated.'); @@ -155,7 +160,7 @@ class Change extends Component if (isCloud() && ! isDev()) { $this->webhook_endpoint = config('app.url'); } else { - $this->webhook_endpoint = $this->ipv4; + $this->webhook_endpoint = $this->ipv4 ?? ''; $this->is_system_wide = $this->github_app->is_system_wide; } } catch (\Throwable $e) { @@ -195,6 +200,8 @@ class Change extends Component public function updateGithubAppName() { try { + $this->authorize('update', $this->github_app); + $privateKey = PrivateKey::ownedByCurrentTeam()->find($this->github_app->private_key_id); if (! $privateKey) { @@ -237,6 +244,8 @@ class Change extends Component public function submit() { try { + $this->authorize('update', $this->github_app); + $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret'); $this->validate([ 'github_app.name' => 'required|string', @@ -262,6 +271,8 @@ class Change extends Component public function createGithubAppManually() { + $this->authorize('update', $this->github_app); + $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret'); $this->github_app->app_id = '1234567890'; $this->github_app->installation_id = '1234567890'; @@ -272,6 +283,8 @@ class Change extends Component public function instantSave() { try { + $this->authorize('update', $this->github_app); + $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret'); $this->github_app->save(); $this->dispatch('success', 'Github App updated.'); @@ -283,6 +296,8 @@ class Change extends Component public function delete() { try { + $this->authorize('delete', $this->github_app); + if ($this->github_app->applications->isNotEmpty()) { $this->dispatch('error', 'This source is being used by an application. Please delete all applications first.'); $this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret'); diff --git a/app/Livewire/Source/Github/Create.php b/app/Livewire/Source/Github/Create.php index 136d3525e..f5d851b64 100644 --- a/app/Livewire/Source/Github/Create.php +++ b/app/Livewire/Source/Github/Create.php @@ -3,10 +3,13 @@ namespace App\Livewire\Source\Github; use App\Models\GithubApp; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Create extends Component { + use AuthorizesRequests; + public string $name; public ?string $organization = null; @@ -29,6 +32,8 @@ class Create extends Component public function createGitHubApp() { try { + $this->authorize('createAnyResource'); + $this->validate([ 'name' => 'required|string', 'organization' => 'nullable|string', diff --git a/app/Livewire/Storage/Create.php b/app/Livewire/Storage/Create.php index 9cbc516da..9efeb948c 100644 --- a/app/Livewire/Storage/Create.php +++ b/app/Livewire/Storage/Create.php @@ -4,11 +4,14 @@ namespace App\Livewire\Storage; use App\Models\S3Storage; use App\Support\ValidationPatterns; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Uri; use Livewire\Component; class Create extends Component { + use AuthorizesRequests; + public string $name; public string $description; @@ -94,6 +97,8 @@ class Create extends Component public function submit() { try { + $this->authorize('create', S3Storage::class); + $this->validate(); $this->storage = new S3Storage; $this->storage->name = $this->name; diff --git a/app/Livewire/Storage/Form.php b/app/Livewire/Storage/Form.php index fd2222d32..41541f6b9 100644 --- a/app/Livewire/Storage/Form.php +++ b/app/Livewire/Storage/Form.php @@ -4,10 +4,13 @@ namespace App\Livewire\Storage; use App\Models\S3Storage; use App\Support\ValidationPatterns; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Form extends Component { + use AuthorizesRequests; + public S3Storage $storage; protected function rules(): array @@ -60,6 +63,8 @@ class Form extends Component public function testConnection() { try { + $this->authorize('validateConnection', $this->storage); + $this->storage->testConnection(shouldSave: true); return $this->dispatch('success', 'Connection is working.', 'Tested with "ListObjectsV2" action.'); @@ -83,8 +88,10 @@ class Form extends Component public function submit() { - $this->validate(); try { + $this->authorize('update', $this->storage); + + $this->validate(); $this->testConnection(); } catch (\Throwable $e) { return handleError($e, $this); diff --git a/app/Livewire/Team/Index.php b/app/Livewire/Team/Index.php index accaab8d9..8b9b70e14 100644 --- a/app/Livewire/Team/Index.php +++ b/app/Livewire/Team/Index.php @@ -5,12 +5,15 @@ namespace App\Livewire\Team; use App\Models\Team; use App\Models\TeamInvitation; use App\Support\ValidationPatterns; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Livewire\Component; class Index extends Component { + use AuthorizesRequests; + public $invitations = []; public Team $team; @@ -58,6 +61,7 @@ class Index extends Component { $this->validate(); try { + $this->authorize('update', $this->team); $this->team->save(); refreshSession(); $this->dispatch('success', 'Team updated.'); @@ -69,6 +73,7 @@ class Index extends Component public function delete() { $currentTeam = currentTeam(); + $this->authorize('delete', $currentTeam); $currentTeam->delete(); $currentTeam->members->each(function ($user) use ($currentTeam) { diff --git a/app/Livewire/Team/Invitations.php b/app/Livewire/Team/Invitations.php index 3af0e0e92..523f640b9 100644 --- a/app/Livewire/Team/Invitations.php +++ b/app/Livewire/Team/Invitations.php @@ -4,10 +4,13 @@ namespace App\Livewire\Team; use App\Models\TeamInvitation; use App\Models\User; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Invitations extends Component { + use AuthorizesRequests; + public $invitations; protected $listeners = ['refreshInvitations']; @@ -15,6 +18,8 @@ class Invitations extends Component public function deleteInvitation(int $invitation_id) { try { + $this->authorize('manageInvitations', currentTeam()); + $invitation = TeamInvitation::ownedByCurrentTeam()->findOrFail($invitation_id); $user = User::whereEmail($invitation->email)->first(); if (filled($user)) { diff --git a/app/Livewire/Team/InviteLink.php b/app/Livewire/Team/InviteLink.php index fb0c51e54..0bac39db8 100644 --- a/app/Livewire/Team/InviteLink.php +++ b/app/Livewire/Team/InviteLink.php @@ -4,6 +4,7 @@ namespace App\Livewire\Team; use App\Models\TeamInvitation; use App\Models\User; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Hash; @@ -13,6 +14,8 @@ use Visus\Cuid2\Cuid2; class InviteLink extends Component { + use AuthorizesRequests; + public string $email; public string $role = 'member'; @@ -40,6 +43,7 @@ class InviteLink extends Component private function generateInviteLink(bool $sendEmail = false) { try { + $this->authorize('manageInvitations', currentTeam()); $this->validate(); if (auth()->user()->role() === 'admin' && $this->role === 'owner') { throw new \Exception('Admins cannot invite owners.'); diff --git a/app/Livewire/Team/Member.php b/app/Livewire/Team/Member.php index 890d640a0..96c98c637 100644 --- a/app/Livewire/Team/Member.php +++ b/app/Livewire/Team/Member.php @@ -4,16 +4,21 @@ namespace App\Livewire\Team; use App\Enums\Role; use App\Models\User; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Facades\Cache; use Livewire\Component; class Member extends Component { + use AuthorizesRequests; + public User $member; public function makeAdmin() { try { + $this->authorize('manageMembers', currentTeam()); + if (Role::from(auth()->user()->role())->lt(Role::ADMIN) || Role::from($this->getMemberRole())->gt(auth()->user()->role())) { throw new \Exception('You are not authorized to perform this action.'); @@ -28,6 +33,8 @@ class Member extends Component public function makeOwner() { try { + $this->authorize('manageMembers', currentTeam()); + if (Role::from(auth()->user()->role())->lt(Role::OWNER) || Role::from($this->getMemberRole())->gt(auth()->user()->role())) { throw new \Exception('You are not authorized to perform this action.'); @@ -42,6 +49,8 @@ class Member extends Component public function makeReadonly() { try { + $this->authorize('manageMembers', currentTeam()); + if (Role::from(auth()->user()->role())->lt(Role::ADMIN) || Role::from($this->getMemberRole())->gt(auth()->user()->role())) { throw new \Exception('You are not authorized to perform this action.'); @@ -56,6 +65,8 @@ class Member extends Component public function remove() { try { + $this->authorize('manageMembers', currentTeam()); + if (Role::from(auth()->user()->role())->lt(Role::ADMIN) || Role::from($this->getMemberRole())->gt(auth()->user()->role())) { throw new \Exception('You are not authorized to perform this action.'); diff --git a/app/Livewire/Team/Member/Index.php b/app/Livewire/Team/Member/Index.php index 00b745fe4..e057ba3f6 100644 --- a/app/Livewire/Team/Member/Index.php +++ b/app/Livewire/Team/Member/Index.php @@ -3,15 +3,19 @@ namespace App\Livewire\Team\Member; use App\Models\TeamInvitation; +use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Livewire\Component; class Index extends Component { + use AuthorizesRequests; + public $invitations = []; public function mount() { - if (auth()->user()->isAdminFromSession()) { + // Only load invitations for users who can manage them + if (auth()->user()->can('manageInvitations', currentTeam())) { $this->invitations = TeamInvitation::whereTeamId(currentTeam()->id)->get(); } } diff --git a/app/Livewire/Terminal/Index.php b/app/Livewire/Terminal/Index.php index dfeb5da66..03dbc1d91 100644 --- a/app/Livewire/Terminal/Index.php +++ b/app/Livewire/Terminal/Index.php @@ -18,7 +18,6 @@ class Index extends Component public function mount() { - $this->authorize('useTerminal', Server::class); $this->servers = Server::isReachable()->get()->filter(function ($server) { return $server->isTerminalEnabled(); }); diff --git a/app/Models/SharedEnvironmentVariable.php b/app/Models/SharedEnvironmentVariable.php index aab8b8735..7956f006a 100644 --- a/app/Models/SharedEnvironmentVariable.php +++ b/app/Models/SharedEnvironmentVariable.php @@ -12,4 +12,19 @@ class SharedEnvironmentVariable extends Model 'key' => 'string', 'value' => 'encrypted', ]; + + public function team() + { + return $this->belongsTo(Team::class); + } + + public function project() + { + return $this->belongsTo(Project::class); + } + + public function environment() + { + return $this->belongsTo(Environment::class); + } } diff --git a/app/Policies/ApiTokenPolicy.php b/app/Policies/ApiTokenPolicy.php new file mode 100644 index 000000000..761227118 --- /dev/null +++ b/app/Policies/ApiTokenPolicy.php @@ -0,0 +1,109 @@ +id === $token->tokenable_id && $token->tokenable_type === User::class; + */ + return true; + } + + /** + * Determine whether the user can create API tokens. + */ + public function create(User $user): bool + { + // Authorization temporarily disabled + /* + // All authenticated users can create their own API tokens + return true; + */ + return true; + } + + /** + * Determine whether the user can update the API token. + */ + public function update(User $user, PersonalAccessToken $token): bool + { + // Authorization temporarily disabled + /* + // Users can only update their own tokens + return $user->id === $token->tokenable_id && $token->tokenable_type === User::class; + */ + return true; + } + + /** + * Determine whether the user can delete the API token. + */ + public function delete(User $user, PersonalAccessToken $token): bool + { + // Authorization temporarily disabled + /* + // Users can only delete their own tokens + return $user->id === $token->tokenable_id && $token->tokenable_type === User::class; + */ + return true; + } + + /** + * Determine whether the user can manage their own API tokens. + */ + public function manage(User $user): bool + { + // Authorization temporarily disabled + /* + // All authenticated users can manage their own API tokens + return true; + */ + return true; + } + + /** + * Determine whether the user can use root permissions for API tokens. + */ + public function useRootPermissions(User $user): bool + { + // Only admins and owners can use root permissions + return $user->isAdmin() || $user->isOwner(); + } + + /** + * Determine whether the user can use write permissions for API tokens. + */ + public function useWritePermissions(User $user): bool + { + // Authorization temporarily disabled + /* + // Only admins and owners can use write permissions + return $user->isAdmin() || $user->isOwner(); + */ + return true; + } +} diff --git a/app/Policies/ApplicationPolicy.php b/app/Policies/ApplicationPolicy.php index 62deb50b1..d64a436ad 100644 --- a/app/Policies/ApplicationPolicy.php +++ b/app/Policies/ApplicationPolicy.php @@ -13,6 +13,10 @@ class ApplicationPolicy */ public function viewAny(User $user): bool { + // Authorization temporarily disabled + /* + return true; + */ return true; } @@ -21,6 +25,10 @@ class ApplicationPolicy */ public function view(User $user, Application $application): bool { + // Authorization temporarily disabled + /* + return true; + */ return true; } @@ -29,11 +37,15 @@ class ApplicationPolicy */ public function create(User $user): bool { + // Authorization temporarily disabled + /* if ($user->isAdmin()) { return true; } return false; + */ + return true; } /** @@ -41,11 +53,15 @@ class ApplicationPolicy */ public function update(User $user, Application $application): Response { + // Authorization temporarily disabled + /* if ($user->isAdmin()) { return Response::allow(); } return Response::deny('As a member, you cannot update this application.

You need at least admin or owner permissions.'); + */ + return Response::allow(); } /** @@ -53,11 +69,15 @@ class ApplicationPolicy */ public function delete(User $user, Application $application): bool { + // Authorization temporarily disabled + /* if ($user->isAdmin()) { return true; } return false; + */ + return true; } /** @@ -65,6 +85,10 @@ class ApplicationPolicy */ public function restore(User $user, Application $application): bool { + // Authorization temporarily disabled + /* + return true; + */ return true; } @@ -73,7 +97,11 @@ class ApplicationPolicy */ public function forceDelete(User $user, Application $application): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $application->team()->first()->id) !== null; + // Authorization temporarily disabled + /* + return $user->isAdmin() && $user->teams->contains('id', $application->team()->first()->id); + */ + return true; } /** @@ -81,7 +109,11 @@ class ApplicationPolicy */ public function deploy(User $user, Application $application): bool { - return $user->teams()->get()->firstWhere('id', $application->team()->first()->id) !== null; + // Authorization temporarily disabled + /* + return $user->teams->contains('id', $application->team()->first()->id); + */ + return true; } /** @@ -89,7 +121,11 @@ class ApplicationPolicy */ public function manageDeployments(User $user, Application $application): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $application->team()->first()->id) !== null; + // Authorization temporarily disabled + /* + return $user->isAdmin() && $user->teams->contains('id', $application->team()->first()->id); + */ + return true; } /** @@ -97,7 +133,11 @@ class ApplicationPolicy */ public function manageEnvironment(User $user, Application $application): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $application->team()->first()->id) !== null; + // Authorization temporarily disabled + /* + return $user->isAdmin() && $user->teams->contains('id', $application->team()->first()->id); + */ + return true; } /** @@ -105,6 +145,10 @@ class ApplicationPolicy */ public function cleanupDeploymentQueue(User $user): bool { + // Authorization temporarily disabled + /* return $user->isAdmin(); + */ + return true; } } diff --git a/app/Policies/ApplicationPreviewPolicy.php b/app/Policies/ApplicationPreviewPolicy.php index 26cf13fcc..14efbdef9 100644 --- a/app/Policies/ApplicationPreviewPolicy.php +++ b/app/Policies/ApplicationPreviewPolicy.php @@ -21,7 +21,8 @@ class ApplicationPreviewPolicy */ public function view(User $user, ApplicationPreview $applicationPreview): bool { - return $user->teams()->get()->firstWhere('id', $applicationPreview->application->team()->first()->id) !== null; + // return $user->teams->contains('id', $applicationPreview->application->team()->first()->id); + return true; } /** @@ -29,7 +30,8 @@ class ApplicationPreviewPolicy */ public function create(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -37,11 +39,12 @@ class ApplicationPreviewPolicy */ public function update(User $user, ApplicationPreview $applicationPreview): Response { - if ($user->isAdmin()) { - return Response::allow(); - } + // if ($user->isAdmin()) { + // return Response::allow(); + // } - return Response::deny('As a member, you cannot update this preview.

You need at least admin or owner permissions.'); + // return Response::deny('As a member, you cannot update this preview.

You need at least admin or owner permissions.'); + return true; } /** @@ -49,7 +52,8 @@ class ApplicationPreviewPolicy */ public function delete(User $user, ApplicationPreview $applicationPreview): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $applicationPreview->application->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $applicationPreview->application->team()->first()->id); + return true; } /** @@ -57,7 +61,8 @@ class ApplicationPreviewPolicy */ public function restore(User $user, ApplicationPreview $applicationPreview): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $applicationPreview->application->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $applicationPreview->application->team()->first()->id); + return true; } /** @@ -65,7 +70,8 @@ class ApplicationPreviewPolicy */ public function forceDelete(User $user, ApplicationPreview $applicationPreview): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $applicationPreview->application->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $applicationPreview->application->team()->first()->id); + return true; } /** @@ -73,7 +79,8 @@ class ApplicationPreviewPolicy */ public function deploy(User $user, ApplicationPreview $applicationPreview): bool { - return $user->teams()->get()->firstWhere('id', $applicationPreview->application->team()->first()->id) !== null; + // return $user->teams->contains('id', $applicationPreview->application->team()->first()->id); + return true; } /** @@ -81,6 +88,7 @@ class ApplicationPreviewPolicy */ public function manageDeployments(User $user, ApplicationPreview $applicationPreview): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $applicationPreview->application->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $applicationPreview->application->team()->first()->id); + return true; } } diff --git a/app/Policies/ApplicationSettingPolicy.php b/app/Policies/ApplicationSettingPolicy.php index ff5e81d2f..848dc9aee 100644 --- a/app/Policies/ApplicationSettingPolicy.php +++ b/app/Policies/ApplicationSettingPolicy.php @@ -20,7 +20,8 @@ class ApplicationSettingPolicy */ public function view(User $user, ApplicationSetting $applicationSetting): bool { - return $user->teams()->get()->firstWhere('id', $applicationSetting->application->team()->first()->id) !== null; + // return $user->teams->contains('id', $applicationSetting->application->team()->first()->id); + return true; } /** @@ -28,7 +29,8 @@ class ApplicationSettingPolicy */ public function create(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -36,7 +38,8 @@ class ApplicationSettingPolicy */ public function update(User $user, ApplicationSetting $applicationSetting): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $applicationSetting->application->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $applicationSetting->application->team()->first()->id); + return true; } /** @@ -44,7 +47,8 @@ class ApplicationSettingPolicy */ public function delete(User $user, ApplicationSetting $applicationSetting): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $applicationSetting->application->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $applicationSetting->application->team()->first()->id); + return true; } /** @@ -52,7 +56,8 @@ class ApplicationSettingPolicy */ public function restore(User $user, ApplicationSetting $applicationSetting): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $applicationSetting->application->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $applicationSetting->application->team()->first()->id); + return true; } /** @@ -60,6 +65,7 @@ class ApplicationSettingPolicy */ public function forceDelete(User $user, ApplicationSetting $applicationSetting): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $applicationSetting->application->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $applicationSetting->application->team()->first()->id); + return true; } } diff --git a/app/Policies/DatabasePolicy.php b/app/Policies/DatabasePolicy.php index b38dad923..520c0006e 100644 --- a/app/Policies/DatabasePolicy.php +++ b/app/Policies/DatabasePolicy.php @@ -20,7 +20,8 @@ class DatabasePolicy */ public function view(User $user, $database): bool { - return $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null; + // return $user->teams->contains('id', $database->team()->first()->id); + return true; } /** @@ -28,7 +29,8 @@ class DatabasePolicy */ public function create(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -36,11 +38,12 @@ class DatabasePolicy */ public function update(User $user, $database): Response { - if ($user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null) { - return Response::allow(); - } + // if ($user->isAdmin() && $user->teams->contains('id', $database->team()->first()->id)) { + // return Response::allow(); + // } - return Response::deny('As a member, you cannot update this database.

You need at least admin or owner permissions.'); + // return Response::deny('As a member, you cannot update this database.

You need at least admin or owner permissions.'); + return true; } /** @@ -48,7 +51,8 @@ class DatabasePolicy */ public function delete(User $user, $database): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $database->team()->first()->id); + return true; } /** @@ -56,7 +60,8 @@ class DatabasePolicy */ public function restore(User $user, $database): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $database->team()->first()->id); + return true; } /** @@ -64,7 +69,8 @@ class DatabasePolicy */ public function forceDelete(User $user, $database): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $database->team()->first()->id); + return true; } /** @@ -72,7 +78,8 @@ class DatabasePolicy */ public function manage(User $user, $database): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $database->team()->first()->id); + return true; } /** @@ -80,7 +87,8 @@ class DatabasePolicy */ public function manageBackups(User $user, $database): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $database->team()->first()->id); + return true; } /** @@ -88,6 +96,7 @@ class DatabasePolicy */ public function manageEnvironment(User $user, $database): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $database->team()->first()->id); + return true; } } diff --git a/app/Policies/EnvironmentPolicy.php b/app/Policies/EnvironmentPolicy.php index 9fdcb3abe..7199abb25 100644 --- a/app/Policies/EnvironmentPolicy.php +++ b/app/Policies/EnvironmentPolicy.php @@ -20,7 +20,8 @@ class EnvironmentPolicy */ public function view(User $user, Environment $environment): bool { - return $user->teams()->get()->firstWhere('id', $environment->project->team_id) !== null; + // return $user->teams->contains('id', $environment->project->team_id); + return true; } /** @@ -28,7 +29,8 @@ class EnvironmentPolicy */ public function create(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -36,7 +38,8 @@ class EnvironmentPolicy */ public function update(User $user, Environment $environment): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $environment->project->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $environment->project->team_id); + return true; } /** @@ -44,7 +47,8 @@ class EnvironmentPolicy */ public function delete(User $user, Environment $environment): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $environment->project->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $environment->project->team_id); + return true; } /** @@ -52,7 +56,8 @@ class EnvironmentPolicy */ public function restore(User $user, Environment $environment): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $environment->project->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $environment->project->team_id); + return true; } /** @@ -60,6 +65,7 @@ class EnvironmentPolicy */ public function forceDelete(User $user, Environment $environment): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $environment->project->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $environment->project->team_id); + return true; } } diff --git a/app/Policies/GithubAppPolicy.php b/app/Policies/GithubAppPolicy.php new file mode 100644 index 000000000..56bec7032 --- /dev/null +++ b/app/Policies/GithubAppPolicy.php @@ -0,0 +1,79 @@ +teams->contains('id', $githubApp->team_id) || $githubApp->is_system_wide; + return true; + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + // return $user->isAdmin(); + return true; + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, GithubApp $githubApp): bool + { + if ($githubApp->is_system_wide) { + // return $user->isAdmin(); + return true; + } + + // return $user->isAdmin() && $user->teams->contains('id', $githubApp->team_id); + return true; + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, GithubApp $githubApp): bool + { + if ($githubApp->is_system_wide) { + // return $user->isAdmin(); + return true; + } + + // return $user->isAdmin() && $user->teams->contains('id', $githubApp->team_id); + return true; + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, GithubApp $githubApp): bool + { + return false; + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, GithubApp $githubApp): bool + { + return false; + } +} diff --git a/app/Policies/NotificationPolicy.php b/app/Policies/NotificationPolicy.php new file mode 100644 index 000000000..4f3be431d --- /dev/null +++ b/app/Policies/NotificationPolicy.php @@ -0,0 +1,56 @@ +team) { + return false; + } + + // return $user->teams()->where('teams.id', $notificationSettings->team->id)->exists(); + return true; + } + + /** + * Determine whether the user can update the notification settings. + */ + public function update(User $user, Model $notificationSettings): bool + { + // Check if the notification settings belong to the user's current team + if (! $notificationSettings->team) { + return false; + } + + // Only owners and admins can update notification settings + // return $user->isAdmin() || $user->isOwner(); + return true; + } + + /** + * Determine whether the user can manage (create, update, delete) notification settings. + */ + public function manage(User $user, Model $notificationSettings): bool + { + // return $this->update($user, $notificationSettings); + return true; + } + + /** + * Determine whether the user can send test notifications. + */ + public function sendTest(User $user, Model $notificationSettings): bool + { + // return $this->update($user, $notificationSettings); + return true; + } +} diff --git a/app/Policies/PrivateKeyPolicy.php b/app/Policies/PrivateKeyPolicy.php index 6b9fd2171..996054c95 100644 --- a/app/Policies/PrivateKeyPolicy.php +++ b/app/Policies/PrivateKeyPolicy.php @@ -20,7 +20,8 @@ class PrivateKeyPolicy */ public function view(User $user, PrivateKey $privateKey): bool { - return $user->teams()->get()->firstWhere('id', $privateKey->team_id) !== null; + // return $user->teams->contains('id', $privateKey->team_id); + return true; } /** @@ -28,7 +29,8 @@ class PrivateKeyPolicy */ public function create(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -36,7 +38,8 @@ class PrivateKeyPolicy */ public function update(User $user, PrivateKey $privateKey): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $privateKey->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $privateKey->team_id); + return true; } /** @@ -44,7 +47,8 @@ class PrivateKeyPolicy */ public function delete(User $user, PrivateKey $privateKey): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $privateKey->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $privateKey->team_id); + return true; } /** diff --git a/app/Policies/ProjectPolicy.php b/app/Policies/ProjectPolicy.php index 27ed159bd..e188c293f 100644 --- a/app/Policies/ProjectPolicy.php +++ b/app/Policies/ProjectPolicy.php @@ -20,7 +20,8 @@ class ProjectPolicy */ public function view(User $user, Project $project): bool { - return $user->teams()->get()->firstWhere('id', $project->team_id) !== null; + // return $user->teams->contains('id', $project->team_id); + return true; } /** @@ -28,7 +29,8 @@ class ProjectPolicy */ public function create(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -36,7 +38,8 @@ class ProjectPolicy */ public function update(User $user, Project $project): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $project->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $project->team_id); + return true; } /** @@ -44,7 +47,8 @@ class ProjectPolicy */ public function delete(User $user, Project $project): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $project->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $project->team_id); + return true; } /** @@ -52,7 +56,8 @@ class ProjectPolicy */ public function restore(User $user, Project $project): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $project->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $project->team_id); + return true; } /** @@ -60,6 +65,7 @@ class ProjectPolicy */ public function forceDelete(User $user, Project $project): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $project->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $project->team_id); + return true; } } diff --git a/app/Policies/ResourceCreatePolicy.php b/app/Policies/ResourceCreatePolicy.php index 58f6ba212..9ed2b66ab 100644 --- a/app/Policies/ResourceCreatePolicy.php +++ b/app/Policies/ResourceCreatePolicy.php @@ -30,6 +30,7 @@ class ResourceCreatePolicy StandaloneClickhouse::class, Service::class, Application::class, + GithubApp::class, ]; /** @@ -37,7 +38,8 @@ class ResourceCreatePolicy */ public function createAny(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -49,7 +51,8 @@ class ResourceCreatePolicy return false; } - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** diff --git a/app/Policies/S3StoragePolicy.php b/app/Policies/S3StoragePolicy.php index 9b24dd31a..982c7c523 100644 --- a/app/Policies/S3StoragePolicy.php +++ b/app/Policies/S3StoragePolicy.php @@ -3,7 +3,6 @@ namespace App\Policies; use App\Models\S3Storage; -use App\Models\Server; use App\Models\User; class S3StoragePolicy @@ -21,7 +20,7 @@ class S3StoragePolicy */ public function view(User $user, S3Storage $storage): bool { - return $user->teams()->get()->firstWhere('id', $storage->team_id)->exists(); + return $user->teams->contains('id', $storage->team_id); } /** @@ -35,9 +34,10 @@ class S3StoragePolicy /** * Determine whether the user can update the model. */ - public function update(User $user, Server $server): bool + public function update(User $user, S3Storage $storage): bool { - return $user->teams()->get()->firstWhere('id', $server->team_id)->exists() && $user->isAdmin(); + // return $user->teams->contains('id', $storage->team_id) && $user->isAdmin(); + return $user->teams->contains('id', $storage->team_id); } /** @@ -45,7 +45,8 @@ class S3StoragePolicy */ public function delete(User $user, S3Storage $storage): bool { - return $user->teams()->get()->firstWhere('id', $storage->team_id)->exists() && $user->isAdmin(); + // return $user->teams->contains('id', $storage->team_id) && $user->isAdmin(); + return $user->teams->contains('id', $storage->team_id); } /** @@ -63,4 +64,12 @@ class S3StoragePolicy { return false; } + + /** + * Determine whether the user can validate the connection of the model. + */ + public function validateConnection(User $user, S3Storage $storage): bool + { + return $user->teams->contains('id', $storage->team_id); + } } diff --git a/app/Policies/ServerPolicy.php b/app/Policies/ServerPolicy.php index a9a64e801..5cc6b739f 100644 --- a/app/Policies/ServerPolicy.php +++ b/app/Policies/ServerPolicy.php @@ -20,7 +20,7 @@ class ServerPolicy */ public function view(User $user, Server $server): bool { - return $user->teams()->get()->firstWhere('id', $server->team_id) !== null; + return $user->teams->contains('id', $server->team_id); } /** @@ -36,7 +36,7 @@ class ServerPolicy */ public function update(User $user, Server $server): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $server->team_id) !== null; + return $user->isAdmin() && $user->teams->contains('id', $server->team_id); } /** @@ -44,7 +44,7 @@ class ServerPolicy */ public function delete(User $user, Server $server): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $server->team_id) !== null; + return $user->isAdmin() && $user->teams->contains('id', $server->team_id); } /** @@ -68,7 +68,7 @@ class ServerPolicy */ public function manageProxy(User $user, Server $server): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $server->team_id) !== null; + return $user->isAdmin() && $user->teams->contains('id', $server->team_id); } /** @@ -76,7 +76,7 @@ class ServerPolicy */ public function manageSentinel(User $user, Server $server): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $server->team_id) !== null; + return $user->isAdmin() && $user->teams->contains('id', $server->team_id); } /** @@ -84,7 +84,7 @@ class ServerPolicy */ public function manageCaCertificate(User $user, Server $server): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $server->team_id) !== null; + return $user->isAdmin() && $user->teams->contains('id', $server->team_id); } /** @@ -92,7 +92,7 @@ class ServerPolicy */ public function viewTerminal(User $user, Server $server): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $server->team_id) !== null; + return $user->isAdmin() && $user->teams->contains('id', $server->team_id); } /** @@ -100,6 +100,6 @@ class ServerPolicy */ public function viewSecurity(User $user, Server $server): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $server->team_id) !== null; + return $user->isAdmin() && $user->teams->contains('id', $server->team_id); } } diff --git a/app/Policies/ServiceApplicationPolicy.php b/app/Policies/ServiceApplicationPolicy.php new file mode 100644 index 000000000..af380a90f --- /dev/null +++ b/app/Policies/ServiceApplicationPolicy.php @@ -0,0 +1,63 @@ +service); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + // return $user->isAdmin(); + return true; + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, ServiceApplication $serviceApplication): bool + { + // return Gate::allows('update', $serviceApplication->service); + return true; + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, ServiceApplication $serviceApplication): bool + { + // return Gate::allows('delete', $serviceApplication->service); + return true; + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, ServiceApplication $serviceApplication): bool + { + // return Gate::allows('update', $serviceApplication->service); + return true; + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, ServiceApplication $serviceApplication): bool + { + // return Gate::allows('delete', $serviceApplication->service); + return true; + } +} diff --git a/app/Policies/ServiceDatabasePolicy.php b/app/Policies/ServiceDatabasePolicy.php new file mode 100644 index 000000000..023434a24 --- /dev/null +++ b/app/Policies/ServiceDatabasePolicy.php @@ -0,0 +1,63 @@ +service); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + // return $user->isAdmin(); + return true; + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, ServiceDatabase $serviceDatabase): bool + { + // return Gate::allows('update', $serviceDatabase->service); + return true; + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, ServiceDatabase $serviceDatabase): bool + { + // return Gate::allows('delete', $serviceDatabase->service); + return true; + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, ServiceDatabase $serviceDatabase): bool + { + // return Gate::allows('update', $serviceDatabase->service); + return true; + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, ServiceDatabase $serviceDatabase): bool + { + // return Gate::allows('delete', $serviceDatabase->service); + return true; + } +} diff --git a/app/Policies/ServicePolicy.php b/app/Policies/ServicePolicy.php index c3f1f9a9a..7ab0fe7d0 100644 --- a/app/Policies/ServicePolicy.php +++ b/app/Policies/ServicePolicy.php @@ -28,7 +28,8 @@ class ServicePolicy */ public function create(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -36,7 +37,13 @@ class ServicePolicy */ public function update(User $user, Service $service): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $service->team()->first()->id) !== null; + $team = $service->team(); + if (! $team) { + return false; + } + + // return $user->isAdmin() && $user->teams->contains('id', $team->id); + return true; } /** @@ -44,11 +51,12 @@ class ServicePolicy */ public function delete(User $user, Service $service): bool { - if ($user->isAdmin()) { - return true; - } + // if ($user->isAdmin()) { + // return true; + // } - return false; + // return false; + return true; } /** @@ -56,6 +64,7 @@ class ServicePolicy */ public function restore(User $user, Service $service): bool { + // return true; return true; } @@ -64,16 +73,23 @@ class ServicePolicy */ public function forceDelete(User $user, Service $service): bool { - if ($user->isAdmin()) { - return true; - } + // if ($user->isAdmin()) { + // return true; + // } - return false; + // return false; + return true; } public function stop(User $user, Service $service): bool { - return $user->teams()->get()->firstWhere('id', $service->team()->first()->id) !== null; + $team = $service->team(); + if (! $team) { + return false; + } + + // return $user->teams->contains('id', $team->id); + return true; } /** @@ -81,7 +97,13 @@ class ServicePolicy */ public function manageEnvironment(User $user, Service $service): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $service->team()->first()->id) !== null; + $team = $service->team(); + if (! $team) { + return false; + } + + // return $user->isAdmin() && $user->teams->contains('id', $team->id); + return true; } /** @@ -89,6 +111,18 @@ class ServicePolicy */ public function deploy(User $user, Service $service): bool { - return $user->teams()->get()->firstWhere('id', $service->team()->first()->id) !== null; + $team = $service->team(); + if (! $team) { + return false; + } + + // return $user->teams->contains('id', $team->id); + return true; + } + + public function accessTerminal(User $user, Service $service): bool + { + // return $user->isAdmin() || $user->teams->contains('id', $service->team()->id); + return true; } } diff --git a/app/Policies/SharedEnvironmentVariablePolicy.php b/app/Policies/SharedEnvironmentVariablePolicy.php new file mode 100644 index 000000000..b465d8a0c --- /dev/null +++ b/app/Policies/SharedEnvironmentVariablePolicy.php @@ -0,0 +1,79 @@ +teams->contains('id', $sharedEnvironmentVariable->team_id); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + // return $user->isAdmin(); + return true; + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, SharedEnvironmentVariable $sharedEnvironmentVariable): bool + { + // return $user->isAdmin() && $user->teams->contains('id', $sharedEnvironmentVariable->team_id); + return true; + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, SharedEnvironmentVariable $sharedEnvironmentVariable): bool + { + // return $user->isAdmin() && $user->teams->contains('id', $sharedEnvironmentVariable->team_id); + return true; + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, SharedEnvironmentVariable $sharedEnvironmentVariable): bool + { + // return $user->isAdmin() && $user->teams->contains('id', $sharedEnvironmentVariable->team_id); + return true; + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, SharedEnvironmentVariable $sharedEnvironmentVariable): bool + { + // return $user->isAdmin() && $user->teams->contains('id', $sharedEnvironmentVariable->team_id); + return true; + } + + /** + * Determine whether the user can manage environment variables. + */ + public function manageEnvironment(User $user, SharedEnvironmentVariable $sharedEnvironmentVariable): bool + { + // return $user->isAdmin() && $user->teams->contains('id', $sharedEnvironmentVariable->team_id); + return true; + } +} diff --git a/app/Policies/StandaloneDockerPolicy.php b/app/Policies/StandaloneDockerPolicy.php index 08d7ea6fe..154648599 100644 --- a/app/Policies/StandaloneDockerPolicy.php +++ b/app/Policies/StandaloneDockerPolicy.php @@ -20,7 +20,7 @@ class StandaloneDockerPolicy */ public function view(User $user, StandaloneDocker $standaloneDocker): bool { - return $user->teams()->get()->firstWhere('id', $standaloneDocker->server->team_id) !== null; + return $user->teams->contains('id', $standaloneDocker->server->team_id); } /** @@ -28,7 +28,8 @@ class StandaloneDockerPolicy */ public function create(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -36,7 +37,8 @@ class StandaloneDockerPolicy */ public function update(User $user, StandaloneDocker $standaloneDocker): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $standaloneDocker->server->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $standaloneDocker->server->team_id); + return true; } /** @@ -44,7 +46,8 @@ class StandaloneDockerPolicy */ public function delete(User $user, StandaloneDocker $standaloneDocker): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $standaloneDocker->server->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $standaloneDocker->server->team_id); + return true; } /** @@ -52,7 +55,8 @@ class StandaloneDockerPolicy */ public function restore(User $user, StandaloneDocker $standaloneDocker): bool { - return false; + // return false; + return true; } /** @@ -60,6 +64,7 @@ class StandaloneDockerPolicy */ public function forceDelete(User $user, StandaloneDocker $standaloneDocker): bool { - return false; + // return false; + return true; } } diff --git a/app/Policies/SwarmDockerPolicy.php b/app/Policies/SwarmDockerPolicy.php index 94ea7a1ee..979bb5889 100644 --- a/app/Policies/SwarmDockerPolicy.php +++ b/app/Policies/SwarmDockerPolicy.php @@ -20,7 +20,7 @@ class SwarmDockerPolicy */ public function view(User $user, SwarmDocker $swarmDocker): bool { - return $user->teams()->get()->firstWhere('id', $swarmDocker->server->team_id) !== null; + return $user->teams->contains('id', $swarmDocker->server->team_id); } /** @@ -28,7 +28,8 @@ class SwarmDockerPolicy */ public function create(User $user): bool { - return $user->isAdmin(); + // return $user->isAdmin(); + return true; } /** @@ -36,7 +37,8 @@ class SwarmDockerPolicy */ public function update(User $user, SwarmDocker $swarmDocker): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $swarmDocker->server->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $swarmDocker->server->team_id); + return true; } /** @@ -44,7 +46,8 @@ class SwarmDockerPolicy */ public function delete(User $user, SwarmDocker $swarmDocker): bool { - return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $swarmDocker->server->team_id) !== null; + // return $user->isAdmin() && $user->teams->contains('id', $swarmDocker->server->team_id); + return true; } /** @@ -52,7 +55,8 @@ class SwarmDockerPolicy */ public function restore(User $user, SwarmDocker $swarmDocker): bool { - return false; + // return false; + return true; } /** @@ -60,6 +64,7 @@ class SwarmDockerPolicy */ public function forceDelete(User $user, SwarmDocker $swarmDocker): bool { - return false; + // return false; + return true; } } diff --git a/app/Policies/TeamPolicy.php b/app/Policies/TeamPolicy.php new file mode 100644 index 000000000..b7ef48943 --- /dev/null +++ b/app/Policies/TeamPolicy.php @@ -0,0 +1,104 @@ +teams->contains('id', $team->id); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + // All authenticated users can create teams + return true; + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, Team $team): bool + { + // Only admins and owners can update team settings + if (! $user->teams->contains('id', $team->id)) { + return false; + } + + // return $user->isAdmin() || $user->isOwner(); + return true; + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, Team $team): bool + { + // Only admins and owners can delete teams + if (! $user->teams->contains('id', $team->id)) { + return false; + } + + // return $user->isAdmin() || $user->isOwner(); + return true; + } + + /** + * Determine whether the user can manage team members. + */ + public function manageMembers(User $user, Team $team): bool + { + // Only admins and owners can manage team members + if (! $user->teams->contains('id', $team->id)) { + return false; + } + + // return $user->isAdmin() || $user->isOwner(); + return true; + } + + /** + * Determine whether the user can view admin panel. + */ + public function viewAdmin(User $user, Team $team): bool + { + // Only admins and owners can view admin panel + if (! $user->teams->contains('id', $team->id)) { + return false; + } + + // return $user->isAdmin() || $user->isOwner(); + return true; + } + + /** + * Determine whether the user can manage invitations. + */ + public function manageInvitations(User $user, Team $team): bool + { + // Only admins and owners can manage invitations + if (! $user->teams->contains('id', $team->id)) { + return false; + } + + // return $user->isAdmin() || $user->isOwner(); + return true; + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 50d21b724..a17d9ec5e 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -23,8 +23,11 @@ class AuthServiceProvider extends ServiceProvider \App\Models\ApplicationPreview::class => \App\Policies\ApplicationPreviewPolicy::class, \App\Models\ApplicationSetting::class => \App\Policies\ApplicationSettingPolicy::class, \App\Models\Service::class => \App\Policies\ServicePolicy::class, + \App\Models\ServiceApplication::class => \App\Policies\ServiceApplicationPolicy::class, + \App\Models\ServiceDatabase::class => \App\Policies\ServiceDatabasePolicy::class, \App\Models\Project::class => \App\Policies\ProjectPolicy::class, \App\Models\Environment::class => \App\Policies\EnvironmentPolicy::class, + \App\Models\SharedEnvironmentVariable::class => \App\Policies\SharedEnvironmentVariablePolicy::class, // Database policies - all use the shared DatabasePolicy \App\Models\StandalonePostgresql::class => \App\Policies\DatabasePolicy::class, \App\Models\StandaloneMysql::class => \App\Policies\DatabasePolicy::class, @@ -35,6 +38,22 @@ class AuthServiceProvider extends ServiceProvider \App\Models\StandaloneDragonfly::class => \App\Policies\DatabasePolicy::class, \App\Models\StandaloneClickhouse::class => \App\Policies\DatabasePolicy::class, + // Notification policies - all use the shared NotificationPolicy + \App\Models\EmailNotificationSettings::class => \App\Policies\NotificationPolicy::class, + \App\Models\DiscordNotificationSettings::class => \App\Policies\NotificationPolicy::class, + \App\Models\TelegramNotificationSettings::class => \App\Policies\NotificationPolicy::class, + \App\Models\SlackNotificationSettings::class => \App\Policies\NotificationPolicy::class, + \App\Models\PushoverNotificationSettings::class => \App\Policies\NotificationPolicy::class, + + // API Token policy + \Laravel\Sanctum\PersonalAccessToken::class => \App\Policies\ApiTokenPolicy::class, + + // Team policy + \App\Models\Team::class => \App\Policies\TeamPolicy::class, + + // Git source policies + \App\Models\GithubApp::class => \App\Policies\GithubAppPolicy::class, + ]; /** @@ -44,5 +63,11 @@ class AuthServiceProvider extends ServiceProvider { // Register gates for resource creation policy Gate::define('createAnyResource', [ResourceCreatePolicy::class, 'createAny']); + + // Register gate for terminal access + Gate::define('canAccessTerminal', function ($user) { + // return $user->isAdmin() || $user->isOwner(); + return true; + }); } } diff --git a/app/View/Components/Forms/Button.php b/app/View/Components/Forms/Button.php index bf88d3f88..b54444261 100644 --- a/app/View/Components/Forms/Button.php +++ b/app/View/Components/Forms/Button.php @@ -4,6 +4,7 @@ namespace App\View\Components\Forms; use Closure; use Illuminate\Contracts\View\View; +use Illuminate\Support\Facades\Gate; use Illuminate\View\Component; class Button extends Component @@ -17,7 +18,19 @@ class Button extends Component public ?string $modalId = null, public string $defaultClass = 'button', public bool $showLoadingIndicator = true, + public ?string $canGate = null, + public mixed $canResource = null, + public bool $autoDisable = true, ) { + // Handle authorization-based disabling + if ($this->canGate && $this->canResource && $this->autoDisable) { + $hasPermission = Gate::allows($this->canGate, $this->canResource); + + if (! $hasPermission) { + $this->disabled = true; + } + } + if ($this->noStyle) { $this->defaultClass = ''; } diff --git a/app/View/Components/Forms/Checkbox.php b/app/View/Components/Forms/Checkbox.php index 8db739642..ece7f0e35 100644 --- a/app/View/Components/Forms/Checkbox.php +++ b/app/View/Components/Forms/Checkbox.php @@ -4,6 +4,7 @@ namespace App\View\Components\Forms; use Closure; use Illuminate\Contracts\View\View; +use Illuminate\Support\Facades\Gate; use Illuminate\View\Component; class Checkbox extends Component @@ -22,7 +23,20 @@ class Checkbox extends Component public string|bool $instantSave = false, public bool $disabled = false, public string $defaultClass = 'dark:border-neutral-700 text-coolgray-400 focus:ring-warning dark:bg-coolgray-100 rounded-sm cursor-pointer dark:disabled:bg-base dark:disabled:cursor-not-allowed', + public ?string $canGate = null, + public mixed $canResource = null, + public bool $autoDisable = true, ) { + // Handle authorization-based disabling + if ($this->canGate && $this->canResource && $this->autoDisable) { + $hasPermission = Gate::allows($this->canGate, $this->canResource); + + if (! $hasPermission) { + $this->disabled = true; + $this->instantSave = false; // Disable instant save for unauthorized users + } + } + if ($this->disabled) { $this->defaultClass .= ' opacity-40'; } diff --git a/app/View/Components/Forms/Input.php b/app/View/Components/Forms/Input.php index a7bd87949..83c98c0df 100644 --- a/app/View/Components/Forms/Input.php +++ b/app/View/Components/Forms/Input.php @@ -4,6 +4,7 @@ namespace App\View\Components\Forms; use Closure; use Illuminate\Contracts\View\View; +use Illuminate\Support\Facades\Gate; use Illuminate\View\Component; use Visus\Cuid2\Cuid2; @@ -26,7 +27,19 @@ class Input extends Component public ?int $minlength = null, public ?int $maxlength = null, public bool $autofocus = false, - ) {} + public ?string $canGate = null, + public mixed $canResource = null, + public bool $autoDisable = true, + ) { + // Handle authorization-based disabling + if ($this->canGate && $this->canResource && $this->autoDisable) { + $hasPermission = Gate::allows($this->canGate, $this->canResource); + + if (! $hasPermission) { + $this->disabled = true; + } + } + } public function render(): View|Closure|string { diff --git a/app/View/Components/Forms/Select.php b/app/View/Components/Forms/Select.php index feb4bf343..49b69136b 100644 --- a/app/View/Components/Forms/Select.php +++ b/app/View/Components/Forms/Select.php @@ -4,6 +4,7 @@ namespace App\View\Components\Forms; use Closure; use Illuminate\Contracts\View\View; +use Illuminate\Support\Facades\Gate; use Illuminate\View\Component; use Visus\Cuid2\Cuid2; @@ -19,9 +20,19 @@ class Select extends Component public ?string $helper = null, public bool $required = false, public bool $disabled = false, - public string $defaultClass = 'select w-full' + public string $defaultClass = 'select w-full', + public ?string $canGate = null, + public mixed $canResource = null, + public bool $autoDisable = true, ) { - // + // Handle authorization-based disabling + if ($this->canGate && $this->canResource && $this->autoDisable) { + $hasPermission = Gate::allows($this->canGate, $this->canResource); + + if (! $hasPermission) { + $this->disabled = true; + } + } } /** diff --git a/app/View/Components/Forms/Textarea.php b/app/View/Components/Forms/Textarea.php index 6081c2a8a..3148d2566 100644 --- a/app/View/Components/Forms/Textarea.php +++ b/app/View/Components/Forms/Textarea.php @@ -4,6 +4,7 @@ namespace App\View\Components\Forms; use Closure; use Illuminate\Contracts\View\View; +use Illuminate\Support\Facades\Gate; use Illuminate\View\Component; use Visus\Cuid2\Cuid2; @@ -33,8 +34,18 @@ class Textarea extends Component public string $defaultClassInput = 'input', public ?int $minlength = null, public ?int $maxlength = null, + public ?string $canGate = null, + public mixed $canResource = null, + public bool $autoDisable = true, ) { - // + // Handle authorization-based disabling + if ($this->canGate && $this->canResource && $this->autoDisable) { + $hasPermission = Gate::allows($this->canGate, $this->canResource); + + if (! $hasPermission) { + $this->disabled = true; + } + } } /** diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index 1a145aa4b..7ec7e4d4c 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -59,20 +59,20 @@ if (this.zoom === '90') { const style = document.createElement('style'); style.textContent = ` - html { - font-size: 93.75%; - } - - :root { - --vh: 1vh; - } - - @media (min-width: 1024px) { - html { - font-size: 87.5%; - } - } - `; + html { + font-size: 93.75%; + } + + :root { + --vh: 1vh; + } + + @media (min-width: 1024px) { + html { + font-size: 87.5%; + } + } + `; document.head.appendChild(style); } } @@ -229,20 +229,22 @@ Tags -
  • - - - - - - - Terminal - -
  • + @can('canAccessTerminal') +
  • + + + + + + + Terminal + +
  • + @endcan
  • Destinations

    @if ($servers->count() > 0) - - - + @can('createAnyResource') + + + + @endcan @endif
    Network endpoints to deploy your resources.
    diff --git a/resources/views/livewire/destination/new/docker.blade.php b/resources/views/livewire/destination/new/docker.blade.php index 1502f70af..795b33e81 100644 --- a/resources/views/livewire/destination/new/docker.blade.php +++ b/resources/views/livewire/destination/new/docker.blade.php @@ -1,18 +1,25 @@ -
    -
    Destinations are used to segregate resources by network.
    -
    -
    - - -
    - - - @foreach ($servers as $server) - - @endforeach - - - Continue - -
    -
    +@can('createAnyResource') +
    +
    Destinations are used to segregate resources by network.
    +
    +
    + + +
    + + + @foreach ($servers as $server) + + @endforeach + + + Continue + +
    +
    +@else +
    +

    You don't have permission to create new destinations.

    +

    Please contact your team administrator for access.

    +
    +@endcan diff --git a/resources/views/livewire/destination/show.blade.php b/resources/views/livewire/destination/show.blade.php index 6c3a9d9dd..f12388770 100644 --- a/resources/views/livewire/destination/show.blade.php +++ b/resources/views/livewire/destination/show.blade.php @@ -2,14 +2,14 @@

    Destination

    - - Save - + Save @if ($network !== 'coolify') + shortConfirmationLabel="Destination Name" :confirmWithPassword="false" step2ButtonText="Permanently Delete" + canGate="delete" :canResource="$destination" /> @endif
    @@ -19,7 +19,7 @@
    A swarm Docker network. WIP
    @endif
    - + @if ($destination->getMorphClass() === 'App\Models\StandaloneDocker') diff --git a/resources/views/livewire/notifications/discord.blade.php b/resources/views/livewire/notifications/discord.blade.php index 4118af5f1..dbf56b027 100644 --- a/resources/views/livewire/notifications/discord.blade.php +++ b/resources/views/livewire/notifications/discord.blade.php @@ -6,27 +6,27 @@

    Discord

    - + Save @if ($discordEnabled) - Send Test Notification @else - + Send Test Notification @endif
    - - +
    - @@ -38,11 +38,11 @@

    Deployments

    - - -
    @@ -50,35 +50,35 @@

    Backups

    - -

    Scheduled Tasks

    - -

    Server

    - - - - - -
    diff --git a/resources/views/livewire/notifications/email.blade.php b/resources/views/livewire/notifications/email.blade.php index 74380f2cd..a3b46fc89 100644 --- a/resources/views/livewire/notifications/email.blade.php +++ b/resources/views/livewire/notifications/email.blade.php @@ -6,41 +6,43 @@

    Email

    - + Save @if (auth()->user()->isAdminFromSession()) - @if ($team->isNotificationEnabled('email')) - - - - - Send Email - - - - @else - - Send Test Email - - @endif + @can('sendTest', $settings) + @if ($team->isNotificationEnabled('email')) + +
    + + + Send Email + + +
    + @else + + Send Test Email + + @endif + @endcan @endif
    @if (!isCloud())
    -
    @endif @if (!$useInstanceEmailSettings)
    - - +
    @if (isInstanceAdmin() && !$useInstanceEmailSettings) - + Copy from Instance Settings @endif @@ -48,7 +50,7 @@ @if (isCloud())
    -
    @endif @@ -58,29 +60,29 @@ class="p-4 border dark:border-coolgray-300 border-neutral-200 flex flex-col gap-2">

    SMTP Server

    - + Save
    -
    - - - + + +
    - - - + +
    @@ -90,18 +92,18 @@ class="p-4 border dark:border-coolgray-300 border-neutral-200 flex flex-col gap-2">

    Resend

    - + Save
    -
    -
    @@ -117,11 +119,11 @@

    Deployments

    - - -
    @@ -129,35 +131,35 @@

    Backups

    - -

    Scheduled Tasks

    - -

    Server

    - - - - - -
    diff --git a/resources/views/livewire/notifications/pushover.blade.php b/resources/views/livewire/notifications/pushover.blade.php index f0123a070..8c967030f 100644 --- a/resources/views/livewire/notifications/pushover.blade.php +++ b/resources/views/livewire/notifications/pushover.blade.php @@ -6,28 +6,28 @@

    Pushover

    - + Save @if ($pushoverEnabled) - Send Test Notification @else - + Send Test Notification @endif
    - +
    - -
    @@ -40,11 +40,11 @@

    Deployments

    - - -
    @@ -52,35 +52,35 @@

    Backups

    - -

    Scheduled Tasks

    - -

    Server

    - - - - - -
    diff --git a/resources/views/livewire/notifications/slack.blade.php b/resources/views/livewire/notifications/slack.blade.php index 22c145460..ce4dd5d2d 100644 --- a/resources/views/livewire/notifications/slack.blade.php +++ b/resources/views/livewire/notifications/slack.blade.php @@ -6,24 +6,24 @@

    Slack

    - + Save @if ($slackEnabled) - Send Test Notification @else - + Send Test Notification @endif
    - +
    - @@ -35,11 +35,11 @@

    Deployments

    - - -
    @@ -47,33 +47,33 @@

    Backups

    - - + +

    Scheduled Tasks

    - -

    Server

    - - - - - - +
    diff --git a/resources/views/livewire/notifications/telegram.blade.php b/resources/views/livewire/notifications/telegram.blade.php index d4312f8d2..7b07b4e22 100644 --- a/resources/views/livewire/notifications/telegram.blade.php +++ b/resources/views/livewire/notifications/telegram.blade.php @@ -6,28 +6,28 @@

    Telegram

    - + Save @if ($telegramEnabled) - Send Test Notification @else - + Send Test Notification @endif
    - +
    - -
    @@ -42,27 +42,27 @@
    -
    -
    -
    -
    -
    -
    @@ -72,19 +72,19 @@
    -
    -
    -
    -
    @@ -95,19 +95,19 @@
    -
    -
    -
    -
    @@ -118,55 +118,55 @@
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    diff --git a/resources/views/livewire/project/application/advanced.blade.php b/resources/views/livewire/project/application/advanced.blade.php index df2b49d48..6dd5c872c 100644 --- a/resources/views/livewire/project/application/advanced.blade.php +++ b/resources/views/livewire/project/application/advanced.blade.php @@ -8,76 +8,73 @@

    General

    @if ($application->git_based()) + id="isAutoDeployEnabled" label="Auto Deploy" canGate="update" :canResource="$application" /> + instantSave id="isPreviewDeploymentsEnabled" label="Preview Deployments" canGate="update" + :canResource="$application" /> @endif - + @if ($application->settings->is_container_label_readonly_enabled) + instantSave id="isForceHttpsEnabled" label="Force Https" canGate="update" :canResource="$application" /> + instantSave id="isGzipEnabled" canGate="update" :canResource="$application" /> + instantSave id="isStripprefixEnabled" label="Strip Prefixes" canGate="update" :canResource="$application" /> @else + id="isForceHttpsEnabled" label="Force Https" canGate="update" :canResource="$application" /> + id="isGzipEnabled" canGate="update" :canResource="$application" /> + instantSave id="isStripprefixEnabled" label="Strip Prefixes" canGate="update" :canResource="$application" /> @endif @if ($application->build_pack === 'dockercompose')

    Docker Compose

    + helper="WARNING: Advanced use cases only. Your docker compose file will be deployed as-is. Nothing is modified by Coolify. You need to configure the proxy parts. More info in the
    documentation." + canGate="update" :canResource="$application" /> @endif

    Container Names

    + instantSave id="isConsistentContainerNameEnabled" label="Consistent Container Names" canGate="update" + :canResource="$application" /> @if ($isConsistentContainerNameEnabled === false) - @can('update', $application) - - Save - - @else - - Save - - @endcan + instantSave id="customInternalName" label="Custom Container Name" canGate="update" + :canResource="$application" /> + Save @endif @if ($application->build_pack === 'dockercompose')

    Network

    + helper="By default, you do not reach the Coolify defined networks.
    Starting a docker compose based resource will have an internal network.
    If you connect to a Coolify defined network, you maybe need to use different internal DNS names to connect to a resource.

    For more information, check this." + canGate="update" :canResource="$application" /> @endif

    Logs

    + instantSave id="isLogDrainEnabled" label="Drain Logs" canGate="update" :canResource="$application" /> @if ($application->git_based())

    Git

    + helper="Allow Git Submodules during build process." canGate="update" :canResource="$application" /> + helper="Allow Git LFS during build process." canGate="update" :canResource="$application" /> + helper="Use shallow cloning (--depth=1) to speed up deployments by only fetching the latest commit history. This reduces clone time and resource usage, especially for large repositories." + canGate="update" :canResource="$application" /> @endif
    @@ -87,16 +84,7 @@

    GPU

    @if ($isGpuEnabled) - @can('update', $application) - - Save - - @else - - Save - - @endcan + Save @endif
    @endif @@ -104,21 +92,23 @@
    + instantSave id="isGpuEnabled" label="Enable GPU" canGate="update" :canResource="$application" />
    @endif @if ($isGpuEnabled)
    - - + + +
    - - + id="gpuDeviceIds" canGate="update" :canResource="$application"> +
    @endif diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php index b473286f0..b833fc7bb 100644 --- a/resources/views/livewire/project/application/general.blade.php +++ b/resources/views/livewire/project/application/general.blade.php @@ -1,56 +1,35 @@ -
    +

    General

    - @can('update', $application) - - Save - - @else - - Save - - @endcan - - {{-- - Download Config - --}} - {{-- - - --}} - + Save
    General configuration for your application.
    - - + +
    @if (!$application->dockerfile && $application->build_pack !== 'dockerimage')
    - @can('update', $application) - - - - - - - @else - - - - - - - @endcan + + + + + + @if ($application->settings->is_static || $application->build_pack === 'static') - + @@ -69,7 +48,8 @@ + id="parsedServiceDomains.{{ str($serviceName)->slug('_') }}.domain" + x-bind:disabled="shouldDisable()"> @can('update', $application) Generate Domain @@ -85,27 +65,23 @@ @if ($application->settings->is_static || $application->build_pack === 'static') + helper="You can add custom Nginx configuration here." x-bind:disabled="!canUpdate" /> @can('update', $application) Generate Default Nginx Configuration - @else - - Generate Default Nginx Configuration - @endcan @endif
    @if ($application->could_set_build_commands()) + helper="If your application is a static site or the final build assets should be served as a static site, enable this." + x-bind:disabled="!canUpdate" /> @endif @if ($application->settings->is_static && $application->build_pack !== 'static') + helper="If your application is a SPA, enable this." id="application.settings.is_spa" instantSave + x-bind:disabled="!canUpdate"> @endif
    @if ($application->build_pack !== 'dockercompose') @@ -113,11 +89,13 @@ @if ($application->settings->is_container_label_readonly_enabled == false) + helper="Readonly labels are disabled. You can set the domains in the labels section." + x-bind:disabled="!canUpdate" /> @else + helper="You can specify one domain with path or more with comma. You can specify a port to bind the domain to.

    Example
    - http://app.coolify.io,https://cloud.coolify.io/dashboard
    - http://app.coolify.io/api/v3
    - http://app.coolify.io:3000 -> app.coolify.io will point to port 3000 inside the container. " + x-bind:disabled="!canUpdate" /> @can('update', $application) Generate Domain @@ -128,32 +106,38 @@ @if ($application->settings->is_container_label_readonly_enabled == false) @if ($application->redirect === 'both') + helper="Readonly labels are disabled. You can set the direction in the labels section." + x-bind:disabled="!canUpdate" /> @elseif ($application->redirect === 'www') + helper="Readonly labels are disabled. You can set the direction in the labels section." + x-bind:disabled="!canUpdate" /> @elseif ($application->redirect === 'non-www') + helper="Readonly labels are disabled. You can set the direction in the labels section." + x-bind:disabled="!canUpdate" /> @endif @else + helper="You must need to add www and non-www as an A DNS record. Make sure the www domain is added under Domains." + x-bind:disabled="!canUpdate"> @if ($application->settings->is_container_label_readonly_enabled) - - -
    Set Direction
    -
    -
    + @can('update', $application) + + +
    Set Direction
    +
    +
    + @endcan @endif @endif
    @@ -177,11 +161,15 @@
    @if ($application->build_pack === 'dockerimage') @if ($application->destination->server->isSwarm()) - - + + @else - - + + @endif @else @if ( @@ -189,19 +177,20 @@ $application->additional_servers->count() > 0 || $application->settings->is_build_server_enabled) + placeholder="Required!" x-bind:disabled="!canUpdate" /> + placeholder="Empty means latest will be used." label="Docker Image Tag" + x-bind:disabled="!canUpdate" /> @else + label="Docker Image" x-bind:disabled="!canUpdate" /> + label="Docker Image Tag" x-bind:disabled="!canUpdate" /> @endif @endif
    @@ -212,17 +201,21 @@ + id="application.custom_docker_run_options" label="Custom Docker Options" + x-bind:disabled="!canUpdate" /> @else @if ($application->could_set_build_commands()) @if ($application->build_pack === 'nixpacks')
    + id="application.install_command" label="Install Command" + x-bind:disabled="!canUpdate" /> + id="application.build_command" label="Build Command" + x-bind:disabled="!canUpdate" /> + id="application.start_command" label="Start Command" + x-bind:disabled="!canUpdate" />
    Nixpacks will detect the required configuration automatically. @@ -240,10 +233,10 @@
    @endcan
    - - @@ -252,7 +245,8 @@ + helper="Git repository (based on the base directory settings) will be copied to the deployment directory." + x-bind:disabled="shouldDisable()" />
    The following commands are for advanced use cases. Only @@ -260,13 +254,13 @@ know what are you doing.
    - - @@ -276,25 +270,28 @@
    + helper="Directory to use as root. Useful for monorepos." + x-bind:disabled="!canUpdate" /> @if ($application->build_pack === 'dockerfile' && !$application->dockerfile) + helper="It is calculated together with the Base Directory:
    {{ Str::start($application->base_directory . $application->dockerfile_location, '/') }}" + x-bind:disabled="!canUpdate" /> @endif @if ($application->build_pack === 'dockerfile') + helper="Useful if you have multi-staged dockerfile." + x-bind:disabled="!canUpdate" /> @endif @if ($application->could_set_build_commands()) @if ($application->settings->is_static) + label="Publish Directory" required x-bind:disabled="!canUpdate" /> @else + label="Publish Directory" x-bind:disabled="!canUpdate" /> @endif @endif @@ -304,20 +301,21 @@ + label="Watch Paths" x-bind:disabled="!canUpdate" />
    @endif + id="application.custom_docker_run_options" label="Custom Docker Options" + x-bind:disabled="!canUpdate" /> @if ($application->build_pack !== 'dockercompose')
    + label="Use a Build Server?" x-bind:disabled="!canUpdate" />
    @endif @endif @@ -327,8 +325,10 @@ @if ($application->build_pack === 'dockercompose')

    Docker Compose

    - Reload Compose File + @can('update', $application) + Reload Compose File + @endcan
    @if ($application->settings->is_raw_compose_deployment_enabled) + id="application.settings.is_container_label_escape_enabled" instantSave + x-bind:disabled="!canUpdate"> {{-- --}} @@ -358,32 +359,36 @@ @endif @if ($application->dockerfile) + useMonacoEditor rows="6" x-bind:disabled="!canUpdate"> @endif @if ($application->build_pack !== 'dockercompose')

    Network

    @if ($application->settings->is_static || $application->build_pack === 'static') - + @else @if ($application->settings->is_container_label_readonly_enabled === false) + helper="Readonly labels are disabled. You can set the ports manually in the labels section." + x-bind:disabled="!canUpdate" /> @else + helper="A comma separated list of ports your application uses. The first port will be used as default healthcheck port if nothing defined in the Healthcheck menu. Be sure to set this correctly." + x-bind:disabled="!canUpdate" /> @endif @endif @if (!$application->destination->server->isSwarm()) + helper="A comma separated list of ports you would like to map to the host system. Useful when you do not want to use domains.

    Example:
    3000:3000,3002:3002

    Rolling update is not supported if you have a port mapped to the host." + x-bind:disabled="!canUpdate" /> @endif @if (!$application->destination->server->isSwarm()) + wire:model="application.custom_network_aliases" x-bind:disabled="!canUpdate" /> @endif
    @@ -391,60 +396,66 @@
    + label="Enable" id="application.is_http_basic_auth_enabled" + x-bind:disabled="!canUpdate" />
    @if ($application->is_http_basic_auth_enabled)
    - + + required x-bind:disabled="!canUpdate" />
    @endif
    @if ($application->settings->is_container_label_readonly_enabled) + monacoEditorLanguage="ini" useMonacoEditor x-bind:disabled="!canUpdate"> @else + monacoEditorLanguage="ini" useMonacoEditor x-bind:disabled="!canUpdate"> @endif
    + id="application.settings.is_container_label_readonly_enabled" instantSave + x-bind:disabled="!canUpdate"> + id="application.settings.is_container_label_escape_enabled" instantSave + x-bind:disabled="!canUpdate">
    - + @can('update', $application) + + @endcan @endif

    Pre/Post Deployment Commands

    - @if ($application->build_pack === 'dockercompose') - @endif
    - @if ($application->build_pack === 'dockercompose') - @endif diff --git a/resources/views/livewire/project/application/heading.blade.php b/resources/views/livewire/project/application/heading.blade.php index 2b44e0ddd..1a8812929 100644 --- a/resources/views/livewire/project/application/heading.blade.php +++ b/resources/views/livewire/project/application/heading.blade.php @@ -15,10 +15,12 @@ Logs @if (!$application->destination->server->isSwarm()) - - Terminal - + @can('canAccessTerminal') + + Terminal + + @endcan @endif diff --git a/resources/views/livewire/project/application/preview/form.blade.php b/resources/views/livewire/project/application/preview/form.blade.php index a273de810..e00d824ef 100644 --- a/resources/views/livewire/project/application/preview/form.blade.php +++ b/resources/views/livewire/project/application/preview/form.blade.php @@ -1,13 +1,15 @@

    Preview Deployments

    - Save - Reset template to default + @can('update', $application) + Save + Reset template to default + @endcan
    Preview Deployments based on pull requests are here.
    + helper="Templates:
    @@{{ random }} to generate random sub-domain each time a PR is deployed
    @@{{ pr_id }} to use pull request ID as sub-domain or @@{{ domain }} to replace the domain name with the application's domain name." canGate="update" :canResource="$application" /> @if ($previewUrlTemplate)
    Domain Preview: {{ $previewUrlTemplate }}
    @endif diff --git a/resources/views/livewire/project/application/previews-compose.blade.php b/resources/views/livewire/project/application/previews-compose.blade.php index 4e50ad18d..ffed66814 100644 --- a/resources/views/livewire/project/application/previews-compose.blade.php +++ b/resources/views/livewire/project/application/previews-compose.blade.php @@ -1,6 +1,6 @@ + id="service.domain" canGate="update" :canResource="$preview->application">
    Save Generate Domain diff --git a/resources/views/livewire/project/application/previews.blade.php b/resources/views/livewire/project/application/previews.blade.php index 5decc26cf..6a2ef485f 100644 --- a/resources/views/livewire/project/application/previews.blade.php +++ b/resources/views/livewire/project/application/previews.blade.php @@ -7,9 +7,11 @@
    @if ($application->is_github_based())
    -

    Pull Requests on Git

    - Load Pull Requests - + @can('update', $application) +

    Pull Requests on Git

    + Load Pull Requests + + @endcan
    @endif @isset($rate_limit_remaining) @@ -40,19 +42,23 @@ - - Configure - - - - - - Deploy - + @can('update', $application) + + Configure + + @endcan + @can('deploy', $application) + + + + + Deploy + + @endcan @endforeach @@ -106,10 +112,12 @@ - Save - Generate - Domain + id="application.previews.{{ $previewName }}.fqdn" canGate="update" :canResource="$application"> + @can('update', $application) + Save + Generate + Domain + @endcan @else @foreach (collect(json_decode($preview->docker_compose_domains)) as $serviceName => $service) @@ -122,82 +130,90 @@ @else
    - Save - Generate - Domain + id="application.previews.{{ $previewName }}.fqdn" canGate="update" :canResource="$application"> + @can('update', $application) + Save + Generate + Domain + @endcan
    @endif
    - - - - - - - - - Force deploy (without - cache) - - - @if (data_get($preview, 'status') === 'exited') - + @can('deploy', $application) + + - - - Deploy - @else - - - - - Redeploy - @endif - - @if (data_get($preview, 'status') !== 'exited') - - - + + + + + Force deploy (without + cache) + + + @if (data_get($preview, 'status') === 'exited') + + + + + Deploy + @else + + d="M10.09 4.01l.496 -.495a2 2 0 0 1 2.828 0l7.071 7.07a2 2 0 0 1 0 2.83l-7.07 7.07a2 2 0 0 1 -2.83 0l-7.07 -7.07a2 2 0 0 1 0 -2.83l3.535 -3.535h-3.988"> - - - - Stop - - + + Redeploy + @endif + + @endcan + @if (data_get($preview, 'status') !== 'exited') + @can('deploy', $application) + + + + + + + + + + Stop + + + @endcan @endif - + @can('delete', $application) + + @endcan
    @endforeach diff --git a/resources/views/livewire/project/application/rollback.blade.php b/resources/views/livewire/project/application/rollback.blade.php index cf4467534..1844316f9 100644 --- a/resources/views/livewire/project/application/rollback.blade.php +++ b/resources/views/livewire/project/application/rollback.blade.php @@ -1,7 +1,9 @@

    Rollback

    - Reload Available Images + @can('view', $application) + Reload Available Images + @endcan
    You can easily rollback to a previously built (local) images quickly.
    @@ -26,16 +28,18 @@
    {{ $date }}
    - @if (data_get($image, 'is_current')) - - Rollback - - @else - - Rollback - - @endif + @can('deploy', $application) + @if (data_get($image, 'is_current')) + + Rollback + + @else + + Rollback + + @endif + @endcan
    diff --git a/resources/views/livewire/project/application/source.blade.php b/resources/views/livewire/project/application/source.blade.php index 85382055e..9e746fadb 100644 --- a/resources/views/livewire/project/application/source.blade.php +++ b/resources/views/livewire/project/application/source.blade.php @@ -2,7 +2,9 @@

    Source

    - Save + @can('update', $application) + Save + @endcan Open Repository @@ -32,11 +34,11 @@
    @endif
    - - + +
    - +
    @@ -46,45 +48,49 @@ class="dark:text-warning">{{ $privateKeyName }}
    -

    Select another Private Key

    -
    - @foreach ($privateKeys as $key) - {{ $key->name }} - - @endforeach -
    - @else -
    -

    Change Git Source

    -
    - @forelse ($sources as $source) -
    - - -
    -
    - {{ $source->name }} - @if ($application->source_id === $source->id) - (current) - @endif -
    -
    - {{ $source->organization ?? 'Personal Account' }} -
    -
    -
    -
    -
    - @empty -
    No other sources found
    - @endforelse + @can('update', $application) +

    Select another Private Key

    +
    + @foreach ($privateKeys as $key) + {{ $key->name }} + + @endforeach
    -
    + @endcan + @else + @can('update', $application) +
    +

    Change Git Source

    +
    + @forelse ($sources as $source) +
    + + +
    +
    + {{ $source->name }} + @if ($application->source_id === $source->id) + (current) + @endif +
    +
    + {{ $source->organization ?? 'Personal Account' }} +
    +
    +
    +
    +
    + @empty +
    No other sources found
    + @endforelse +
    +
    + @endcan @endif
    diff --git a/resources/views/livewire/project/application/swarm.blade.php b/resources/views/livewire/project/application/swarm.blade.php index 1822f948b..a7da02627 100644 --- a/resources/views/livewire/project/application/swarm.blade.php +++ b/resources/views/livewire/project/application/swarm.blade.php @@ -15,14 +15,14 @@
    - + + id="isSwarmOnlyWorkerNodes" label="Only Start on Worker nodes" canGate="update" :canResource="$application" />
    + - 'node.role == worker'" canGate="update" :canResource="$application" />
    diff --git a/resources/views/livewire/project/database/backup/index.blade.php b/resources/views/livewire/project/database/backup/index.blade.php index 91f0676aa..05a0ce04e 100644 --- a/resources/views/livewire/project/database/backup/index.blade.php +++ b/resources/views/livewire/project/database/backup/index.blade.php @@ -8,9 +8,11 @@

    Scheduled Backups

    - - - + @can('update', $database) + + + + @endcan
    diff --git a/resources/views/livewire/project/database/clickhouse/general.blade.php b/resources/views/livewire/project/database/clickhouse/general.blade.php index e91663f35..9017f7c09 100644 --- a/resources/views/livewire/project/database/clickhouse/general.blade.php +++ b/resources/views/livewire/project/database/clickhouse/general.blade.php @@ -2,54 +2,56 @@

    General

    - + Save
    - - - + +
    @if ($database->started_at)
    + readonly helper="You can only change this in the database." canGate="update" :canResource="$database" /> + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    @else
    Please verify these values. You can only modify them before the initial start. After that, you need to modify it in the database.
    - - + +
    @endif + id="customDockerRunOptions" label="Custom Docker Options" canGate="update" :canResource="$database" />

    Network

    + helper="A comma separated list of ports you would like to map to the host system.
    Example3000:5432,3002:5433" + canGate="update" :canResource="$database" />
    + type="password" readonly wire:model="dbUrl" canGate="update" :canResource="$database" /> @if ($dbUrlPublic) + type="password" readonly wire:model="dbUrlPublic" canGate="update" :canResource="$database" /> @else + readonly value="Starting the database will generate this." canGate="update" :canResource="$database" /> @endif
    @@ -71,14 +73,17 @@ @endif
    - +
    - +

    Advanced

    + instantSave="instantSaveAdvanced" id="isLogDrainEnabled" label="Drain Logs" canGate="update" + :canResource="$database" />
    diff --git a/resources/views/livewire/project/database/configuration.blade.php b/resources/views/livewire/project/database/configuration.blade.php index 5e1600461..a57f0fac2 100644 --- a/resources/views/livewire/project/database/configuration.blade.php +++ b/resources/views/livewire/project/database/configuration.blade.php @@ -17,9 +17,11 @@ Persistent Storage - Import - Backups + @can('update', $database) + Import + Backups + @endcan Webhooks

    General

    - + Save
    - - - + + +
    + id="customDockerRunOptions" label="Custom Docker Options" canGate="update" :canResource="$database" /> @if ($database->started_at)
    + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    @else
    Please verify these values. You can only modify them before the initial start. After that, you need to modify it in the database.
    - +
    @endif

    Network

    + helper="A comma separated list of ports you would like to map to the host system.
    Example3000:5432,3002:5433" + canGate="update" :canResource="$database" />
    + type="password" readonly wire:model="dbUrl" canGate="update" :canResource="$database" /> @if ($dbUrlPublic) + type="password" readonly wire:model="dbUrlPublic" canGate="update" :canResource="$database" /> @else + readonly value="Starting the database will generate this." canGate="update" :canResource="$database" /> @endif
    @@ -79,11 +81,12 @@
    @if (str($database->status)->contains('exited')) + instantSave="instantSaveSSL" canGate="update" :canResource="$database" /> @else + helper="Database should be stopped to change this settings." canGate="update" + :canResource="$database" /> @endif
    @@ -107,14 +110,17 @@ @endif
    - +
    - +

    Advanced

    + instantSave="instantSaveAdvanced" id="isLogDrainEnabled" label="Drain Logs" canGate="update" + :canResource="$database" />
    diff --git a/resources/views/livewire/project/database/heading.blade.php b/resources/views/livewire/project/database/heading.blade.php index 3df3b0e53..b09adcc4e 100644 --- a/resources/views/livewire/project/database/heading.blade.php +++ b/resources/views/livewire/project/database/heading.blade.php @@ -18,10 +18,12 @@ href="{{ route('project.database.logs', $parameters) }}"> Logs - - Terminal - + @can('canAccessTerminal') + + Terminal + + @endcan @if ( $database->getMorphClass() === 'App\Models\StandalonePostgresql' || $database->getMorphClass() === 'App\Models\StandaloneMongodb' || diff --git a/resources/views/livewire/project/database/import.blade.php b/resources/views/livewire/project/database/import.blade.php index d7baf602f..c6501e031 100644 --- a/resources/views/livewire/project/database/import.blade.php +++ b/resources/views/livewire/project/database/import.blade.php @@ -108,8 +108,8 @@
    Location: /
    Restore Backup
    -
    - +
    +
    @else
    Database must be running to restore a backup.
    diff --git a/resources/views/livewire/project/database/keydb/general.blade.php b/resources/views/livewire/project/database/keydb/general.blade.php index 065303f75..a4b0eb471 100644 --- a/resources/views/livewire/project/database/keydb/general.blade.php +++ b/resources/views/livewire/project/database/keydb/general.blade.php @@ -2,51 +2,53 @@

    General

    - + Save
    - - - + +
    @if ($database->started_at)
    + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    @else
    Please verify these values. You can only modify them before the initial start. After that, you need to modify it in the database.
    - +
    @endif + id="customDockerRunOptions" label="Custom Docker Options" canGate="update" :canResource="$database" />

    Network

    + helper="A comma separated list of ports you would like to map to the host system.
    Example3000:5432,3002:5433" + canGate="update" :canResource="$database" />
    + type="password" readonly wire:model="dbUrl" canGate="update" :canResource="$database" /> @if ($dbUrlPublic) + type="password" readonly wire:model="dbUrlPublic" canGate="update" :canResource="$database" /> @else + readonly value="Starting the database will generate this." canGate="update" :canResource="$database" /> @endif
    @@ -79,11 +81,12 @@
    @if (str($database->status)->contains('exited')) + instantSave="instantSaveSSL" canGate="update" :canResource="$database" /> @else + helper="Database should be stopped to change this settings." canGate="update" + :canResource="$database" /> @endif
    @@ -107,17 +110,20 @@ @endif
    - +
    - + + label="Custom KeyDB Configuration" rows="10" id="keydbConf" canGate="update" :canResource="$database" />

    Advanced

    + instantSave="instantSaveAdvanced" id="isLogDrainEnabled" label="Drain Logs" canGate="update" + :canResource="$database" />
    diff --git a/resources/views/livewire/project/database/mariadb/general.blade.php b/resources/views/livewire/project/database/mariadb/general.blade.php index 6186e4a82..fdc659408 100644 --- a/resources/views/livewire/project/database/mariadb/general.blade.php +++ b/resources/views/livewire/project/database/mariadb/general.blade.php @@ -2,14 +2,14 @@

    General

    - + Save
    - - - + +
    If you change the values in the database, please sync it here, otherwise @@ -18,11 +18,14 @@ @if ($database->started_at)
    + helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." + canGate="update" :canResource="$database" /> + helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." + canGate="update" :canResource="$database" /> + helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." + canGate="update" :canResource="$database" />
    + helper="You can only change this in the database." canGate="update" :canResource="$database" /> + helper="You can only change this in the database." canGate="update" :canResource="$database" /> + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    @endif
    + id="database.custom_docker_run_options" label="Custom Docker Options" canGate="update" + :canResource="$database" />

    Network

    + helper="A comma separated list of ports you would like to map to the host system.
    Example3000:5432,3002:5433" + canGate="update" :canResource="$database" />
    + type="password" readonly wire:model="db_url" canGate="update" :canResource="$database" /> @if ($db_url_public) + type="password" readonly wire:model="db_url_public" canGate="update" :canResource="$database" /> @endif
    @@ -98,11 +103,13 @@
    @if (str($database->status)->contains('exited')) + wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" canGate="update" + :canResource="$database" /> @else + helper="Database should be stopped to change this settings." canGate="update" + :canResource="$database" /> @endif
    @@ -127,16 +134,19 @@ @endif - + + id="database.public_port" label="Public Port" canGate="update" :canResource="$database" /> - +

    Advanced

    + instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" + canGate="update" :canResource="$database" />
    diff --git a/resources/views/livewire/project/database/mongodb/general.blade.php b/resources/views/livewire/project/database/mongodb/general.blade.php index c92143336..2892e721e 100644 --- a/resources/views/livewire/project/database/mongodb/general.blade.php +++ b/resources/views/livewire/project/database/mongodb/general.blade.php @@ -2,14 +2,14 @@

    General

    - + Save
    - - - + +
    If you change the values in the database, please sync it here, otherwise @@ -19,40 +19,44 @@
    + helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." + canGate="update" :canResource="$database" /> + helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." + canGate="update" :canResource="$database" /> + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    @else
    - + placeholder="If empty: postgres" canGate="update" :canResource="$database" /> + + placeholder="If empty, it will be the same as Username." canGate="update" :canResource="$database" />
    @endif + id="database.custom_docker_run_options" label="Custom Docker Options" canGate="update" :canResource="$database" />

    Network

    + helper="A comma separated list of ports you would like to map to the host system.
    Example3000:5432,3002:5433" + canGate="update" :canResource="$database" />
    + type="password" readonly wire:model="db_url" canGate="update" :canResource="$database" /> @if ($db_url_public) + type="password" readonly wire:model="db_url_public" canGate="update" :canResource="$database" /> @endif
    @@ -88,11 +92,13 @@
    @if (str($database->status)->contains('exited')) + wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" canGate="update" + :canResource="$database" /> @else + helper="Database should be stopped to change this settings." canGate="update" + :canResource="$database" /> @endif
    @if ($database->enable_ssl) @@ -100,7 +106,8 @@ @if (str($database->status)->contains('exited')) + helper="Choose the SSL verification mode for MongoDB connections" canGate="update" + :canResource="$database"> @@ -109,7 +116,8 @@ @else + disabled helper="Database should be stopped to change this settings." canGate="update" + :canResource="$database"> @@ -140,16 +148,20 @@ @endif
    - + + id="database.public_port" label="Public Port" canGate="update" :canResource="$database" /> - +

    Advanced

    + instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" + canGate="update" :canResource="$database" />
    + diff --git a/resources/views/livewire/project/database/mysql/general.blade.php b/resources/views/livewire/project/database/mysql/general.blade.php index c9090a4db..c04119f9f 100644 --- a/resources/views/livewire/project/database/mysql/general.blade.php +++ b/resources/views/livewire/project/database/mysql/general.blade.php @@ -7,10 +7,10 @@
    - - + + + helper="For all available images, check here:

    https://hub.docker.com/_/mysql" canGate="update" :canResource="$database" />
    If you change the values in the database, please sync it here, otherwise automations (like backups) won't work. @@ -18,43 +18,43 @@ @if ($database->started_at)
    + helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." canGate="update" :canResource="$database" /> + helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." canGate="update" :canResource="$database" /> + helper="If you change this in the database, please sync it here, otherwise automations (like backups) won't work." canGate="update" :canResource="$database" />
    + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    @else
    + helper="You can only change this in the database." canGate="update" :canResource="$database" /> + helper="You can only change this in the database." canGate="update" :canResource="$database" /> + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    @endif
    + id="database.custom_docker_run_options" label="Custom Docker Options" canGate="update" :canResource="$database" />

    Network

    + helper="A comma separated list of ports you would like to map to the host system.
    Example3000:5432,3002:5433" canGate="update" :canResource="$database" />
    @if (str($database->status)->contains('exited')) + wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" canGate="update" :canResource="$database" /> @else status)->contains('exited')) + helper="Choose the SSL verification mode for MySQL connections" canGate="update" :canResource="$database"> @@ -151,16 +151,16 @@ @endif
    - +
    + id="database.public_port" label="Public Port" canGate="update" :canResource="$database" /> - +

    Advanced

    + instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" canGate="update" :canResource="$database" />
    diff --git a/resources/views/livewire/project/database/postgresql/general.blade.php b/resources/views/livewire/project/database/postgresql/general.blade.php index 50575f6c7..d93170edf 100644 --- a/resources/views/livewire/project/database/postgresql/general.blade.php +++ b/resources/views/livewire/project/database/postgresql/general.blade.php @@ -16,14 +16,14 @@

    General

    - + Save
    - - - + +
    If you change the values in the database, please sync it here, otherwise @@ -32,8 +32,10 @@ @if ($database->started_at)
    @else
    - - + + + placeholder="If empty, it will be the same as Username." canGate="update" :canResource="$database" />
    @endif
    - - + +
    + id="database.custom_docker_run_options" label="Custom Docker Options" canGate="update" :canResource="$database" />

    Network

    + helper="A comma separated list of ports you would like to map to the host system.
    Example3000:5432,3002:5433" + canGate="update" :canResource="$database" />
    + ]" submitAction="regenerateSslCertificate" :confirmWithText="false" + :confirmWithPassword="false" /> @endif
    @if ($database->enable_ssl && $certificateValidUntil) @@ -102,7 +108,8 @@
    @if ($database->isExited()) + wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" canGate="update" + :canResource="$database" /> @else isExited()) + helper="Choose the SSL verification mode for PostgreSQL connections" canGate="update" + :canResource="$database"> @@ -153,15 +161,16 @@ @endif
    - +
    + id="database.public_port" label="Public Port" canGate="update" :canResource="$database" />
    + id="database.postgres_conf" canGate="update" :canResource="$database" />
    @@ -169,23 +178,27 @@

    Advanced

    + instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" + canGate="update" :canResource="$database" />
    +

    Initialization scripts

    - -
    - - - - Save - - -
    + @can('update', $database) + +
    + + + + Save + + +
    + @endcan
    @forelse(data_get($database,'init_scripts', []) as $script) diff --git a/resources/views/livewire/project/database/redis/general.blade.php b/resources/views/livewire/project/database/redis/general.blade.php index b4876f325..66e913be0 100644 --- a/resources/views/livewire/project/database/redis/general.blade.php +++ b/resources/views/livewire/project/database/redis/general.blade.php @@ -2,14 +2,14 @@

    General

    - + Save
    - - - + +
    @@ -21,10 +21,10 @@
    @if (version_compare($redis_version, '6.0', '>=')) + helper="You can only change this in the database." canGate="update" :canResource="$database" /> @endif + helper="You can only change this in the database." canGate="update" :canResource="$database" />
    @else
    You can only change the username and password in the database after @@ -37,7 +37,7 @@ If you change the Redis Username in the database, please sync it here, otherwise automations (like backups) won't work.

    Note: If the environment variable REDIS_USERNAME is set as a shared variable (environment, project, or team-based), this input field will become read-only." - :disabled="$this->isSharedVariable('REDIS_USERNAME')" /> + :disabled="$this->isSharedVariable('REDIS_USERNAME')" canGate="update" :canResource="$database" /> @endif + :disabled="$this->isSharedVariable('REDIS_PASSWORD')" canGate="update" :canResource="$database" />
    @endif
    + id="database.custom_docker_run_options" label="Custom Docker Options" canGate="update" :canResource="$database" />

    Network

    + helper="A comma separated list of ports you would like to map to the host system.
    Example3000:5432,3002:5433" + canGate="update" :canResource="$database" />
    + type="password" readonly wire:model="db_url" canGate="update" :canResource="$database" /> @if ($db_url_public) + type="password" readonly wire:model="db_url_public" canGate="update" :canResource="$database" /> @endif
    @@ -98,11 +99,13 @@
    @if (str($database->status)->contains('exited')) + wire:model.live="database.enable_ssl" instantSave="instantSaveSSL" canGate="update" + :canResource="$database" /> @else + helper="Database should be stopped to change this settings." canGate="update" + :canResource="$database" /> @endif
    @@ -126,26 +129,28 @@ @endif
    - +
    + id="database.public_port" label="Public Port" canGate="update" :canResource="$database" />
    -
    ⚠️ Important: Coolify automatically applies the requirepass directive using the password shown in the Password field above. If you override requirepass in your custom configuration, make sure it matches the password field to avoid authentication issues.

    🔗 Tip: View the full Redis default configuration to see what options are available." - label="Custom Redis Configuration" rows="10" id="database.redis_conf" /> + label="Custom Redis Configuration" rows="10" id="database.redis_conf" canGate="update" + :canResource="$database" />

    Advanced

    + instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" + canGate="update" :canResource="$database" />
    diff --git a/resources/views/livewire/project/database/scheduled-backups.blade.php b/resources/views/livewire/project/database/scheduled-backups.blade.php index 7872e436a..c0b8647b2 100644 --- a/resources/views/livewire/project/database/scheduled-backups.blade.php +++ b/resources/views/livewire/project/database/scheduled-backups.blade.php @@ -62,7 +62,7 @@ @else + class="px-3 py-1 rounded-md text-xs font-medium tracking-wide shadow-xs bg-gray-100 text-gray-800 dark:bg-neutral-800 dark:text-gray-200"> No executions yet @endif @@ -146,7 +146,7 @@ @else + class="px-3 py-1 rounded-md text-xs font-medium tracking-wide shadow-xs bg-gray-100 text-gray-800 dark:bg-neutral-800 dark:text-gray-200"> No executions yet @endif diff --git a/resources/views/livewire/project/environment-edit.blade.php b/resources/views/livewire/project/environment-edit.blade.php index 7062d7e0a..078d93456 100644 --- a/resources/views/livewire/project/environment-edit.blade.php +++ b/resources/views/livewire/project/environment-edit.blade.php @@ -5,16 +5,7 @@

    Environment: {{ data_get_str($environment, 'name')->limit(15) }}

    - @can('update', $environment) - - Save - - @else - - Save - - @endcan + Save @can('delete', $environment) @endcan diff --git a/resources/views/livewire/project/index.blade.php b/resources/views/livewire/project/index.blade.php index 46ded4424..89da9117e 100644 --- a/resources/views/livewire/project/index.blade.php +++ b/resources/views/livewire/project/index.blade.php @@ -4,9 +4,11 @@

    Projects

    - - - + @can('createAnyResource') + + + + @endcan
    All your projects are here.
    @@ -24,8 +26,8 @@
    - @@ -149,13 +153,15 @@ Settings @if (str($database->status)->contains('running')) - + @can('update', $service) + + @endcan @endif diff --git a/resources/views/livewire/project/service/database.blade.php b/resources/views/livewire/project/service/database.blade.php index b066a22b1..117ad44c5 100644 --- a/resources/views/livewire/project/service/database.blade.php +++ b/resources/views/livewire/project/service/database.blade.php @@ -6,29 +6,33 @@ @else

    {{ Str::headline($database->name) }}

    @endif - Save - - + Save + @can('update', $database) + + @endcan + @can('delete', $database) + + @endcan
    - - - + +
    - - +
    @if ($db_url_public)

    Advanced

    - -
    diff --git a/resources/views/livewire/project/service/edit-domain.blade.php b/resources/views/livewire/project/service/edit-domain.blade.php index 5528834eb..1b4fa48fd 100644 --- a/resources/views/livewire/project/service/edit-domain.blade.php +++ b/resources/views/livewire/project/service/edit-domain.blade.php @@ -1,7 +1,7 @@
    Note: If a service has a defined port, do not delete it.
    If you want to use your custom domain, you can add it with a port.
    - - Save + Save
    diff --git a/resources/views/livewire/project/service/file-storage.blade.php b/resources/views/livewire/project/service/file-storage.blade.php index 0637c9e86..aa0ce66a3 100644 --- a/resources/views/livewire/project/service/file-storage.blade.php +++ b/resources/views/livewire/project/service/file-storage.blade.php @@ -6,54 +6,68 @@
    -
    - @if ($fileStorage->is_directory) - - - @else - @if (!$fileStorage->is_binary) - + @if ($fileStorage->is_directory) + + shortConfirmationLabel="Filepath" :confirmWithPassword="false" step2ButtonText="Convert to file" /> + + @else + @if (!$fileStorage->is_binary) + + @endif + Load from server + @endif - Load from server - - @endif -
    + + @endcan @if (!$fileStorage->is_directory) - @if (data_get($resource, 'settings.is_preserve_repository_enabled')) -
    - -
    - @endif - - @if (!$fileStorage->is_based_on_git && !$fileStorage->is_binary) - Save - @endif + @can('update', $resource) + @if (data_get($resource, 'settings.is_preserve_repository_enabled')) +
    + +
    + @endif + + @if (!$fileStorage->is_based_on_git && !$fileStorage->is_binary) + Save + @endif + @else + @if (data_get($resource, 'settings.is_preserve_repository_enabled')) +
    + +
    + @endif + + @endcan @endif
    diff --git a/resources/views/livewire/project/service/heading.blade.php b/resources/views/livewire/project/service/heading.blade.php index 8afade4b1..73635d93a 100644 --- a/resources/views/livewire/project/service/heading.blade.php +++ b/resources/views/livewire/project/service/heading.blade.php @@ -18,10 +18,12 @@ href="{{ route('project.service.logs', $parameters) }}"> - - - + @can('canAccessTerminal') + + + + @endcan @if ($service->isDeployable) diff --git a/resources/views/livewire/project/service/index.blade.php b/resources/views/livewire/project/service/index.blade.php index d6afe90e3..9a782fca6 100644 --- a/resources/views/livewire/project/service/index.blade.php +++ b/resources/views/livewire/project/service/index.blade.php @@ -38,9 +38,11 @@

    Scheduled Backups

    @if (filled($serviceDatabase->custom_type) || !$serviceDatabase->is_migrated) - - - + @can('update', $serviceDatabase) + + + + @endcan @endif
    diff --git a/resources/views/livewire/project/service/service-application-view.blade.php b/resources/views/livewire/project/service/service-application-view.blade.php index 4685741a7..deaf1429c 100644 --- a/resources/views/livewire/project/service/service-application-view.blade.php +++ b/resources/views/livewire/project/service/service-application-view.blade.php @@ -6,35 +6,41 @@ @else

    {{ Str::headline($application->name) }}

    @endif - Save - - + Save + @can('update', $application) + + @endcan + @can('delete', $application) + + @endcan
    - - +
    @if (!$application->serviceType()?->contains(str($application->image)->before(':'))) @if ($application->required_fqdn) - @else - @endif @endif -
    @@ -42,18 +48,22 @@

    Advanced

    @if (str($application->image)->contains('pocketbase')) - @else - @endif - - -
    diff --git a/resources/views/livewire/project/service/stack-form.blade.php b/resources/views/livewire/project/service/stack-form.blade.php index 7583cabaf..fff6524ce 100644 --- a/resources/views/livewire/project/service/stack-form.blade.php +++ b/resources/views/livewire/project/service/stack-form.blade.php @@ -5,19 +5,21 @@ @if (isDev())
    {{ $service->compose_parsing_version }}
    @endif - Save - - - + Save + @can('update', $service) + + + + @endcan
    Configuration
    - - + +
    -
    @if ($fields->count() > 0) @@ -34,7 +36,7 @@ @endif - @endforeach diff --git a/resources/views/livewire/project/service/storage.blade.php b/resources/views/livewire/project/service/storage.blade.php index 0988788e9..41d48f386 100644 --- a/resources/views/livewire/project/service/storage.blade.php +++ b/resources/views/livewire/project/service/storage.blade.php @@ -16,9 +16,11 @@ volume name, example: -pr-1" /> @if ($resource?->build_pack !== 'dockercompose') - - - + @can('update', $resource) + + + + @endcan @endif
    Persistent storage to preserve data between deployments.
    diff --git a/resources/views/livewire/project/shared/environment-variable/all.blade.php b/resources/views/livewire/project/shared/environment-variable/all.blade.php index a71f88637..c75407179 100644 --- a/resources/views/livewire/project/shared/environment-variable/all.blade.php +++ b/resources/views/livewire/project/shared/environment-variable/all.blade.php @@ -2,20 +2,28 @@

    Environment Variables

    -
    - - - -
    - {{ $view === 'normal' ? 'Developer view' : 'Normal view' }} + @can('manageEnvironment', $resource) +
    + + + +
    + {{ $view === 'normal' ? 'Developer view' : 'Normal view' }} + @endcan
    Environment variables (secrets) for this resource.
    @if ($resourceClass === 'App\Models\Application' && data_get($resource, 'build_pack') !== 'dockercompose')
    - + @can('manageEnvironment', $resource) + + @else + + @endcan
    @endif @if ($resource->type() === 'service' || $resource?->build_pack === 'dockercompose') @@ -62,16 +70,27 @@ @endif @else
    - + @can('manageEnvironment', $resource) + - @if ($showPreview) - - @endif + @if ($showPreview) + + @endif - Save All Environment Variables + Save All Environment Variables + @else + + + @if ($showPreview) + + @endif + @endcan
    @endif
    diff --git a/resources/views/livewire/project/shared/environment-variable/show.blade.php b/resources/views/livewire/project/shared/environment-variable/show.blade.php index 5a197dc7a..63148b74c 100644 --- a/resources/views/livewire/project/shared/environment-variable/show.blade.php +++ b/resources/views/livewire/project/shared/environment-variable/show.blade.php @@ -13,101 +13,151 @@ - + @can('delete', $this->env) + + @endcan @else - @if ($isDisabled) -
    + @can('update', $this->env) + @if ($isDisabled) +
    + + + @if ($is_shared) + + @endif +
    + @else +
    + @if ($is_multiline) + + + @else + + + @endif + @if ($is_shared) + + @endif +
    + @endif + @else +
    @if ($is_shared) @endif
    - @else -
    - @if ($is_multiline) - - - @else - - - @endif - @if ($is_shared) - - @endif -
    - @endif -
    - @if (!$is_redis_credential) - @if ($type === 'service') - - - - @else - @if ($is_shared) + @endcan + @can('manageEnvironment', $this->resource) +
    + @if (!$is_redis_credential) + @if ($type === 'service') + @else - @if ($isSharedVariable) - - @else + @if ($is_shared) - - @if ($is_multiline === false) - + + @else + @if ($isSharedVariable) + + @else + + + @if ($is_multiline === false) + + @endif @endif @endif @endif @endif - @endif -
    - @if ($isDisabled) - - Update - - - Lock - - - @else - - Update - - - Lock - - - @endif -
    +
    + @if ($isDisabled) + + Update + + + Lock + + + @else + + Update + + + Lock + + + @endif +
    + @else +
    + @if (!$is_redis_credential) + @if ($type === 'service') + + + + @else + @if ($is_shared) + + + @else + @if ($isSharedVariable) + + @else + + + @if ($is_multiline === false) + + @endif + @endif + @endif + @endif + @endif +
    +
    + @endcan @endif diff --git a/resources/views/livewire/project/shared/health-checks.blade.php b/resources/views/livewire/project/shared/health-checks.blade.php index cb34f61ed..fb9f7f3bc 100644 --- a/resources/views/livewire/project/shared/health-checks.blade.php +++ b/resources/views/livewire/project/shared/health-checks.blade.php @@ -1,7 +1,7 @@

    Healthchecks

    - Save + Save
    Define how your resource's health should be checked.
    @@ -10,29 +10,29 @@
    @endif
    - +
    - - - - + + + - +
    - - +
    - - - - +
    - + \ No newline at end of file diff --git a/resources/views/livewire/project/shared/resource-limits.blade.php b/resources/views/livewire/project/shared/resource-limits.blade.php index 6c84335de..2aa2fd0af 100644 --- a/resources/views/livewire/project/shared/resource-limits.blade.php +++ b/resources/views/livewire/project/shared/resource-limits.blade.php @@ -2,40 +2,39 @@

    Resource Limits

    - Save + Save
    Limit your container resources by CPU & memory.

    Limit CPUs

    - - -

    Limit Memory

    - -
    - - -
    diff --git a/resources/views/livewire/project/shared/resource-operations.blade.php b/resources/views/livewire/project/shared/resource-operations.blade.php index f23c6eb4e..aa8f536ce 100644 --- a/resources/views/livewire/project/shared/resource-operations.blade.php +++ b/resources/views/livewire/project/shared/resource-operations.blade.php @@ -1,30 +1,41 @@

    Resource Operations

    You can easily make different kind of operations on this resource.
    -

    Clone

    +

    Clone

    To another project / environment on a different / same server.
    - @foreach ($servers->sortBy('id') as $server) -
    Server: {{ $server->name }}
    - @foreach ($server->destinations() as $destination) - - -
    -
    -
    Network
    -
    {{ $destination->name }}
    + @can('update', $resource) + @foreach ($servers->sortBy('id') as $server) +
    Server: {{ $server->name }}
    + @foreach ($server->destinations() as $destination) + + +
    +
    +
    Network
    +
    {{ $destination->name }}
    +
    -
    - - + + + @endforeach @endforeach - @endforeach + @else +
    +
    + Access Restricted: You don't have permission to clone resources. Contact your team + administrator to request access. +
    +
    + @endcan

    Move

    @@ -36,28 +47,38 @@ {{ $resource->environment->name }} environment.
    - @forelse ($projects as $project) -
    Project: {{ $project->name }}
    + @can('update', $resource) + @forelse ($projects as $project) +
    Project: {{ $project->name }}
    - @foreach ($project->environments as $environment) - - -
    -
    -
    Environment
    -
    {{ $environment->name }}
    + @foreach ($project->environments as $environment) + + +
    +
    +
    Environment
    +
    {{ $environment->name }}
    +
    -
    - - - @endforeach - @empty -
    No projects found to move to
    - @endforelse + + + @endforeach + @empty +
    No projects found to move to
    + @endforelse + @else +
    +
    + Access Restricted: You don't have permission to move resources between projects or + environments. Contact your team administrator to request access. +
    +
    + @endcan
    diff --git a/resources/views/livewire/project/shared/scheduled-task/all.blade.php b/resources/views/livewire/project/shared/scheduled-task/all.blade.php index 8a2ec4d7a..fb6985094 100644 --- a/resources/views/livewire/project/shared/scheduled-task/all.blade.php +++ b/resources/views/livewire/project/shared/scheduled-task/all.blade.php @@ -1,13 +1,15 @@

    Scheduled Tasks

    - - @if ($resource->type() == 'application') - - @elseif ($resource->type() == 'service') - - @endif - + @can('update', $resource) + + @if ($resource->type() == 'application') + + @elseif ($resource->type() == 'service') + + @endif + + @endcan
    @forelse($resource->scheduled_tasks as $task) diff --git a/resources/views/livewire/project/shared/storages/all.blade.php b/resources/views/livewire/project/shared/storages/all.blade.php index e357b4f94..f7bd7bdce 100644 --- a/resources/views/livewire/project/shared/storages/all.blade.php +++ b/resources/views/livewire/project/shared/storages/all.blade.php @@ -3,10 +3,10 @@ @foreach ($resource->persistentStorages as $storage) @if ($resource->type() === 'service') + :resource="$resource" :isFirst="$loop->first" isReadOnly='true' isService='true' /> @else @endif @endforeach diff --git a/resources/views/livewire/project/shared/storages/show.blade.php b/resources/views/livewire/project/shared/storages/show.blade.php index 4ad5636ec..569df0c4b 100644 --- a/resources/views/livewire/project/shared/storages/show.blade.php +++ b/resources/views/livewire/project/shared/storages/show.blade.php @@ -9,7 +9,7 @@ @else - @endif @if ($isService || $startedAt) @@ -19,13 +19,11 @@ @else - - - Update - @endif
    @else @@ -36,32 +34,50 @@
    @endif @else - @if ($isFirst) -
    - - - + @can('update', $resource) + @if ($isFirst) +
    + + + +
    + @else +
    + + + +
    + @endif +
    + + Update + +
    @else -
    - - - -
    - @endif -
    - - Update - - -
    + @if ($isFirst) +
    + + + +
    + @else +
    + + + +
    + @endif + @endcan @endif
    diff --git a/resources/views/livewire/project/shared/tags.blade.php b/resources/views/livewire/project/shared/tags.blade.php index 4ceb475a6..2c75deab9 100644 --- a/resources/views/livewire/project/shared/tags.blade.php +++ b/resources/views/livewire/project/shared/tags.blade.php @@ -1,37 +1,50 @@

    Tags

    -
    -
    - + @can('update', $resource) + +
    + +
    + Add + + @else +
    +
    + Access Restricted: You don't have permission to manage tags. Contact your team + administrator to request access. +
    - Add - + @endcan @if (data_get($this->resource, 'tags') && count(data_get($this->resource, 'tags')) > 0)

    Assigned Tags

    @foreach (data_get($this->resource, 'tags') as $tagId => $tag)
    {{ $tag->name }} - - - - + @can('update', $resource) + + + + + @endcan
    @endforeach
    @endif - @if (count($filteredTags) > 0) -

    Existing Tags

    -
    Click to add quickly
    -
    - @foreach ($filteredTags as $tag) - - {{ $tag->name }} - @endforeach -
    - @endif + @can('update', $resource) + @if (count($filteredTags) > 0) +

    Existing Tags

    +
    Click to add quickly
    +
    + @foreach ($filteredTags as $tag) + + {{ $tag->name }} + @endforeach +
    + @endif + @endcan
    diff --git a/resources/views/livewire/project/shared/webhooks.blade.php b/resources/views/livewire/project/shared/webhooks.blade.php index 64a2ece51..f3403a402 100644 --- a/resources/views/livewire/project/shared/webhooks.blade.php +++ b/resources/views/livewire/project/shared/webhooks.blade.php @@ -17,10 +17,15 @@
    - - + @can('update', $resource) + + @else + + @endcan
    Webhook Configuration on GitHub @@ -29,23 +34,43 @@
    - + @can('update', $resource) + + @else + + @endcan
    - + @can('update', $resource) + + @else + + @endcan
    - + @can('update', $resource) + + @else + + @endcan
    - Save + @can('update', $resource) + Save + @endcan @else You are using an official Git App. You do not need manual webhooks. diff --git a/resources/views/livewire/project/show.blade.php b/resources/views/livewire/project/show.blade.php index da653398b..3d034b8f3 100644 --- a/resources/views/livewire/project/show.blade.php +++ b/resources/views/livewire/project/show.blade.php @@ -4,21 +4,16 @@

    Environments

    - -
    - - @can('update', $project) + @can('update', $project) + + + Save - @else - - Save - - @endcan - - + +
    + @endcan @can('delete', $project) @endcan @@ -34,12 +29,14 @@
    {{ $environment->description }}
    - + @can('update', $project) + + @endcan
    @empty diff --git a/resources/views/livewire/security/api-tokens.blade.php b/resources/views/livewire/security/api-tokens.blade.php index eaf7a439d..bf6bcf76c 100644 --- a/resources/views/livewire/security/api-tokens.blade.php +++ b/resources/views/livewire/security/api-tokens.blade.php @@ -12,44 +12,58 @@
    Tokens are created with the current team as scope.

    New Token

    -
    -
    - - Create -
    -
    - Permissions - : -
    - @if ($permissions) - @foreach ($permissions as $permission) -
    {{ $permission }}
    - @endforeach + @can('create', App\Models\PersonalAccessToken::class) + +
    + + Create +
    +
    + Permissions + : +
    + @if ($permissions) + @foreach ($permissions as $permission) +
    {{ $permission }}
    + @endforeach + @endif +
    +
    + +

    Token Permissions

    +
    + @if ($canUseRootPermissions) + + @else + + @endif + + @if (!in_array('root', $permissions)) + @if ($canUseWritePermissions) + + @else + + @endif + + + + @endif
    -
    - -

    Token Permissions

    -
    - - @if (!in_array('root', $permissions)) - - - - + @if (in_array('root', $permissions)) +
    Root access, be careful!
    @endif -
    - @if (in_array('root', $permissions)) -
    Root access, be careful!
    - @endif - + + @endcan @if (session()->has('token'))
    Please copy this token now. For your security, it won't be shown again. @@ -72,15 +86,17 @@ @endif
    - + @if (auth()->id() === $token->tokenable_id) + + @endif
    @empty
    diff --git a/resources/views/livewire/security/private-key/index.blade.php b/resources/views/livewire/security/private-key/index.blade.php index f40b91f43..47cfc9b1e 100644 --- a/resources/views/livewire/security/private-key/index.blade.php +++ b/resources/views/livewire/security/private-key/index.blade.php @@ -2,11 +2,15 @@

    Private Keys

    - - - - + @can('create', App\Models\PrivateKey::class) + + + + @endcan + @can('create', App\Models\PrivateKey::class) + + @endcan
    @forelse ($privateKeys as $key) diff --git a/resources/views/livewire/security/private-key/show.blade.php b/resources/views/livewire/security/private-key/show.blade.php index c381b8f2a..8668cfd34 100644 --- a/resources/views/livewire/security/private-key/show.blade.php +++ b/resources/views/livewire/security/private-key/show.blade.php @@ -7,32 +7,34 @@

    Private Key

    - + Save @if (data_get($private_key, 'id') > 0) - + @can('delete', $private_key) + + @endcan @endif
    - - + +
    Public Key
    - +
    Private Key *
    @endif
    -
    - +
    diff --git a/resources/views/livewire/server/advanced.blade.php b/resources/views/livewire/server/advanced.blade.php index 98ab15534..308a9eed2 100644 --- a/resources/views/livewire/server/advanced.blade.php +++ b/resources/views/livewire/server/advanced.blade.php @@ -9,7 +9,7 @@

    Advanced

    - Save + Save
    Advanced configuration for your server.
    @@ -59,10 +59,10 @@
    - -
    @@ -71,9 +71,11 @@

    Builds

    - -
    diff --git a/resources/views/livewire/server/ca-certificate/show.blade.php b/resources/views/livewire/server/ca-certificate/show.blade.php index 66262614c..f11bd732e 100644 --- a/resources/views/livewire/server/ca-certificate/show.blade.php +++ b/resources/views/livewire/server/ca-certificate/show.blade.php @@ -8,28 +8,30 @@

    CA Certificate

    -
    - - - - -
    + @can('update', $server) +
    + + + + +
    + @endcan
    @@ -63,9 +65,11 @@ @endif
    - - {{ $showCertificate ? 'Hide' : 'Show' }} - + @can('view', $server) + + {{ $showCertificate ? 'Hide' : 'Show' }} + + @endcan
    @if ($showCertificate)