From 63fcc0ebc3a41a91eb4a48265d9d637f80afcf31 Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Tue, 26 Aug 2025 10:27:31 +0200
Subject: [PATCH] feat(acl): Change views/backend code to able to use proper
ACL's later on. Currently it is not enabled.
---
app/Http/Kernel.php | 2 +
app/Http/Middleware/CanAccessTerminal.php | 31 +++
app/Http/Middleware/CanCreateResources.php | 9 +-
app/Http/Middleware/CanUpdateResource.php | 75 +++++
app/Livewire/Destination/Show.php | 7 +
app/Livewire/Notifications/Discord.php | 6 +
app/Livewire/Notifications/Email.php | 7 +
app/Livewire/Notifications/Pushover.php | 6 +
app/Livewire/Notifications/Slack.php | 6 +
app/Livewire/Notifications/Telegram.php | 6 +
.../Project/Application/Preview/Form.php | 5 +
app/Livewire/Project/Application/Previews.php | 1 +
app/Livewire/Project/Database/Import.php | 1 +
app/Livewire/Project/Index.php | 1 +
.../Project/Service/Configuration.php | 45 +--
app/Livewire/Project/Service/Database.php | 102 ++++---
app/Livewire/Project/Service/FileStorage.php | 13 +
app/Livewire/Project/Service/Index.php | 11 +-
.../Service/ServiceApplicationView.php | 54 ++--
app/Livewire/Project/Service/Storage.php | 5 +
.../Shared/EnvironmentVariable/Add.php | 3 +
.../Shared/EnvironmentVariable/Show.php | 18 +-
app/Livewire/Project/Shared/HealthChecks.php | 5 +
.../Project/Shared/ResourceLimits.php | 4 +
.../Project/Shared/ScheduledTask/Add.php | 23 ++
.../Project/Shared/ScheduledTask/Show.php | 7 +
app/Livewire/Project/Shared/Storages/Add.php | 9 +
app/Livewire/Project/Shared/Storages/Show.php | 9 +
app/Livewire/Project/Shared/Tags.php | 6 +
app/Livewire/Project/Shared/Webhooks.php | 3 +
app/Livewire/Security/ApiTokens.php | 39 +++
app/Livewire/Security/PrivateKey/Index.php | 4 +
.../Proxy/DynamicConfigurationNavbar.php | 15 +-
.../SharedVariables/Environment/Show.php | 5 +
app/Livewire/SharedVariables/Project/Show.php | 5 +
app/Livewire/SharedVariables/Team/Index.php | 5 +
app/Livewire/Source/Github/Change.php | 19 +-
app/Livewire/Source/Github/Create.php | 5 +
app/Livewire/Storage/Create.php | 5 +
app/Livewire/Storage/Form.php | 9 +-
app/Livewire/Team/Index.php | 5 +
app/Livewire/Team/Invitations.php | 5 +
app/Livewire/Team/InviteLink.php | 4 +
app/Livewire/Team/Member.php | 11 +
app/Livewire/Team/Member/Index.php | 6 +-
app/Livewire/Terminal/Index.php | 1 -
app/Models/SharedEnvironmentVariable.php | 15 +
app/Policies/ApiTokenPolicy.php | 109 ++++++++
app/Policies/ApplicationPolicy.php | 52 +++-
app/Policies/ApplicationPreviewPolicy.php | 30 +-
app/Policies/ApplicationSettingPolicy.php | 18 +-
app/Policies/DatabasePolicy.php | 33 ++-
app/Policies/EnvironmentPolicy.php | 18 +-
app/Policies/GithubAppPolicy.php | 79 ++++++
app/Policies/NotificationPolicy.php | 56 ++++
app/Policies/PrivateKeyPolicy.php | 12 +-
app/Policies/ProjectPolicy.php | 18 +-
app/Policies/ResourceCreatePolicy.php | 7 +-
app/Policies/S3StoragePolicy.php | 19 +-
app/Policies/ServerPolicy.php | 16 +-
app/Policies/ServiceApplicationPolicy.php | 63 +++++
app/Policies/ServiceDatabasePolicy.php | 63 +++++
app/Policies/ServicePolicy.php | 60 +++-
.../SharedEnvironmentVariablePolicy.php | 79 ++++++
app/Policies/StandaloneDockerPolicy.php | 17 +-
app/Policies/SwarmDockerPolicy.php | 17 +-
app/Policies/TeamPolicy.php | 104 +++++++
app/Providers/AuthServiceProvider.php | 25 ++
app/View/Components/Forms/Button.php | 13 +
app/View/Components/Forms/Checkbox.php | 14 +
app/View/Components/Forms/Input.php | 15 +-
app/View/Components/Forms/Select.php | 15 +-
app/View/Components/Forms/Textarea.php | 13 +-
resources/views/components/navbar.blade.php | 58 ++--
.../livewire/destination/index.blade.php | 8 +-
.../livewire/destination/new/docker.blade.php | 43 +--
.../views/livewire/destination/show.blade.php | 10 +-
.../livewire/notifications/discord.blade.php | 38 +--
.../livewire/notifications/email.blade.php | 92 ++++---
.../livewire/notifications/pushover.blade.php | 38 +--
.../livewire/notifications/slack.blade.php | 36 +--
.../livewire/notifications/telegram.blade.php | 64 ++---
.../project/application/advanced.blade.php | 78 +++---
.../project/application/general.blade.php | 257 +++++++++---------
.../project/application/heading.blade.php | 10 +-
.../application/preview/form.blade.php | 8 +-
.../application/previews-compose.blade.php | 2 +-
.../project/application/previews.blade.php | 184 +++++++------
.../project/application/rollback.blade.php | 26 +-
.../project/application/source.blade.php | 90 +++---
.../project/application/swarm.blade.php | 6 +-
.../project/database/backup/index.blade.php | 8 +-
.../database/clickhouse/general.blade.php | 37 +--
.../project/database/configuration.blade.php | 8 +-
.../database/dragonfly/general.blade.php | 38 +--
.../project/database/heading.blade.php | 10 +-
.../project/database/import.blade.php | 4 +-
.../project/database/keydb/general.blade.php | 40 +--
.../database/mariadb/general.blade.php | 52 ++--
.../database/mongodb/general.blade.php | 56 ++--
.../project/database/mysql/general.blade.php | 38 +--
.../database/postgresql/general.blade.php | 75 ++---
.../project/database/redis/general.blade.php | 47 ++--
.../database/scheduled-backups.blade.php | 4 +-
.../project/environment-edit.blade.php | 11 +-
.../views/livewire/project/index.blade.php | 12 +-
.../project/service/configuration.blade.php | 76 +++---
.../project/service/database.blade.php | 38 +--
.../project/service/edit-domain.blade.php | 4 +-
.../project/service/file-storage.blade.php | 100 ++++---
.../project/service/heading.blade.php | 10 +-
.../livewire/project/service/index.blade.php | 8 +-
.../service-application-view.blade.php | 52 ++--
.../project/service/stack-form.blade.php | 18 +-
.../project/service/storage.blade.php | 8 +-
.../shared/environment-variable/all.blade.php | 55 ++--
.../environment-variable/show.blade.php | 198 +++++++++-----
.../project/shared/health-checks.blade.php | 28 +-
.../project/shared/resource-limits.blade.php | 17 +-
.../shared/resource-operations.blade.php | 99 ++++---
.../shared/scheduled-task/all.blade.php | 16 +-
.../project/shared/storages/all.blade.php | 4 +-
.../project/shared/storages/show.blade.php | 74 +++--
.../livewire/project/shared/tags.blade.php | 59 ++--
.../project/shared/webhooks.blade.php | 53 +++-
.../views/livewire/project/show.blade.php | 33 +--
.../livewire/security/api-tokens.blade.php | 104 ++++---
.../security/private-key/index.blade.php | 14 +-
.../security/private-key/show.blade.php | 34 +--
.../views/livewire/server/advanced.blade.php | 14 +-
.../server/ca-certificate/show.blade.php | 54 ++--
.../server/cloudflare-tunnel.blade.php | 44 ++-
.../livewire/server/destinations.blade.php | 12 +-
.../livewire/server/docker-cleanup.blade.php | 39 +--
.../views/livewire/server/index.blade.php | 8 +-
.../livewire/server/log-drains.blade.php | 37 +--
.../views/livewire/server/navbar.blade.php | 28 +-
.../server/private-key/show.blade.php | 12 +-
.../views/livewire/server/proxy.blade.php | 68 +++--
.../dynamic-configuration-navbar.blade.php | 16 +-
.../proxy/dynamic-configurations.blade.php | 10 +-
.../proxy/new-dynamic-configuration.blade.php | 7 +-
.../views/livewire/server/show.blade.php | 172 +++++++-----
.../environment/index.blade.php | 4 +-
.../environment/show.blade.php | 8 +-
.../shared-variables/project/show.blade.php | 10 +-
.../shared-variables/team/index.blade.php | 8 +-
.../livewire/source/github/change.blade.php | 255 +++++++++--------
.../livewire/source/github/create.blade.php | 99 +++----
.../views/livewire/storage/create.blade.php | 53 ++--
.../views/livewire/storage/form.blade.php | 44 +--
.../views/livewire/storage/index.blade.php | 8 +-
resources/views/livewire/team/index.blade.php | 124 +++++----
.../views/livewire/team/invitations.blade.php | 108 ++++----
.../views/livewire/team/invite-link.blade.php | 36 +--
.../views/livewire/team/member.blade.php | 8 +-
.../livewire/team/member/index.blade.php | 4 +-
resources/views/source/all.blade.php | 20 +-
routes/web.php | 29 +-
159 files changed, 3610 insertions(+), 1922 deletions(-)
create mode 100644 app/Http/Middleware/CanAccessTerminal.php
create mode 100644 app/Http/Middleware/CanUpdateResource.php
create mode 100644 app/Policies/ApiTokenPolicy.php
create mode 100644 app/Policies/GithubAppPolicy.php
create mode 100644 app/Policies/NotificationPolicy.php
create mode 100644 app/Policies/ServiceApplicationPolicy.php
create mode 100644 app/Policies/ServiceDatabasePolicy.php
create mode 100644 app/Policies/SharedEnvironmentVariablePolicy.php
create mode 100644 app/Policies/TeamPolicy.php
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 @@
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 @@ public function syncData(bool $toModel = false)
public function submit()
{
try {
+ $this->authorize('update', $this->destination);
+
$this->syncData(true);
$this->dispatch('success', 'Destination saved.');
} catch (\Throwable $e) {
@@ -73,6 +78,8 @@ public function submit()
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 @@
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 @@ public function mount()
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 @@ public function syncData(bool $toModel = false)
{
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 @@ public function saveModel()
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 @@
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 @@
class Email extends Component
{
+ use AuthorizesRequests;
+
protected $listeners = ['refresh' => '$refresh'];
#[Locked]
@@ -110,6 +113,7 @@ public function mount()
$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 @@ public function syncData(bool $toModel = false)
{
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 @@ public function submitResend()
public function sendTestEmail()
{
try {
+ $this->authorize('sendTest', $this->settings);
$this->validate([
'testEmailAddress' => 'required|email',
], [
@@ -338,6 +344,7 @@ function () {
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 @@
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 @@ public function mount()
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 @@ public function syncData(bool $toModel = false)
{
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 @@ public function saveModel()
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 @@
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 @@ public function mount()
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 @@ public function syncData(bool $toModel = false)
{
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 @@ public function saveModel()
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 @@
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 @@ public function mount()
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 @@ public function syncData(bool $toModel = false)
{
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 @@ public function saveModel()
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 @@ public function mount()
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 @@ public function submit()
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 @@ public function mount()
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 @@ public function runImport()
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 @@ public function mount()
$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 @@ public function render()
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 @@ public function refreshServices()
public function restartApplication($id)
{
try {
+ $this->authorize('update', $this->service);
$application = $this->service->applications->find($id);
if ($application) {
$application->restart();
@@ -83,6 +93,7 @@ public function restartApplication($id)
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\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 @@
class Database extends Component
{
+ use AuthorizesRequests;
+
public ServiceDatabase $database;
public ?string $db_url_public = null;
@@ -40,24 +43,31 @@ public function render()
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 @@ public function delete($password)
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 @@ public function convertToApplication()
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 @@ public function refreshFileStorages()
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\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 @@ public function mount()
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 @@ public function convertToDirectory()
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 @@ public function loadStorageOnServer()
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 @@ public function convertToFile()
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 @@ public function delete($password)
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 @@
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 @@ public function mount()
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 @@ public function mount()
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 @@
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 @@
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 @@ public function delete($password)
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 @@ public function convertToDatabase()
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 @@ public function refreshStorages()
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 @@
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 @@ public function mount()
}
}
+ public function getResourceProperty()
+ {
+ return $this->env->resourceable ?? $this->env;
+ }
+
public function refresh()
{
$this->syncData();
@@ -140,6 +146,8 @@ public function serialize()
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 @@ public function instantSave()
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 @@ public function submit()
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 @@ public function instantSave()
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 @@ public function mount()
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\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 @@ public function syncData(bool $toModel = false)
public function instantSave()
{
try {
+ $this->authorize('update', $this->resource);
$this->syncData(true);
$this->dispatch('success', 'Scheduled task updated.');
$this->refreshTasks();
@@ -120,6 +124,7 @@ public function instantSave()
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 @@ public function refreshTasks()
public function delete()
{
try {
+ $this->authorize('update', $this->resource);
$this->task->delete();
if ($this->type === 'application') {
@@ -154,6 +160,7 @@ public function delete()
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 @@
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 @@ public function mount()
public function submitFileStorage()
{
try {
+ $this->authorize('update', $this->resource);
+
$this->validate([
'file_storage_path' => 'string',
'file_storage_content' => 'nullable|string',
@@ -112,6 +117,8 @@ public function submitFileStorage()
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 @@ public function submitFileStorageDirectory()
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 @@
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 @@ public function submit()
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 @@ public function loadTags()
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 @@ public function submit()
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 @@ public function addTag(string $id, string $name)
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 @@ public function render()
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 @@ private function getTokens()
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 @@ public function updatedPermissions($permissionToUpdate)
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 @@ public function revoke(int $id)
{
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 @@ public function render()
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 @@
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 @@
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 @@
class Change extends Component
{
- public string $webhook_endpoint;
+ use AuthorizesRequests;
+
+ public string $webhook_endpoint = '';
public ?string $ipv4 = null;
@@ -69,6 +72,8 @@ public function boot()
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 @@ public function mount()
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 @@ private function generateGithubJwt($private_key, $app_id): string
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 @@ public function updateGithubAppName()
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 @@ public function submit()
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 @@ public function createGithubAppManually()
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 @@ public function instantSave()
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 @@ public function mount()
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 @@
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 @@ public function updatedEndpoint($value)
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 @@
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 @@ protected function messages(): array
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 @@ public function delete()
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 @@
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 @@ public function submit()
{
$this->validate();
try {
+ $this->authorize('update', $this->team);
$this->team->save();
refreshSession();
$this->dispatch('success', 'Team updated.');
@@ -69,6 +73,7 @@ public function submit()
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 @@
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 @@
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 @@
class InviteLink extends Component
{
+ use AuthorizesRequests;
+
public string $email;
public string $role = 'member';
@@ -40,6 +43,7 @@ public function viaLink()
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 @@
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 @@ public function makeAdmin()
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 @@ public function makeOwner()
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 @@ public function makeReadonly()
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 @@ public function viewAny(User $user): bool
*/
public function view(User $user, Application $application): bool
{
+ // Authorization temporarily disabled
+ /*
+ return true;
+ */
return true;
}
@@ -29,11 +37,15 @@ public function view(User $user, Application $application): bool
*/
public function create(User $user): bool
{
+ // Authorization temporarily disabled
+ /*
if ($user->isAdmin()) {
return true;
}
return false;
+ */
+ return true;
}
/**
@@ -41,11 +53,15 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, Application $application): Response
*/
public function delete(User $user, Application $application): bool
{
+ // Authorization temporarily disabled
+ /*
if ($user->isAdmin()) {
return true;
}
return false;
+ */
+ return true;
}
/**
@@ -65,6 +85,10 @@ public function delete(User $user, Application $application): bool
*/
public function restore(User $user, Application $application): bool
{
+ // Authorization temporarily disabled
+ /*
+ return true;
+ */
return true;
}
@@ -73,7 +97,11 @@ public function restore(User $user, Application $application): bool
*/
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 @@ public function forceDelete(User $user, Application $application): bool
*/
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 @@ public function deploy(User $user, Application $application): bool
*/
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 @@ public function manageDeployments(User $user, Application $application): bool
*/
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 @@ public function manageEnvironment(User $user, Application $application): bool
*/
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function view(User $user, ApplicationPreview $applicationPreview): bool
*/
public function create(User $user): bool
{
- return $user->isAdmin();
+ // return $user->isAdmin();
+ return true;
}
/**
@@ -37,11 +39,12 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, ApplicationPreview $applicationPreview): Resp
*/
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 @@ public function delete(User $user, ApplicationPreview $applicationPreview): bool
*/
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 @@ public function restore(User $user, ApplicationPreview $applicationPreview): boo
*/
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 @@ public function forceDelete(User $user, ApplicationPreview $applicationPreview):
*/
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 @@ public function deploy(User $user, ApplicationPreview $applicationPreview): bool
*/
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function view(User $user, ApplicationSetting $applicationSetting): bool
*/
public function create(User $user): bool
{
- return $user->isAdmin();
+ // return $user->isAdmin();
+ return true;
}
/**
@@ -36,7 +38,8 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, ApplicationSetting $applicationSetting): bool
*/
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 @@ public function delete(User $user, ApplicationSetting $applicationSetting): bool
*/
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 @@ public function restore(User $user, ApplicationSetting $applicationSetting): boo
*/
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function view(User $user, $database): bool
*/
public function create(User $user): bool
{
- return $user->isAdmin();
+ // return $user->isAdmin();
+ return true;
}
/**
@@ -36,11 +38,12 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, $database): Response
*/
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 @@ public function delete(User $user, $database): bool
*/
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 @@ public function restore(User $user, $database): bool
*/
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 @@ public function forceDelete(User $user, $database): bool
*/
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 @@ public function manage(User $user, $database): bool
*/
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 @@ public function manageBackups(User $user, $database): bool
*/
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function view(User $user, Environment $environment): bool
*/
public function create(User $user): bool
{
- return $user->isAdmin();
+ // return $user->isAdmin();
+ return true;
}
/**
@@ -36,7 +38,8 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, Environment $environment): bool
*/
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 @@ public function delete(User $user, Environment $environment): bool
*/
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 @@ public function restore(User $user, Environment $environment): bool
*/
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function view(User $user, PrivateKey $privateKey): bool
*/
public function create(User $user): bool
{
- return $user->isAdmin();
+ // return $user->isAdmin();
+ return true;
}
/**
@@ -36,7 +38,8 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, PrivateKey $privateKey): bool
*/
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function view(User $user, Project $project): bool
*/
public function create(User $user): bool
{
- return $user->isAdmin();
+ // return $user->isAdmin();
+ return true;
}
/**
@@ -36,7 +38,8 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, Project $project): bool
*/
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 @@ public function delete(User $user, Project $project): bool
*/
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 @@ public function restore(User $user, Project $project): bool
*/
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 @@ public function create(User $user, string $resourceClass): bool
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function create(User $user): bool
/**
* 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 @@ public function update(User $user, Server $server): bool
*/
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 @@ public function forceDelete(User $user, S3Storage $storage): bool
{
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, Server $server): bool
*/
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 @@ public function forceDelete(User $user, Server $server): bool
*/
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 @@ public function manageProxy(User $user, Server $server): bool
*/
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 @@ public function manageSentinel(User $user, Server $server): bool
*/
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 @@ public function manageCaCertificate(User $user, Server $server): bool
*/
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 @@ public function viewTerminal(User $user, Server $server): bool
*/
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 @@ public function view(User $user, Service $service): bool
*/
public function create(User $user): bool
{
- return $user->isAdmin();
+ // return $user->isAdmin();
+ return true;
}
/**
@@ -36,7 +37,13 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, Service $service): bool
*/
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 @@ public function delete(User $user, Service $service): bool
*/
public function restore(User $user, Service $service): bool
{
+ // return true;
return true;
}
@@ -64,16 +73,23 @@ public function restore(User $user, Service $service): bool
*/
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 @@ public function stop(User $user, Service $service): bool
*/
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 @@ public function manageEnvironment(User $user, Service $service): bool
*/
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function view(User $user, StandaloneDocker $standaloneDocker): bool
*/
public function create(User $user): bool
{
- return $user->isAdmin();
+ // return $user->isAdmin();
+ return true;
}
/**
@@ -36,7 +37,8 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, StandaloneDocker $standaloneDocker): bool
*/
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 @@ public function delete(User $user, StandaloneDocker $standaloneDocker): bool
*/
public function restore(User $user, StandaloneDocker $standaloneDocker): bool
{
- return false;
+ // return false;
+ return true;
}
/**
@@ -60,6 +64,7 @@ public function restore(User $user, StandaloneDocker $standaloneDocker): bool
*/
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 @@ public function viewAny(User $user): bool
*/
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 @@ public function view(User $user, SwarmDocker $swarmDocker): bool
*/
public function create(User $user): bool
{
- return $user->isAdmin();
+ // return $user->isAdmin();
+ return true;
}
/**
@@ -36,7 +37,8 @@ public function create(User $user): bool
*/
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 @@ public function update(User $user, SwarmDocker $swarmDocker): bool
*/
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 @@ public function delete(User $user, SwarmDocker $swarmDocker): bool
*/
public function restore(User $user, SwarmDocker $swarmDocker): bool
{
- return false;
+ // return false;
+ return true;
}
/**
@@ -60,6 +64,7 @@ public function restore(User $user, SwarmDocker $swarmDocker): bool
*/
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 @@ public function boot(): void
{
// 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 @@
use Closure;
use Illuminate\Contracts\View\View;
+use Illuminate\Support\Facades\Gate;
use Illuminate\View\Component;
class Button extends Component
@@ -17,7 +18,19 @@ public function __construct(
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 @@
use Closure;
use Illuminate\Contracts\View\View;
+use Illuminate\Support\Facades\Gate;
use Illuminate\View\Component;
class Checkbox extends Component
@@ -22,7 +23,20 @@ public function __construct(
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 @@
use Closure;
use Illuminate\Contracts\View\View;
+use Illuminate\Support\Facades\Gate;
use Illuminate\View\Component;
use Visus\Cuid2\Cuid2;
@@ -26,7 +27,19 @@ public function __construct(
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 @@
use Closure;
use Illuminate\Contracts\View\View;
+use Illuminate\Support\Facades\Gate;
use Illuminate\View\Component;
use Visus\Cuid2\Cuid2;
@@ -19,9 +20,19 @@ public function __construct(
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 @@
use Closure;
use Illuminate\Contracts\View\View;
+use Illuminate\Support\Facades\Gate;
use Illuminate\View\Component;
use Visus\Cuid2\Cuid2;
@@ -33,8 +34,18 @@ public function __construct(
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 @@ class="{{ request()->is('tags*') ? 'menu-item-active menu-item' : 'menu-item' }}
Tags
-
You don't have permission to create new destinations.
+Please contact your team administrator for access.
+