fix(livewire): add Locked attributes and consolidate container name validation

- Add #[Locked] to server-set properties on Import component (resourceId,
  resourceType, serverId, resourceUuid, resourceDbType, container) to
  prevent client-side modification via Livewire wire protocol
- Add container name validation in runImport() and restoreFromS3()
  using shared ValidationPatterns::isValidContainerName()
- Scope server lookup to current team via ownedByCurrentTeam()
- Consolidate duplicate container name regex from Import,
  ExecuteContainerCommand, and Terminal into shared
  ValidationPatterns::isValidContainerName() static helper
- Add tests for container name validation, locked attributes, and
  team-scoped server lookup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Andras BacsaiandClaude Opus 4.6 committed 2026-03-25 20:21:39 +01:00
1 parent 0fed553207
commit d486bf09ab
5 files changed
+158 -3

No files matched your search

+21 -1
View File
@@ -5,10 +5,12 @@ namespace App\Livewire\Project\Database;
use App\Models\S3Storage;
use App\Models\Server;
use App\Models\Service;
use App\Support\ValidationPatterns;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Locked;
use Livewire\Component;
class Import extends Component
@@ -104,17 +106,22 @@ class Import extends Component
public bool $unsupported = false;
// Store IDs instead of models for proper Livewire serialization
#[Locked]
public ?int $resourceId = null;
#[Locked]
public ?string $resourceType = null;
#[Locked]
public ?int $serverId = null;
// View-friendly properties to avoid computed property access in Blade
#[Locked]
public string $resourceUuid = '';
public string $resourceStatus = '';
#[Locked]
public string $resourceDbType = '';
public array $parameters = [];
@@ -135,6 +142,7 @@ class Import extends Component
public bool $error = false;
#[Locked]
public string $container;
public array $importCommands = [];
@@ -181,7 +189,7 @@ class Import extends Component
return null;
}
return Server::find($this->serverId);
return Server::ownedByCurrentTeam()->find($this->serverId);
}
public function getListeners()
@@ -409,6 +417,12 @@ EOD;
$this->authorize('update', $this->resource);
if (! ValidationPatterns::isValidContainerName($this->container)) {
$this->dispatch('error', 'Invalid container name.');
return true;
}
if ($this->filename === '') {
$this->dispatch('error', 'Please select a file to import.');
@@ -593,6 +607,12 @@ EOD;
$this->authorize('update', $this->resource);
if (! ValidationPatterns::isValidContainerName($this->container)) {
$this->dispatch('error', 'Invalid container name.');
return true;
}
if (! $this->s3StorageId || blank($this->s3Path)) {
$this->dispatch('error', 'Please select S3 storage and provide a path first.');
@@ -5,6 +5,7 @@ namespace App\Livewire\Project\Shared;
use App\Models\Application;
use App\Models\Server;
use App\Models\Service;
use App\Support\ValidationPatterns;
use Illuminate\Support\Collection;
use Livewire\Attributes\On;
use Livewire\Component;
@@ -181,7 +182,7 @@ class ExecuteContainerCommand extends Component
}
try {
// Validate container name format
if (! preg_match('/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/', $this->selected_container)) {
if (! ValidationPatterns::isValidContainerName($this->selected_container)) {
throw new \InvalidArgumentException('Invalid container name format');
}
+2 -1
View File
@@ -4,6 +4,7 @@ namespace App\Livewire\Project\Shared;
use App\Helpers\SshMultiplexingHelper;
use App\Models\Server;
use App\Support\ValidationPatterns;
use Livewire\Attributes\On;
use Livewire\Component;
@@ -36,7 +37,7 @@ class Terminal extends Component
if ($isContainer) {
// Validate container identifier format (alphanumeric, dashes, and underscores only)
if (! preg_match('/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/', $identifier)) {
if (! ValidationPatterns::isValidContainerName($identifier)) {
throw new \InvalidArgumentException('Invalid container identifier format');
}