feat(auth): implement authorization checks for database management

This commit is contained in:
Andras Bacsai
2025-08-23 18:50:35 +02:00
parent 6d02f6a60b
commit adb8f9d88e
17 changed files with 281 additions and 27 deletions

View File

@@ -5,6 +5,7 @@ namespace App\Livewire\Project\Database;
use App\Models\InstanceSettings; use App\Models\InstanceSettings;
use App\Models\ScheduledDatabaseBackup; use App\Models\ScheduledDatabaseBackup;
use Exception; use Exception;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Hash;
use Livewire\Attributes\Locked; use Livewire\Attributes\Locked;
@@ -14,6 +15,8 @@ use Spatie\Url\Url;
class BackupEdit extends Component class BackupEdit extends Component
{ {
use AuthorizesRequests;
public ScheduledDatabaseBackup $backup; public ScheduledDatabaseBackup $backup;
#[Locked] #[Locked]
@@ -129,6 +132,8 @@ class BackupEdit extends Component
public function delete($password) public function delete($password)
{ {
$this->authorize('manageBackups', $this->backup->database);
if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) { if (! data_get(InstanceSettings::get(), 'disable_two_step_confirmation')) {
if (! Hash::check($password, Auth::user()->password)) { if (! Hash::check($password, Auth::user()->password)) {
$this->addError('password', 'The provided password is incorrect.'); $this->addError('password', 'The provided password is incorrect.');
@@ -186,6 +191,8 @@ class BackupEdit extends Component
public function instantSave() public function instantSave()
{ {
try { try {
$this->authorize('manageBackups', $this->backup->database);
$this->syncData(true); $this->syncData(true);
$this->dispatch('success', 'Backup updated successfully.'); $this->dispatch('success', 'Backup updated successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {
@@ -214,6 +221,8 @@ class BackupEdit extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('manageBackups', $this->backup->database);
$this->syncData(true); $this->syncData(true);
$this->dispatch('success', 'Backup updated successfully.'); $this->dispatch('success', 'Backup updated successfully.');
} catch (\Throwable $e) { } catch (\Throwable $e) {

View File

@@ -3,14 +3,19 @@
namespace App\Livewire\Project\Database; namespace App\Livewire\Project\Database;
use App\Jobs\DatabaseBackupJob; use App\Jobs\DatabaseBackupJob;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Component; use Livewire\Component;
class BackupNow extends Component class BackupNow extends Component
{ {
use AuthorizesRequests;
public $backup; public $backup;
public function backupNow() public function backupNow()
{ {
$this->authorize('manageBackups', $this->backup->database);
DatabaseBackupJob::dispatch($this->backup); DatabaseBackupJob::dispatch($this->backup);
$this->dispatch('success', 'Backup queued. It will be available in a few minutes.'); $this->dispatch('success', 'Backup queued. It will be available in a few minutes.');
} }

View File

@@ -8,11 +8,14 @@ use App\Models\Server;
use App\Models\StandaloneClickhouse; use App\Models\StandaloneClickhouse;
use App\Support\ValidationPatterns; use App\Support\ValidationPatterns;
use Exception; use Exception;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Livewire\Component; use Livewire\Component;
class General extends Component class General extends Component
{ {
use AuthorizesRequests;
public Server $server; public Server $server;
public StandaloneClickhouse $database; public StandaloneClickhouse $database;
@@ -131,6 +134,8 @@ class General extends Component
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
$this->authorize('update', $this->database);
if (! $this->server->isLogDrainEnabled()) { if (! $this->server->isLogDrainEnabled()) {
$this->isLogDrainEnabled = false; $this->isLogDrainEnabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -149,6 +154,8 @@ class General extends Component
public function instantSave() public function instantSave()
{ {
try { try {
$this->authorize('update', $this->database);
if ($this->isPublic && ! $this->publicPort) { if ($this->isPublic && ! $this->publicPort) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->isPublic = false; $this->isPublic = false;
@@ -186,6 +193,8 @@ class General extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('update', $this->database);
if (str($this->publicPort)->isEmpty()) { if (str($this->publicPort)->isEmpty()) {
$this->publicPort = null; $this->publicPort = null;
} }

View File

@@ -26,6 +26,7 @@ class Configuration extends Component
public function mount() public function mount()
{ {
try {
$this->currentRoute = request()->route()->getName(); $this->currentRoute = request()->route()->getName();
$project = currentTeam() $project = currentTeam()
@@ -48,6 +49,16 @@ class Configuration extends Component
$this->database->isConfigurationChanged(true); $this->database->isConfigurationChanged(true);
$this->dispatch('configurationChanged'); $this->dispatch('configurationChanged');
} }
} catch (\Throwable $e) {
if ($e instanceof \Illuminate\Auth\Access\AuthorizationException) {
return redirect()->route('dashboard');
}
if ($e instanceof \Illuminate\Support\ItemNotFoundException) {
return redirect()->route('dashboard');
}
return handleError($e, $this);
}
} }
public function render() public function render()

View File

@@ -3,6 +3,7 @@
namespace App\Livewire\Project\Database; namespace App\Livewire\Project\Database;
use App\Models\ScheduledDatabaseBackup; use App\Models\ScheduledDatabaseBackup;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Livewire\Attributes\Locked; use Livewire\Attributes\Locked;
use Livewire\Attributes\Validate; use Livewire\Attributes\Validate;
@@ -10,6 +11,8 @@ use Livewire\Component;
class CreateScheduledBackup extends Component class CreateScheduledBackup extends Component
{ {
use AuthorizesRequests;
#[Validate(['required', 'string'])] #[Validate(['required', 'string'])]
public $frequency; public $frequency;
@@ -41,6 +44,8 @@ class CreateScheduledBackup extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('manageBackups', $this->database);
$this->validate(); $this->validate();
$isValid = validate_cron_expression($this->frequency); $isValid = validate_cron_expression($this->frequency);

View File

@@ -11,11 +11,14 @@ use App\Models\StandaloneDragonfly;
use App\Support\ValidationPatterns; use App\Support\ValidationPatterns;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Livewire\Component; use Livewire\Component;
class General extends Component class General extends Component
{ {
use AuthorizesRequests;
public Server $server; public Server $server;
public StandaloneDragonfly $database; public StandaloneDragonfly $database;
@@ -142,6 +145,8 @@ class General extends Component
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
$this->authorize('update', $this->database);
if (! $this->server->isLogDrainEnabled()) { if (! $this->server->isLogDrainEnabled()) {
$this->isLogDrainEnabled = false; $this->isLogDrainEnabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -160,6 +165,8 @@ class General extends Component
public function instantSave() public function instantSave()
{ {
try { try {
$this->authorize('update', $this->database);
if ($this->isPublic && ! $this->publicPort) { if ($this->isPublic && ! $this->publicPort) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->isPublic = false; $this->isPublic = false;
@@ -197,6 +204,8 @@ class General extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('update', $this->database);
if (str($this->publicPort)->isEmpty()) { if (str($this->publicPort)->isEmpty()) {
$this->publicPort = null; $this->publicPort = null;
} }
@@ -216,6 +225,8 @@ class General extends Component
public function instantSaveSSL() public function instantSaveSSL()
{ {
try { try {
$this->authorize('update', $this->database);
$this->syncData(true); $this->syncData(true);
$this->dispatch('success', 'SSL configuration updated.'); $this->dispatch('success', 'SSL configuration updated.');
} catch (Exception $e) { } catch (Exception $e) {
@@ -226,6 +237,8 @@ class General extends Component
public function regenerateSslCertificate() public function regenerateSslCertificate()
{ {
try { try {
$this->authorize('update', $this->database);
$existingCert = $this->database->sslCertificates()->first(); $existingCert = $this->database->sslCertificates()->first();
if (! $existingCert) { if (! $existingCert) {

View File

@@ -7,10 +7,13 @@ use App\Actions\Database\StartDatabase;
use App\Actions\Database\StopDatabase; use App\Actions\Database\StopDatabase;
use App\Actions\Docker\GetContainersStatus; use App\Actions\Docker\GetContainersStatus;
use App\Events\ServiceStatusChanged; use App\Events\ServiceStatusChanged;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Component; use Livewire\Component;
class Heading extends Component class Heading extends Component
{ {
use AuthorizesRequests;
public $database; public $database;
public array $parameters; public array $parameters;
@@ -67,6 +70,8 @@ class Heading extends Component
public function stop() public function stop()
{ {
try { try {
$this->authorize('manage', $this->database);
$this->dispatch('info', 'Gracefully stopping database.'); $this->dispatch('info', 'Gracefully stopping database.');
StopDatabase::dispatch($this->database, false, $this->docker_cleanup); StopDatabase::dispatch($this->database, false, $this->docker_cleanup);
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -76,12 +81,16 @@ class Heading extends Component
public function restart() public function restart()
{ {
$this->authorize('manage', $this->database);
$activity = RestartDatabase::run($this->database); $activity = RestartDatabase::run($this->database);
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class); $this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
} }
public function start() public function start()
{ {
$this->authorize('manage', $this->database);
$activity = StartDatabase::run($this->database); $activity = StartDatabase::run($this->database);
$this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class); $this->dispatch('activityMonitor', $activity->id, ServiceStatusChanged::class);
} }

View File

@@ -3,12 +3,15 @@
namespace App\Livewire\Project\Database; namespace App\Livewire\Project\Database;
use App\Models\Server; use App\Models\Server;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Livewire\Component; use Livewire\Component;
class Import extends Component class Import extends Component
{ {
use AuthorizesRequests;
public bool $unsupported = false; public bool $unsupported = false;
public $resource; public $resource;
@@ -165,6 +168,8 @@ EOD;
public function runImport() public function runImport()
{ {
$this->authorize('update', $this->resource);
if ($this->filename === '') { if ($this->filename === '') {
$this->dispatch('error', 'Please select a file to import.'); $this->dispatch('error', 'Please select a file to import.');

View File

@@ -11,11 +11,14 @@ use App\Models\StandaloneKeydb;
use App\Support\ValidationPatterns; use App\Support\ValidationPatterns;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Livewire\Component; use Livewire\Component;
class General extends Component class General extends Component
{ {
use AuthorizesRequests;
public Server $server; public Server $server;
public StandaloneKeydb $database; public StandaloneKeydb $database;
@@ -150,6 +153,8 @@ class General extends Component
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
$this->authorize('update', $this->database);
if (! $this->server->isLogDrainEnabled()) { if (! $this->server->isLogDrainEnabled()) {
$this->isLogDrainEnabled = false; $this->isLogDrainEnabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -168,6 +173,8 @@ class General extends Component
public function instantSave() public function instantSave()
{ {
try { try {
$this->authorize('update', $this->database);
if ($this->isPublic && ! $this->publicPort) { if ($this->isPublic && ! $this->publicPort) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->isPublic = false; $this->isPublic = false;
@@ -205,6 +212,8 @@ class General extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('manageEnvironment', $this->database);
if (str($this->publicPort)->isEmpty()) { if (str($this->publicPort)->isEmpty()) {
$this->publicPort = null; $this->publicPort = null;
} }
@@ -224,6 +233,8 @@ class General extends Component
public function instantSaveSSL() public function instantSaveSSL()
{ {
try { try {
$this->authorize('update', $this->database);
$this->syncData(true); $this->syncData(true);
$this->dispatch('success', 'SSL configuration updated.'); $this->dispatch('success', 'SSL configuration updated.');
} catch (Exception $e) { } catch (Exception $e) {
@@ -234,6 +245,8 @@ class General extends Component
public function regenerateSslCertificate() public function regenerateSslCertificate()
{ {
try { try {
$this->authorize('update', $this->database);
$existingCert = $this->database->sslCertificates()->first(); $existingCert = $this->database->sslCertificates()->first();
if (! $existingCert) { if (! $existingCert) {

View File

@@ -11,11 +11,14 @@ use App\Models\StandaloneMariadb;
use App\Support\ValidationPatterns; use App\Support\ValidationPatterns;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Livewire\Component; use Livewire\Component;
class General extends Component class General extends Component
{ {
use AuthorizesRequests;
protected $listeners = ['refresh']; protected $listeners = ['refresh'];
public Server $server; public Server $server;
@@ -108,6 +111,8 @@ class General extends Component
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
$this->authorize('update', $this->database);
if (! $this->server->isLogDrainEnabled()) { if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -125,6 +130,8 @@ class General extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('update', $this->database);
if (str($this->database->public_port)->isEmpty()) { if (str($this->database->public_port)->isEmpty()) {
$this->database->public_port = null; $this->database->public_port = null;
} }
@@ -145,6 +152,8 @@ class General extends Component
public function instantSave() public function instantSave()
{ {
try { try {
$this->authorize('update', $this->database);
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
@@ -176,6 +185,8 @@ class General extends Component
public function instantSaveSSL() public function instantSaveSSL()
{ {
try { try {
$this->authorize('update', $this->database);
$this->database->save(); $this->database->save();
$this->dispatch('success', 'SSL configuration updated.'); $this->dispatch('success', 'SSL configuration updated.');
} catch (Exception $e) { } catch (Exception $e) {
@@ -186,6 +197,8 @@ class General extends Component
public function regenerateSslCertificate() public function regenerateSslCertificate()
{ {
try { try {
$this->authorize('update', $this->database);
$existingCert = $this->database->sslCertificates()->first(); $existingCert = $this->database->sslCertificates()->first();
if (! $existingCert) { if (! $existingCert) {

View File

@@ -11,11 +11,14 @@ use App\Models\StandaloneMongodb;
use App\Support\ValidationPatterns; use App\Support\ValidationPatterns;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Livewire\Component; use Livewire\Component;
class General extends Component class General extends Component
{ {
use AuthorizesRequests;
protected $listeners = ['refresh']; protected $listeners = ['refresh'];
public Server $server; public Server $server;
@@ -108,6 +111,8 @@ class General extends Component
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
$this->authorize('update', $this->database);
if (! $this->server->isLogDrainEnabled()) { if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -125,6 +130,8 @@ class General extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('update', $this->database);
if (str($this->database->public_port)->isEmpty()) { if (str($this->database->public_port)->isEmpty()) {
$this->database->public_port = null; $this->database->public_port = null;
} }
@@ -148,6 +155,8 @@ class General extends Component
public function instantSave() public function instantSave()
{ {
try { try {
$this->authorize('update', $this->database);
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
@@ -184,6 +193,8 @@ class General extends Component
public function instantSaveSSL() public function instantSaveSSL()
{ {
try { try {
$this->authorize('update', $this->database);
$this->database->save(); $this->database->save();
$this->dispatch('success', 'SSL configuration updated.'); $this->dispatch('success', 'SSL configuration updated.');
} catch (Exception $e) { } catch (Exception $e) {
@@ -194,6 +205,8 @@ class General extends Component
public function regenerateSslCertificate() public function regenerateSslCertificate()
{ {
try { try {
$this->authorize('update', $this->database);
$existingCert = $this->database->sslCertificates()->first(); $existingCert = $this->database->sslCertificates()->first();
if (! $existingCert) { if (! $existingCert) {

View File

@@ -11,11 +11,14 @@ use App\Models\StandaloneMysql;
use App\Support\ValidationPatterns; use App\Support\ValidationPatterns;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Livewire\Component; use Livewire\Component;
class General extends Component class General extends Component
{ {
use AuthorizesRequests;
protected $listeners = ['refresh']; protected $listeners = ['refresh'];
public StandaloneMysql $database; public StandaloneMysql $database;
@@ -111,6 +114,8 @@ class General extends Component
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
$this->authorize('update', $this->database);
if (! $this->server->isLogDrainEnabled()) { if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -128,6 +133,8 @@ class General extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('update', $this->database);
if (str($this->database->public_port)->isEmpty()) { if (str($this->database->public_port)->isEmpty()) {
$this->database->public_port = null; $this->database->public_port = null;
} }
@@ -148,6 +155,8 @@ class General extends Component
public function instantSave() public function instantSave()
{ {
try { try {
$this->authorize('update', $this->database);
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
@@ -184,6 +193,8 @@ class General extends Component
public function instantSaveSSL() public function instantSaveSSL()
{ {
try { try {
$this->authorize('update', $this->database);
$this->database->save(); $this->database->save();
$this->dispatch('success', 'SSL configuration updated.'); $this->dispatch('success', 'SSL configuration updated.');
} catch (Exception $e) { } catch (Exception $e) {
@@ -194,6 +205,8 @@ class General extends Component
public function regenerateSslCertificate() public function regenerateSslCertificate()
{ {
try { try {
$this->authorize('update', $this->database);
$existingCert = $this->database->sslCertificates()->first(); $existingCert = $this->database->sslCertificates()->first();
if (! $existingCert) { if (! $existingCert) {

View File

@@ -11,11 +11,14 @@ use App\Models\StandalonePostgresql;
use App\Support\ValidationPatterns; use App\Support\ValidationPatterns;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Livewire\Component; use Livewire\Component;
class General extends Component class General extends Component
{ {
use AuthorizesRequests;
public StandalonePostgresql $database; public StandalonePostgresql $database;
public Server $server; public Server $server;
@@ -118,6 +121,8 @@ class General extends Component
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
$this->authorize('update', $this->database);
if (! $this->server->isLogDrainEnabled()) { if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -140,6 +145,8 @@ class General extends Component
public function instantSaveSSL() public function instantSaveSSL()
{ {
try { try {
$this->authorize('update', $this->database);
$this->database->save(); $this->database->save();
$this->dispatch('success', 'SSL configuration updated.'); $this->dispatch('success', 'SSL configuration updated.');
$this->db_url = $this->database->internal_db_url; $this->db_url = $this->database->internal_db_url;
@@ -152,6 +159,8 @@ class General extends Component
public function regenerateSslCertificate() public function regenerateSslCertificate()
{ {
try { try {
$this->authorize('update', $this->database);
$existingCert = $this->database->sslCertificates()->first(); $existingCert = $this->database->sslCertificates()->first();
if (! $existingCert) { if (! $existingCert) {
@@ -184,6 +193,8 @@ class General extends Component
public function instantSave() public function instantSave()
{ {
try { try {
$this->authorize('update', $this->database);
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
@@ -214,6 +225,8 @@ class General extends Component
public function save_init_script($script) public function save_init_script($script)
{ {
$this->authorize('update', $this->database);
$initScripts = collect($this->database->init_scripts ?? []); $initScripts = collect($this->database->init_scripts ?? []);
$existingScript = $initScripts->firstWhere('filename', $script['filename']); $existingScript = $initScripts->firstWhere('filename', $script['filename']);
@@ -264,6 +277,8 @@ class General extends Component
public function delete_init_script($script) public function delete_init_script($script)
{ {
$this->authorize('update', $this->database);
$collection = collect($this->database->init_scripts); $collection = collect($this->database->init_scripts);
$found = $collection->firstWhere('filename', $script['filename']); $found = $collection->firstWhere('filename', $script['filename']);
if ($found) { if ($found) {
@@ -298,6 +313,8 @@ class General extends Component
public function save_new_init_script() public function save_new_init_script()
{ {
$this->authorize('update', $this->database);
$this->validate([ $this->validate([
'new_filename' => 'required|string', 'new_filename' => 'required|string',
'new_content' => 'required|string', 'new_content' => 'required|string',
@@ -327,6 +344,8 @@ class General extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('update', $this->database);
if (str($this->database->public_port)->isEmpty()) { if (str($this->database->public_port)->isEmpty()) {
$this->database->public_port = null; $this->database->public_port = null;
} }

View File

@@ -11,11 +11,14 @@ use App\Models\StandaloneRedis;
use App\Support\ValidationPatterns; use App\Support\ValidationPatterns;
use Carbon\Carbon; use Carbon\Carbon;
use Exception; use Exception;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Livewire\Component; use Livewire\Component;
class General extends Component class General extends Component
{ {
use AuthorizesRequests;
public Server $server; public Server $server;
public StandaloneRedis $database; public StandaloneRedis $database;
@@ -105,6 +108,8 @@ class General extends Component
public function instantSaveAdvanced() public function instantSaveAdvanced()
{ {
try { try {
$this->authorize('update', $this->database);
if (! $this->server->isLogDrainEnabled()) { if (! $this->server->isLogDrainEnabled()) {
$this->database->is_log_drain_enabled = false; $this->database->is_log_drain_enabled = false;
$this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.'); $this->dispatch('error', 'Log drain is not enabled on the server. Please enable it first.');
@@ -122,6 +127,8 @@ class General extends Component
public function submit() public function submit()
{ {
try { try {
$this->authorize('manageEnvironment', $this->database);
$this->validate(); $this->validate();
if (version_compare($this->redis_version, '6.0', '>=')) { if (version_compare($this->redis_version, '6.0', '>=')) {
@@ -147,6 +154,8 @@ class General extends Component
public function instantSave() public function instantSave()
{ {
try { try {
$this->authorize('update', $this->database);
if ($this->database->is_public && ! $this->database->public_port) { if ($this->database->is_public && ! $this->database->public_port) {
$this->dispatch('error', 'Public port is required.'); $this->dispatch('error', 'Public port is required.');
$this->database->is_public = false; $this->database->is_public = false;
@@ -178,6 +187,8 @@ class General extends Component
public function instantSaveSSL() public function instantSaveSSL()
{ {
try { try {
$this->authorize('update', $this->database);
$this->database->save(); $this->database->save();
$this->dispatch('success', 'SSL configuration updated.'); $this->dispatch('success', 'SSL configuration updated.');
} catch (Exception $e) { } catch (Exception $e) {
@@ -188,6 +199,8 @@ class General extends Component
public function regenerateSslCertificate() public function regenerateSslCertificate()
{ {
try { try {
$this->authorize('update', $this->database);
$existingCert = $this->database->sslCertificates()->first(); $existingCert = $this->database->sslCertificates()->first();
if (! $existingCert) { if (! $existingCert) {

View File

@@ -3,10 +3,13 @@
namespace App\Livewire\Project\Database; namespace App\Livewire\Project\Database;
use App\Models\ScheduledDatabaseBackup; use App\Models\ScheduledDatabaseBackup;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Component; use Livewire\Component;
class ScheduledBackups extends Component class ScheduledBackups extends Component
{ {
use AuthorizesRequests;
public $database; public $database;
public $parameters; public $parameters;
@@ -53,6 +56,8 @@ class ScheduledBackups extends Component
public function setCustomType() public function setCustomType()
{ {
$this->authorize('update', $this->database);
$this->database->custom_type = $this->custom_type; $this->database->custom_type = $this->custom_type;
$this->database->save(); $this->database->save();
$this->dispatch('success', 'Database type set.'); $this->dispatch('success', 'Database type set.');
@@ -61,7 +66,10 @@ class ScheduledBackups extends Component
public function delete($scheduled_backup_id): void public function delete($scheduled_backup_id): void
{ {
$this->database->scheduledBackups->find($scheduled_backup_id)->delete(); $backup = $this->database->scheduledBackups->find($scheduled_backup_id);
$this->authorize('manageBackups', $this->database);
$backup->delete();
$this->dispatch('success', 'Scheduled backup deleted.'); $this->dispatch('success', 'Scheduled backup deleted.');
$this->refreshScheduledBackups(); $this->refreshScheduledBackups();
} }

View File

@@ -45,12 +45,16 @@ class All extends Component
public function instantSave() public function instantSave()
{ {
try {
$this->authorize('manageEnvironment', $this->resource); $this->authorize('manageEnvironment', $this->resource);
$this->resource->settings->is_env_sorting_enabled = $this->is_env_sorting_enabled; $this->resource->settings->is_env_sorting_enabled = $this->is_env_sorting_enabled;
$this->resource->settings->save(); $this->resource->settings->save();
$this->sortEnvironmentVariables(); $this->sortEnvironmentVariables();
$this->dispatch('success', 'Environment variable settings updated.'); $this->dispatch('success', 'Environment variable settings updated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
} }
public function sortEnvironmentVariables() public function sortEnvironmentVariables()
@@ -98,9 +102,8 @@ class All extends Component
public function submit($data = null) public function submit($data = null)
{ {
$this->authorize('manageEnvironment', $this->resource);
try { try {
$this->authorize('manageEnvironment', $this->resource);
if ($data === null) { if ($data === null) {
$this->handleBulkSubmit(); $this->handleBulkSubmit();
} else { } else {

View File

@@ -0,0 +1,93 @@
<?php
namespace App\Policies;
use App\Models\User;
use Illuminate\Auth\Access\Response;
class DatabasePolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return true;
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, $database): bool
{
return $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null;
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->isAdmin();
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, $database): Response
{
if ($user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null) {
return Response::allow();
}
return Response::deny('As a member, you cannot update this database.<br/><br/>You need at least admin or owner permissions.');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, $database): bool
{
return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null;
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, $database): bool
{
return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, $database): bool
{
return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null;
}
/**
* Determine whether the user can start/stop the database.
*/
public function manage(User $user, $database): bool
{
return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null;
}
/**
* Determine whether the user can manage database backups.
*/
public function manageBackups(User $user, $database): bool
{
return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null;
}
/**
* Determine whether the user can manage environment variables.
*/
public function manageEnvironment(User $user, $database): bool
{
return $user->isAdmin() && $user->teams()->get()->firstWhere('id', $database->team()->first()->id) !== null;
}
}