mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-15 16:14:35 +00:00
fix(security): enforce team access on mutable actions
Authorize cloud provider token access, audit sensitive operations, and standardize public IDs across deployment and resource flows.
This commit is contained in:
1 parent
9dca7ca351
commit
062ad57740
83 files changed
+824
-278
No files matched your search
@@ -13,7 +13,6 @@ use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Collection;
|
||||
use Livewire\Attributes\Url;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Index extends Component
|
||||
{
|
||||
@@ -470,7 +469,7 @@ class Index extends Component
|
||||
$this->createdProject = Project::create([
|
||||
'name' => 'My first project',
|
||||
'team_id' => currentTeam()->id,
|
||||
'uuid' => (string) new Cuid2,
|
||||
'uuid' => new_public_id(),
|
||||
]);
|
||||
$this->currentState = 'create-resource';
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Docker extends Component
|
||||
{
|
||||
@@ -35,7 +34,7 @@ class Docker extends Component
|
||||
|
||||
public function mount(?string $server_id = null): void
|
||||
{
|
||||
$this->network = (string) new Cuid2;
|
||||
$this->network = new_public_id();
|
||||
$this->servers = Server::isUsable()->get();
|
||||
|
||||
if (filled($server_id)) {
|
||||
@@ -68,7 +67,7 @@ class Docker extends Component
|
||||
|
||||
public function generateName(): void
|
||||
{
|
||||
$name = data_get($this->selectedServer, 'name', new Cuid2);
|
||||
$name = data_get($this->selectedServer, 'name', new_public_id());
|
||||
$this->name = str("{$name}-{$this->network}")->kebab();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Livewire;
|
||||
|
||||
// use Livewire\Component;
|
||||
use Illuminate\View\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class MonacoEditor extends Component
|
||||
{
|
||||
@@ -40,7 +39,7 @@ class MonacoEditor extends Component
|
||||
public function render()
|
||||
{
|
||||
if (is_null($this->id)) {
|
||||
$this->id = new Cuid2;
|
||||
$this->id = new_public_id();
|
||||
}
|
||||
|
||||
if (is_null($this->name)) {
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Models\Project;
|
||||
use App\Support\ValidationPatterns;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class AddEmpty extends Component
|
||||
{
|
||||
@@ -38,7 +37,7 @@ class AddEmpty extends Component
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'team_id' => currentTeam()->id,
|
||||
'uuid' => (string) new Cuid2,
|
||||
'uuid' => new_public_id(),
|
||||
]);
|
||||
|
||||
$productionEnvironment = $project->environments()->where('name', 'production')->first();
|
||||
|
||||
@@ -13,7 +13,6 @@ use Illuminate\Support\Collection;
|
||||
use Livewire\Component;
|
||||
use Livewire\Features\SupportEvents\Event;
|
||||
use Spatie\Url\Url;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class General extends Component
|
||||
{
|
||||
@@ -549,7 +548,7 @@ class General extends Component
|
||||
try {
|
||||
$this->authorize('update', $this->application);
|
||||
|
||||
$uuid = new Cuid2;
|
||||
$uuid = new_public_id();
|
||||
$domain = generateUrl(server: $this->application->destination->server, random: $uuid);
|
||||
$sanitizedKey = str($serviceName)->replace('-', '_')->replace('.', '_')->toString();
|
||||
$this->parsedServiceDomains[$sanitizedKey]['domain'] = $domain;
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Actions\Docker\GetContainersStatus;
|
||||
use App\Models\Application;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Heading extends Component
|
||||
{
|
||||
@@ -129,7 +128,7 @@ class Heading extends Component
|
||||
|
||||
protected function setDeploymentUuid()
|
||||
{
|
||||
$this->deploymentUuid = new Cuid2;
|
||||
$this->deploymentUuid = new_public_id();
|
||||
$this->parameters['deployment_uuid'] = $this->deploymentUuid;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ use App\Models\ApplicationPreview;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Collection;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Previews extends Component
|
||||
{
|
||||
@@ -312,7 +311,7 @@ class Previews extends Component
|
||||
|
||||
protected function setDeploymentUuid()
|
||||
{
|
||||
$this->deployment_uuid = new Cuid2;
|
||||
$this->deployment_uuid = new_public_id();
|
||||
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Models\ApplicationPreview;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
use Spatie\Url\Url;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class PreviewsCompose extends Component
|
||||
{
|
||||
@@ -64,7 +63,7 @@ class PreviewsCompose extends Component
|
||||
if (empty($domain_string)) {
|
||||
$server = $this->preview->application->destination->server;
|
||||
$template = $this->preview->application->preview_url_template;
|
||||
$random = new Cuid2;
|
||||
$random = new_public_id();
|
||||
|
||||
// Generate a unique domain like main app services do
|
||||
$generated_fqdn = generateUrl(server: $server, random: $random);
|
||||
@@ -79,7 +78,7 @@ class PreviewsCompose extends Component
|
||||
$domain_list = explode(',', $domain_string);
|
||||
$preview_fqdns = [];
|
||||
$template = $this->preview->application->preview_url_template;
|
||||
$random = new Cuid2;
|
||||
$random = new_public_id();
|
||||
|
||||
foreach ($domain_list as $single_domain) {
|
||||
$single_domain = trim($single_domain);
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Models\Application;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Rollback extends Component
|
||||
{
|
||||
@@ -52,7 +51,7 @@ class Rollback extends Component
|
||||
|
||||
$commit = validateGitRef($commit, 'rollback commit');
|
||||
|
||||
$deployment_uuid = new Cuid2;
|
||||
$deployment_uuid = new_public_id();
|
||||
|
||||
$result = queue_application_deployment(
|
||||
application: $this->application,
|
||||
|
||||
@@ -13,7 +13,6 @@ use App\Models\Server;
|
||||
use App\Support\ValidationPatterns;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class CloneMe extends Component
|
||||
{
|
||||
@@ -64,7 +63,7 @@ class CloneMe extends Component
|
||||
->servers()
|
||||
->get()
|
||||
->reject(fn ($server) => $server->isBuildServer());
|
||||
$this->newName = str($this->project->name.'-clone-'.(string) new Cuid2)->slug();
|
||||
$this->newName = str($this->project->name.'-clone-'.new_public_id())->slug();
|
||||
}
|
||||
|
||||
public function toggleVolumeCloning(bool $value)
|
||||
@@ -112,7 +111,7 @@ class CloneMe extends Component
|
||||
if ($this->environment->name !== 'production') {
|
||||
$project->environments()->create([
|
||||
'name' => $this->environment->name,
|
||||
'uuid' => (string) new Cuid2,
|
||||
'uuid' => new_public_id(),
|
||||
]);
|
||||
}
|
||||
$environment = $project->environments->where('name', $this->environment->name)->first();
|
||||
@@ -124,7 +123,7 @@ class CloneMe extends Component
|
||||
$project = $this->project;
|
||||
$environment = $this->project->environments()->create([
|
||||
'name' => $this->newName,
|
||||
'uuid' => (string) new Cuid2,
|
||||
'uuid' => new_public_id(),
|
||||
]);
|
||||
}
|
||||
$applications = $this->environment->applications;
|
||||
@@ -138,7 +137,7 @@ class CloneMe extends Component
|
||||
}
|
||||
|
||||
foreach ($databases as $database) {
|
||||
$uuid = (string) new Cuid2;
|
||||
$uuid = new_public_id();
|
||||
$newDatabase = $database->replicate([
|
||||
'id',
|
||||
'created_at',
|
||||
@@ -229,7 +228,7 @@ class CloneMe extends Component
|
||||
|
||||
$scheduledBackups = $database->scheduledBackups()->get();
|
||||
foreach ($scheduledBackups as $backup) {
|
||||
$uuid = (string) new Cuid2;
|
||||
$uuid = new_public_id();
|
||||
$newBackup = $backup->replicate([
|
||||
'id',
|
||||
'created_at',
|
||||
@@ -258,7 +257,7 @@ class CloneMe extends Component
|
||||
}
|
||||
|
||||
foreach ($services as $service) {
|
||||
$uuid = (string) new Cuid2;
|
||||
$uuid = new_public_id();
|
||||
$newService = $service->replicate([
|
||||
'id',
|
||||
'created_at',
|
||||
@@ -282,7 +281,7 @@ class CloneMe extends Component
|
||||
'created_at',
|
||||
'updated_at',
|
||||
])->fill([
|
||||
'uuid' => (string) new Cuid2,
|
||||
'uuid' => new_public_id(),
|
||||
'service_id' => $newService->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
@@ -413,7 +412,7 @@ class CloneMe extends Component
|
||||
|
||||
$scheduledBackups = $database->scheduledBackups()->get();
|
||||
foreach ($scheduledBackups as $backup) {
|
||||
$uuid = (string) new Cuid2;
|
||||
$uuid = new_public_id();
|
||||
$newBackup = $backup->replicate([
|
||||
'id',
|
||||
'created_at',
|
||||
|
||||
@@ -2,13 +2,20 @@
|
||||
|
||||
namespace App\Livewire\Project\Database;
|
||||
|
||||
use App\Models\StandalonePostgresql;
|
||||
use Exception;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Attributes\Locked;
|
||||
use Livewire\Attributes\Validate;
|
||||
use Livewire\Component;
|
||||
|
||||
class InitScript extends Component
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
|
||||
#[Locked]
|
||||
public StandalonePostgresql $database;
|
||||
|
||||
#[Locked]
|
||||
public array $script;
|
||||
|
||||
@@ -35,6 +42,7 @@ class InitScript extends Component
|
||||
public function submit()
|
||||
{
|
||||
try {
|
||||
$this->authorize('update', $this->database);
|
||||
$this->validate();
|
||||
$this->script['index'] = $this->index;
|
||||
$this->script['content'] = $this->content;
|
||||
@@ -48,6 +56,7 @@ class InitScript extends Component
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
$this->authorize('update', $this->database);
|
||||
$this->dispatch('delete_init_script', $this->script);
|
||||
} catch (Exception $e) {
|
||||
return handleError($e, $this);
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Models\Project;
|
||||
use App\Services\DockerImageParser;
|
||||
use App\Support\ValidationPatterns;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class DockerImage extends Component
|
||||
{
|
||||
@@ -130,7 +129,7 @@ class DockerImage extends Component
|
||||
$imageTag = $parser->isImageHash() ? 'sha256-'.$parser->getTag() : $parser->getTag();
|
||||
|
||||
$application = Application::create([
|
||||
'name' => 'docker-image-'.new Cuid2,
|
||||
'name' => 'docker-image-'.new_public_id(),
|
||||
'repository_project_id' => 0,
|
||||
'git_repository' => 'coollabsio/coolify',
|
||||
'git_branch' => 'main',
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Livewire\Project\New;
|
||||
|
||||
use App\Models\Project;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class EmptyProject extends Component
|
||||
{
|
||||
@@ -13,7 +12,7 @@ class EmptyProject extends Component
|
||||
$project = Project::create([
|
||||
'name' => generate_random_name(),
|
||||
'team_id' => currentTeam()->id,
|
||||
'uuid' => (string) new Cuid2,
|
||||
'uuid' => new_public_id(),
|
||||
]);
|
||||
|
||||
return redirectRoute($this, 'project.show', ['project_uuid' => $project->uuid, 'environment_uuid' => $project->environments->first()->uuid]);
|
||||
|
||||
@@ -6,7 +6,6 @@ use App\Models\Application;
|
||||
use App\Models\GithubApp;
|
||||
use App\Models\Project;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class SimpleDockerfile extends Component
|
||||
{
|
||||
@@ -48,7 +47,7 @@ CMD ["nginx", "-g", "daemon off;"]
|
||||
$port = 80;
|
||||
}
|
||||
$application = Application::create([
|
||||
'name' => 'dockerfile-'.new Cuid2,
|
||||
'name' => 'dockerfile-'.new_public_id(),
|
||||
'repository_project_id' => 0,
|
||||
'git_repository' => 'coollabsio/coolify',
|
||||
'git_branch' => 'main',
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Models\ServiceApplication;
|
||||
use App\Models\ServiceDatabase;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Danger extends Component
|
||||
{
|
||||
@@ -39,7 +38,7 @@ class Danger extends Component
|
||||
public function mount()
|
||||
{
|
||||
$parameters = get_route_parameters();
|
||||
$this->modalId = new Cuid2;
|
||||
$this->modalId = new_public_id();
|
||||
$this->projectUuid = data_get($parameters, 'project_uuid');
|
||||
$this->environmentUuid = data_get($parameters, 'environment_uuid');
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ use App\Models\StandaloneDocker;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Collection;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Destination extends Component
|
||||
{
|
||||
@@ -80,7 +79,7 @@ class Destination extends Component
|
||||
|
||||
return;
|
||||
}
|
||||
$deployment_uuid = new Cuid2;
|
||||
$deployment_uuid = new_public_id();
|
||||
$server = Server::ownedByCurrentTeam()->findOrFail($server_id);
|
||||
$destination = $server->standaloneDockers->where('id', $network_id)->firstOrFail();
|
||||
$result = queue_application_deployment(
|
||||
|
||||
@@ -6,12 +6,15 @@ use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
use App\Support\ValidationPatterns;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Collection;
|
||||
use Livewire\Attributes\On;
|
||||
use Livewire\Component;
|
||||
|
||||
class ExecuteContainerCommand extends Component
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
|
||||
public $selected_container = 'default';
|
||||
|
||||
public Collection $containers;
|
||||
@@ -40,6 +43,7 @@ class ExecuteContainerCommand extends Component
|
||||
if (data_get($this->parameters, 'application_uuid')) {
|
||||
$this->type = 'application';
|
||||
$this->resource = Application::ownedByCurrentTeam()->where('uuid', $this->parameters['application_uuid'])->firstOrFail();
|
||||
$this->authorize('view', $this->resource);
|
||||
if ($this->resource->destination->server->isFunctional()) {
|
||||
$this->servers = $this->servers->push($this->resource->destination->server);
|
||||
}
|
||||
@@ -56,6 +60,7 @@ class ExecuteContainerCommand extends Component
|
||||
abort(404);
|
||||
}
|
||||
$this->resource = $resource;
|
||||
$this->authorize('view', $this->resource);
|
||||
if ($this->resource->destination->server->isFunctional()) {
|
||||
$this->servers = $this->servers->push($this->resource->destination->server);
|
||||
}
|
||||
@@ -63,6 +68,7 @@ class ExecuteContainerCommand extends Component
|
||||
} elseif (data_get($this->parameters, 'service_uuid')) {
|
||||
$this->type = 'service';
|
||||
$this->resource = Service::ownedByCurrentTeam()->where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
||||
$this->authorize('view', $this->resource);
|
||||
if ($this->resource->server->isFunctional()) {
|
||||
$this->servers = $this->servers->push($this->resource->server);
|
||||
}
|
||||
@@ -70,6 +76,7 @@ class ExecuteContainerCommand extends Component
|
||||
} elseif (data_get($this->parameters, 'server_uuid')) {
|
||||
$this->type = 'server';
|
||||
$this->resource = Server::ownedByCurrentTeam()->where('uuid', $this->parameters['server_uuid'])->firstOrFail();
|
||||
$this->authorize('view', $this->resource);
|
||||
$this->servers = $this->servers->push($this->resource);
|
||||
}
|
||||
$this->servers = $this->servers->sortByDesc(fn ($server) => $server->isTerminalEnabled());
|
||||
@@ -152,7 +159,9 @@ class ExecuteContainerCommand extends Component
|
||||
public function connectToServer()
|
||||
{
|
||||
try {
|
||||
$this->authorize('canAccessTerminal');
|
||||
$server = $this->servers->first();
|
||||
$this->authorize('view', $server);
|
||||
if ($server->isForceDisabled()) {
|
||||
throw new \RuntimeException('Server is disabled.');
|
||||
}
|
||||
@@ -181,6 +190,7 @@ class ExecuteContainerCommand extends Component
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$this->authorize('canAccessTerminal');
|
||||
// Validate container name format
|
||||
if (! ValidationPatterns::isValidContainerName($this->selected_container)) {
|
||||
throw new \InvalidArgumentException('Invalid container name format');
|
||||
@@ -198,6 +208,8 @@ class ExecuteContainerCommand extends Component
|
||||
throw new \RuntimeException('Invalid server configuration.');
|
||||
}
|
||||
|
||||
$this->authorize('view', $server);
|
||||
|
||||
if ($server->isForceDisabled()) {
|
||||
throw new \RuntimeException('Server is disabled.');
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ use App\Models\StandaloneRedis;
|
||||
use App\Models\SwarmDocker;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class ResourceOperations extends Component
|
||||
{
|
||||
@@ -66,7 +65,7 @@ class ResourceOperations extends Component
|
||||
if (! $new_destination) {
|
||||
return $this->addError('destination_id', 'Destination not found.');
|
||||
}
|
||||
$uuid = (string) new Cuid2;
|
||||
$uuid = new_public_id();
|
||||
$server = $new_destination->server;
|
||||
|
||||
if ($this->resource->getMorphClass() === Application::class) {
|
||||
@@ -89,7 +88,7 @@ class ResourceOperations extends Component
|
||||
$this->resource->getMorphClass() === StandaloneDragonfly::class ||
|
||||
$this->resource->getMorphClass() === StandaloneClickhouse::class
|
||||
) {
|
||||
$uuid = (string) new Cuid2;
|
||||
$uuid = new_public_id();
|
||||
$new_resource = $this->resource->replicate([
|
||||
'id',
|
||||
'created_at',
|
||||
@@ -180,7 +179,7 @@ class ResourceOperations extends Component
|
||||
|
||||
$scheduledBackups = $this->resource->scheduledBackups()->get();
|
||||
foreach ($scheduledBackups as $backup) {
|
||||
$uuid = (string) new Cuid2;
|
||||
$uuid = new_public_id();
|
||||
$newBackup = $backup->replicate([
|
||||
'id',
|
||||
'created_at',
|
||||
@@ -216,7 +215,7 @@ class ResourceOperations extends Component
|
||||
|
||||
return redirect()->to($route);
|
||||
} elseif ($this->resource->type() === 'service') {
|
||||
$uuid = (string) new Cuid2;
|
||||
$uuid = new_public_id();
|
||||
$new_resource = $this->resource->replicate([
|
||||
'id',
|
||||
'created_at',
|
||||
@@ -243,7 +242,7 @@ class ResourceOperations extends Component
|
||||
'created_at',
|
||||
'updated_at',
|
||||
])->fill([
|
||||
'uuid' => (string) new Cuid2,
|
||||
'uuid' => new_public_id(),
|
||||
'service_id' => $new_resource->id,
|
||||
'team_id' => currentTeam()->id,
|
||||
]);
|
||||
|
||||
@@ -5,11 +5,14 @@ namespace App\Livewire\Project\Shared;
|
||||
use App\Helpers\SshMultiplexingHelper;
|
||||
use App\Models\Server;
|
||||
use App\Support\ValidationPatterns;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Attributes\On;
|
||||
use Livewire\Component;
|
||||
|
||||
class Terminal extends Component
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
|
||||
public bool $hasShell = true;
|
||||
|
||||
public bool $isTerminalConnected = false;
|
||||
@@ -32,7 +35,11 @@ class Terminal extends Component
|
||||
#[On('send-terminal-command')]
|
||||
public function sendTerminalCommand($isContainer, $identifier, $serverUuid)
|
||||
{
|
||||
$this->authorize('canAccessTerminal');
|
||||
|
||||
$server = Server::ownedByCurrentTeam()->whereUuid($serverUuid)->firstOrFail();
|
||||
$this->authorize('view', $server);
|
||||
|
||||
if (! $server->isTerminalEnabled() || $server->isForceDisabled()) {
|
||||
abort(403, 'Terminal access is disabled on this server.');
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Models\Project;
|
||||
use App\Support\ValidationPatterns;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class Show extends Component
|
||||
{
|
||||
@@ -49,7 +48,7 @@ class Show extends Component
|
||||
$environment = Environment::create([
|
||||
'name' => $this->name,
|
||||
'project_id' => $this->project->id,
|
||||
'uuid' => (string) new Cuid2,
|
||||
'uuid' => new_public_id(),
|
||||
]);
|
||||
|
||||
return redirectRoute($this, 'project.resource.index', [
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Livewire\Security;
|
||||
|
||||
use App\Models\CloudInitScript;
|
||||
use App\Rules\ValidCloudInitYaml;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
|
||||
@@ -40,7 +41,7 @@ class CloudInitScriptForm extends Component
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|max:255',
|
||||
'script' => ['required', 'string', new \App\Rules\ValidCloudInitYaml],
|
||||
'script' => ['required', 'string', new ValidCloudInitYaml],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -68,17 +69,29 @@ class CloudInitScriptForm extends Component
|
||||
'script' => $this->script,
|
||||
]);
|
||||
|
||||
auditLog('ui.cloud_init_script.updated', [
|
||||
'team_id' => currentTeam()->id,
|
||||
'cloud_init_script_id' => $cloudInitScript->id,
|
||||
'cloud_init_script_name' => $cloudInitScript->name,
|
||||
]);
|
||||
|
||||
$message = 'Cloud-init script updated successfully.';
|
||||
} else {
|
||||
// Create new script
|
||||
$this->authorize('create', CloudInitScript::class);
|
||||
|
||||
CloudInitScript::create([
|
||||
$cloudInitScript = CloudInitScript::create([
|
||||
'team_id' => currentTeam()->id,
|
||||
'name' => $this->name,
|
||||
'script' => $this->script,
|
||||
]);
|
||||
|
||||
auditLog('ui.cloud_init_script.created', [
|
||||
'team_id' => currentTeam()->id,
|
||||
'cloud_init_script_id' => $cloudInitScript->id,
|
||||
'cloud_init_script_name' => $cloudInitScript->name,
|
||||
]);
|
||||
|
||||
$message = 'Cloud-init script created successfully.';
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,16 @@ class CloudInitScripts extends Component
|
||||
$script = CloudInitScript::ownedByCurrentTeam()->findOrFail($scriptId);
|
||||
$this->authorize('delete', $script);
|
||||
|
||||
$scriptName = $script->name;
|
||||
$script->delete();
|
||||
$this->loadScripts();
|
||||
|
||||
auditLog('ui.cloud_init_script.deleted', [
|
||||
'team_id' => currentTeam()->id,
|
||||
'cloud_init_script_id' => $scriptId,
|
||||
'cloud_init_script_name' => $scriptName,
|
||||
]);
|
||||
|
||||
$this->dispatch('success', 'Cloud-init script deleted successfully.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
||||
@@ -54,7 +54,6 @@ class CloudProviderTokenForm extends Component
|
||||
$response = Http::withHeaders([
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
])->timeout(10)->get('https://api.hetzner.cloud/v1/servers');
|
||||
ray($response);
|
||||
|
||||
return $response->successful();
|
||||
}
|
||||
@@ -85,6 +84,13 @@ class CloudProviderTokenForm extends Component
|
||||
'name' => $this->name,
|
||||
]);
|
||||
|
||||
auditLog('ui.cloud_token.created', [
|
||||
'team_id' => currentTeam()->id,
|
||||
'cloud_token_uuid' => $savedToken->uuid,
|
||||
'cloud_token_name' => $savedToken->name,
|
||||
'provider' => $savedToken->provider,
|
||||
]);
|
||||
|
||||
$this->reset(['token', 'name']);
|
||||
|
||||
// Dispatch event with token ID so parent components can react
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Livewire\Security;
|
||||
|
||||
use App\Models\CloudProviderToken;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Livewire\Component;
|
||||
|
||||
class CloudProviderTokens extends Component
|
||||
@@ -57,6 +58,14 @@ class CloudProviderTokens extends Component
|
||||
} else {
|
||||
$this->dispatch('error', 'Unknown provider.');
|
||||
}
|
||||
|
||||
auditLog('ui.cloud_token.validated', [
|
||||
'team_id' => currentTeam()->id,
|
||||
'cloud_token_uuid' => $token->uuid,
|
||||
'cloud_token_name' => $token->name,
|
||||
'provider' => $token->provider,
|
||||
'valid' => $isValid ?? false,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
@@ -65,7 +74,7 @@ class CloudProviderTokens extends Component
|
||||
private function validateHetznerToken(string $token): bool
|
||||
{
|
||||
try {
|
||||
$response = \Illuminate\Support\Facades\Http::withToken($token)
|
||||
$response = Http::withToken($token)
|
||||
->timeout(10)
|
||||
->get('https://api.hetzner.cloud/v1/servers?per_page=1');
|
||||
|
||||
@@ -78,7 +87,7 @@ class CloudProviderTokens extends Component
|
||||
private function validateDigitalOceanToken(string $token): bool
|
||||
{
|
||||
try {
|
||||
$response = \Illuminate\Support\Facades\Http::withToken($token)
|
||||
$response = Http::withToken($token)
|
||||
->timeout(10)
|
||||
->get('https://api.digitalocean.com/v2/account');
|
||||
|
||||
@@ -102,9 +111,19 @@ class CloudProviderTokens extends Component
|
||||
return;
|
||||
}
|
||||
|
||||
$tokenUuid = $token->uuid;
|
||||
$tokenName = $token->name;
|
||||
$tokenProvider = $token->provider;
|
||||
$token->delete();
|
||||
$this->loadTokens();
|
||||
|
||||
auditLog('ui.cloud_token.deleted', [
|
||||
'team_id' => currentTeam()->id,
|
||||
'cloud_token_uuid' => $tokenUuid,
|
||||
'cloud_token_name' => $tokenName,
|
||||
'provider' => $tokenProvider,
|
||||
]);
|
||||
|
||||
$this->dispatch('success', 'Cloud provider token deleted successfully.');
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Livewire\Server\CloudProviderToken;
|
||||
use App\Models\CloudProviderToken;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Livewire\Component;
|
||||
|
||||
class Show extends Component
|
||||
@@ -67,6 +68,16 @@ class Show extends Component
|
||||
|
||||
$this->server->cloudProviderToken()->associate($ownedToken);
|
||||
$this->server->save();
|
||||
|
||||
auditLog('ui.server.cloud_token_assigned', [
|
||||
'team_id' => currentTeam()->id,
|
||||
'server_uuid' => $this->server->uuid,
|
||||
'server_name' => $this->server->name,
|
||||
'cloud_token_uuid' => $ownedToken->uuid,
|
||||
'cloud_token_name' => $ownedToken->name,
|
||||
'provider' => $ownedToken->provider,
|
||||
]);
|
||||
|
||||
$this->dispatch('success', 'Hetzner token updated successfully.');
|
||||
$this->dispatch('refreshServerShow');
|
||||
} catch (\Exception $e) {
|
||||
@@ -79,7 +90,7 @@ class Show extends Component
|
||||
{
|
||||
try {
|
||||
// First, validate the token itself
|
||||
$response = \Illuminate\Support\Facades\Http::withHeaders([
|
||||
$response = Http::withHeaders([
|
||||
'Authorization' => 'Bearer '.$token->token,
|
||||
])->timeout(10)->get('https://api.hetzner.cloud/v1/servers');
|
||||
|
||||
@@ -92,7 +103,7 @@ class Show extends Component
|
||||
|
||||
// Check if this token can access the specific Hetzner server
|
||||
if ($this->server->hetzner_server_id) {
|
||||
$serverResponse = \Illuminate\Support\Facades\Http::withHeaders([
|
||||
$serverResponse = Http::withHeaders([
|
||||
'Authorization' => 'Bearer '.$token->token,
|
||||
])->timeout(10)->get("https://api.hetzner.cloud/v1/servers/{$this->server->hetzner_server_id}");
|
||||
|
||||
@@ -123,7 +134,7 @@ class Show extends Component
|
||||
return;
|
||||
}
|
||||
|
||||
$response = \Illuminate\Support\Facades\Http::withHeaders([
|
||||
$response = Http::withHeaders([
|
||||
'Authorization' => 'Bearer '.$token->token,
|
||||
])->timeout(10)->get('https://api.hetzner.cloud/v1/servers');
|
||||
|
||||
@@ -132,6 +143,16 @@ class Show extends Component
|
||||
} else {
|
||||
$this->dispatch('error', 'Hetzner token is invalid or has insufficient permissions.');
|
||||
}
|
||||
|
||||
auditLog('ui.server.cloud_token_validated', [
|
||||
'team_id' => currentTeam()->id,
|
||||
'server_uuid' => $this->server->uuid,
|
||||
'server_name' => $this->server->name,
|
||||
'cloud_token_uuid' => $token->uuid,
|
||||
'cloud_token_name' => $token->name,
|
||||
'provider' => $token->provider,
|
||||
'valid' => $response->successful(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e, $this);
|
||||
}
|
||||
|
||||
@@ -4,16 +4,21 @@ namespace App\Livewire\Storage;
|
||||
|
||||
use App\Models\S3Storage;
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Livewire\Component;
|
||||
|
||||
class Resources extends Component
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
|
||||
public S3Storage $storage;
|
||||
|
||||
public array $selectedStorages = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->authorize('view', $this->storage);
|
||||
|
||||
$backups = ScheduledDatabaseBackup::where('s3_storage_id', $this->storage->id)
|
||||
->where('save_s3', true)
|
||||
->get();
|
||||
@@ -25,6 +30,8 @@ class Resources extends Component
|
||||
|
||||
public function disableS3(int $backupId): void
|
||||
{
|
||||
$this->authorize('update', $this->storage);
|
||||
|
||||
$backup = ScheduledDatabaseBackup::where('id', $backupId)
|
||||
->where('s3_storage_id', $this->storage->id)
|
||||
->firstOrFail();
|
||||
@@ -41,6 +48,8 @@ class Resources extends Component
|
||||
|
||||
public function moveBackup(int $backupId): void
|
||||
{
|
||||
$this->authorize('update', $this->storage);
|
||||
|
||||
$backup = ScheduledDatabaseBackup::where('id', $backupId)
|
||||
->where('s3_storage_id', $this->storage->id)
|
||||
->firstOrFail();
|
||||
@@ -62,6 +71,8 @@ class Resources extends Component
|
||||
return;
|
||||
}
|
||||
|
||||
$this->authorize('update', $newStorage);
|
||||
|
||||
$backup->update(['s3_storage_id' => $newStorage->id]);
|
||||
|
||||
unset($this->selectedStorages[$backupId]);
|
||||
|
||||
@@ -10,7 +10,6 @@ use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class InviteLink extends Component
|
||||
{
|
||||
@@ -61,7 +60,7 @@ class InviteLink extends Component
|
||||
if ($member_emails->contains($this->email)) {
|
||||
return handleError(livewire: $this, customErrorMessage: "$this->email is already a member of ".currentTeam()->name.'.');
|
||||
}
|
||||
$uuid = (string) new Cuid2(32);
|
||||
$uuid = new_public_id(32);
|
||||
$link = url('/').config('constants.invitation.link.base_url').$uuid;
|
||||
$user = User::whereEmail($this->email)->first();
|
||||
|
||||
|
||||
Reference in new issue
Block a user