feat(auth): implement authorization checks for application management

This commit is contained in:
Andras Bacsai
2025-08-22 16:47:59 +02:00
parent 37ee6717e9
commit 40f108d6e1
14 changed files with 449 additions and 144 deletions

View File

@@ -5,6 +5,7 @@ namespace App\Livewire\Project\Application;
use App\Actions\Application\GenerateConfig;
use App\Models\Application;
use App\Support\ValidationPatterns;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Collection;
use Livewire\Component;
use Spatie\Url\Url;
@@ -12,6 +13,8 @@ use Visus\Cuid2\Cuid2;
class General extends Component
{
use AuthorizesRequests;
public string $applicationId;
public Application $application;
@@ -224,37 +227,44 @@ class General extends Component
public function instantSave()
{
if ($this->application->settings->isDirty('is_spa')) {
$this->generateNginxConfiguration($this->application->settings->is_spa ? 'spa' : 'static');
}
if ($this->application->isDirty('is_http_basic_auth_enabled')) {
$this->application->save();
}
$this->application->settings->save();
$this->dispatch('success', 'Settings saved.');
$this->application->refresh();
try {
$this->authorize('update', $this->application);
// If port_exposes changed, reset default labels
if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
$this->resetDefaultLabels(false);
}
if ($this->is_preserve_repository_enabled !== $this->application->settings->is_preserve_repository_enabled) {
if ($this->application->settings->is_preserve_repository_enabled === false) {
$this->application->fileStorages->each(function ($storage) {
$storage->is_based_on_git = $this->application->settings->is_preserve_repository_enabled;
$storage->save();
});
if ($this->application->settings->isDirty('is_spa')) {
$this->generateNginxConfiguration($this->application->settings->is_spa ? 'spa' : 'static');
}
}
if ($this->application->settings->is_container_label_readonly_enabled) {
$this->resetDefaultLabels(false);
}
if ($this->application->isDirty('is_http_basic_auth_enabled')) {
$this->application->save();
}
$this->application->settings->save();
$this->dispatch('success', 'Settings saved.');
$this->application->refresh();
// If port_exposes changed, reset default labels
if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
$this->resetDefaultLabels(false);
}
if ($this->is_preserve_repository_enabled !== $this->application->settings->is_preserve_repository_enabled) {
if ($this->application->settings->is_preserve_repository_enabled === false) {
$this->application->fileStorages->each(function ($storage) {
$storage->is_based_on_git = $this->application->settings->is_preserve_repository_enabled;
$storage->save();
});
}
}
if ($this->application->settings->is_container_label_readonly_enabled) {
$this->resetDefaultLabels(false);
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function loadComposeFile($isInit = false, $showToast = true)
{
try {
$this->authorize('update', $this->application);
if ($isInit && $this->application->docker_compose_raw) {
return;
}
@@ -293,35 +303,41 @@ class General extends Component
public function generateDomain(string $serviceName)
{
$uuid = new Cuid2;
$domain = generateUrl(server: $this->application->destination->server, random: $uuid);
$sanitizedKey = str($serviceName)->slug('_')->toString();
$this->parsedServiceDomains[$sanitizedKey]['domain'] = $domain;
try {
$this->authorize('update', $this->application);
// Convert back to original service names for storage
$originalDomains = [];
foreach ($this->parsedServiceDomains as $key => $value) {
// Find the original service name by checking parsed services
$originalServiceName = $key;
if (isset($this->parsedServices['services'])) {
foreach ($this->parsedServices['services'] as $originalName => $service) {
if (str($originalName)->slug('_')->toString() === $key) {
$originalServiceName = $originalName;
break;
$uuid = new Cuid2;
$domain = generateUrl(server: $this->application->destination->server, random: $uuid);
$sanitizedKey = str($serviceName)->slug('_')->toString();
$this->parsedServiceDomains[$sanitizedKey]['domain'] = $domain;
// Convert back to original service names for storage
$originalDomains = [];
foreach ($this->parsedServiceDomains as $key => $value) {
// Find the original service name by checking parsed services
$originalServiceName = $key;
if (isset($this->parsedServices['services'])) {
foreach ($this->parsedServices['services'] as $originalName => $service) {
if (str($originalName)->slug('_')->toString() === $key) {
$originalServiceName = $originalName;
break;
}
}
}
$originalDomains[$originalServiceName] = $value;
}
$originalDomains[$originalServiceName] = $value;
}
$this->application->docker_compose_domains = json_encode($originalDomains);
$this->application->save();
$this->dispatch('success', 'Domain generated.');
if ($this->application->build_pack === 'dockercompose') {
$this->loadComposeFile(showToast: false);
}
$this->application->docker_compose_domains = json_encode($originalDomains);
$this->application->save();
$this->dispatch('success', 'Domain generated.');
if ($this->application->build_pack === 'dockercompose') {
$this->loadComposeFile(showToast: false);
}
return $domain;
return $domain;
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function updatedApplicationBaseDirectory()
@@ -374,21 +390,33 @@ class General extends Component
public function getWildcardDomain()
{
$server = data_get($this->application, 'destination.server');
if ($server) {
$fqdn = generateFqdn(server: $server, random: $this->application->uuid, parserVersion: $this->application->compose_parsing_version);
$this->application->fqdn = $fqdn;
$this->application->save();
$this->resetDefaultLabels();
$this->dispatch('success', 'Wildcard domain generated.');
try {
$this->authorize('update', $this->application);
$server = data_get($this->application, 'destination.server');
if ($server) {
$fqdn = generateFqdn(server: $server, random: $this->application->uuid, parserVersion: $this->application->compose_parsing_version);
$this->application->fqdn = $fqdn;
$this->application->save();
$this->resetDefaultLabels();
$this->dispatch('success', 'Wildcard domain generated.');
}
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function generateNginxConfiguration($type = 'static')
{
$this->application->custom_nginx_configuration = defaultNginxConfiguration($type);
$this->application->save();
$this->dispatch('success', 'Nginx configuration generated.');
try {
$this->authorize('update', $this->application);
$this->application->custom_nginx_configuration = defaultNginxConfiguration($type);
$this->application->save();
$this->dispatch('success', 'Nginx configuration generated.');
} catch (\Throwable $e) {
return handleError($e, $this);
}
}
public function resetDefaultLabels($manualReset = false)
@@ -430,6 +458,8 @@ class General extends Component
public function setRedirect()
{
$this->authorize('update', $this->application);
try {
$has_www = collect($this->application->fqdns)->filter(fn ($fqdn) => str($fqdn)->contains('www.'))->count();
if ($has_www === 0 && $this->application->redirect === 'www') {
@@ -448,6 +478,7 @@ class General extends Component
public function submit($showToaster = true)
{
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) {